AVR.cpp revision 360784
1//===--- AVR.cpp - AVR ToolChain Implementations ----------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "AVR.h"
10#include "CommonArgs.h"
11#include "InputInfo.h"
12#include "clang/Driver/Compilation.h"
13#include "clang/Driver/DriverDiagnostic.h"
14#include "clang/Driver/Options.h"
15#include "llvm/ADT/Optional.h"
16#include "llvm/ADT/StringSwitch.h"
17#include "llvm/MC/MCSubtargetInfo.h"
18#include "llvm/MC/SubtargetFeature.h"
19#include "llvm/Option/ArgList.h"
20#include "llvm/Support/FileSystem.h"
21
22using namespace clang::driver;
23using namespace clang::driver::toolchains;
24using namespace clang::driver::tools;
25using namespace clang;
26using namespace llvm::opt;
27
28namespace {
29
30// TODO: Consider merging this into the AVR device table
31// array in Targets/AVR.cpp.
32llvm::Optional<StringRef> GetMcuFamilyName(StringRef MCU) {
33  return llvm::StringSwitch<llvm::Optional<StringRef>>(MCU)
34      .Case("atmega328", Optional<StringRef>("avr5"))
35      .Case("atmega328p", Optional<StringRef>("avr5"))
36      .Default(Optional<StringRef>());
37}
38
39const StringRef PossibleAVRLibcLocations[] = {
40    "/usr/avr",
41    "/usr/lib/avr",
42};
43
44} // end anonymous namespace
45
46/// AVR Toolchain
47AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
48                           const ArgList &Args)
49    : Generic_ELF(D, Triple, Args), LinkStdlib(false) {
50  GCCInstallation.init(Triple, Args);
51
52  // Only add default libraries if the user hasn't explicitly opted out.
53  if (!Args.hasArg(options::OPT_nostdlib) &&
54      !Args.hasArg(options::OPT_nodefaultlibs) &&
55      !Args.hasArg(options::OPT_c /* does not apply when not linking */)) {
56    std::string CPU = getCPUName(Args, Triple);
57
58    if (CPU.empty()) {
59      // We cannot link any standard libraries without an MCU specified.
60      D.Diag(diag::warn_drv_avr_mcu_not_specified);
61    } else {
62      Optional<StringRef> FamilyName = GetMcuFamilyName(CPU);
63      Optional<std::string> AVRLibcRoot = findAVRLibcInstallation();
64
65      if (!FamilyName.hasValue()) {
66        // We do not have an entry for this CPU in the family
67        // mapping table yet.
68        D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented)
69            << CPU;
70      } else if (!GCCInstallation.isValid()) {
71        // No avr-gcc found and so no runtime linked.
72        D.Diag(diag::warn_drv_avr_gcc_not_found);
73      } else if (!AVRLibcRoot.hasValue()) {
74        // No avr-libc found and so no runtime linked.
75        D.Diag(diag::warn_drv_avr_libc_not_found);
76      } else { // We have enough information to link stdlibs
77        std::string GCCRoot = GCCInstallation.getInstallPath();
78        std::string LibcRoot = AVRLibcRoot.getValue();
79
80        getFilePaths().push_back(LibcRoot + std::string("/lib/") +
81                                 std::string(*FamilyName));
82        getFilePaths().push_back(LibcRoot + std::string("/lib/") +
83                                 std::string(*FamilyName));
84        getFilePaths().push_back(GCCRoot + std::string("/") +
85                                 std::string(*FamilyName));
86
87        LinkStdlib = true;
88      }
89    }
90
91    if (!LinkStdlib)
92      D.Diag(diag::warn_drv_avr_stdlib_not_linked);
93  }
94}
95
96Tool *AVRToolChain::buildLinker() const {
97  return new tools::AVR::Linker(getTriple(), *this, LinkStdlib);
98}
99
100void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
101                               const InputInfo &Output,
102                               const InputInfoList &Inputs,
103                               const ArgList &Args,
104                               const char *LinkingOutput) const {
105  // Compute information about the target AVR.
106  std::string CPU = getCPUName(Args, getToolChain().getTriple());
107  llvm::Optional<StringRef> FamilyName = GetMcuFamilyName(CPU);
108
109  std::string Linker = getToolChain().GetProgramPath(getShortName());
110  ArgStringList CmdArgs;
111  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
112
113  CmdArgs.push_back("-o");
114  CmdArgs.push_back(Output.getFilename());
115
116  // Enable garbage collection of unused sections.
117  CmdArgs.push_back("--gc-sections");
118
119  // Add library search paths before we specify libraries.
120  Args.AddAllArgs(CmdArgs, options::OPT_L);
121  getToolChain().AddFilePathLibArgs(Args, CmdArgs);
122
123  // If the family name is known, we can link with the device-specific libgcc.
124  // Without it, libgcc will simply not be linked. This matches avr-gcc
125  // behavior.
126  if (LinkStdlib) {
127    assert(!CPU.empty() && "CPU name must be known in order to link stdlibs");
128
129    // Add the object file for the CRT.
130    std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o");
131    CmdArgs.push_back(Args.MakeArgString(CrtFileName));
132
133    CmdArgs.push_back("-lgcc");
134    CmdArgs.push_back("-lm");
135    CmdArgs.push_back("-lc");
136
137    // Add the link library specific to the MCU.
138    CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU));
139
140    // Specify the family name as the emulation mode to use.
141    // This is almost always required because otherwise avr-ld
142    // will assume 'avr2' and warn about the program being larger
143    // than the bare minimum supports.
144    CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
145  }
146
147  C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
148                                          CmdArgs, Inputs));
149}
150
151llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
152  for (StringRef PossiblePath : PossibleAVRLibcLocations) {
153    // Return the first avr-libc installation that exists.
154    if (llvm::sys::fs::is_directory(PossiblePath))
155      return Optional<std::string>(std::string(PossiblePath));
156  }
157
158  return llvm::None;
159}
160