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 22 using namespace clang::driver; 23 using namespace clang::driver::toolchains; 24 using namespace clang::driver::tools; 25 using namespace clang; 26 using namespace llvm::opt; 27 28 namespace { 29 30 // TODO: Consider merging this into the AVR device table 31 // array in Targets/AVR.cpp. 32 llvm::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 39 const StringRef PossibleAVRLibcLocations[] = { 40 "/usr/avr", 41 "/usr/lib/avr", 42 }; 43 44 } // end anonymous namespace 45 46 /// AVR Toolchain 47 AVRToolChain::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 96 Tool *AVRToolChain::buildLinker() const { 97 return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); 98 } 99 100 void 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 151 llvm::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