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 = std::string(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(GCCRoot + std::string("/") + 83 std::string(*FamilyName)); 84 85 LinkStdlib = true; 86 } 87 } 88 89 if (!LinkStdlib) 90 D.Diag(diag::warn_drv_avr_stdlib_not_linked); 91 } 92 } 93 94 Tool *AVRToolChain::buildLinker() const { 95 return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); 96 } 97 98 void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, 99 const InputInfo &Output, 100 const InputInfoList &Inputs, 101 const ArgList &Args, 102 const char *LinkingOutput) const { 103 // Compute information about the target AVR. 104 std::string CPU = getCPUName(Args, getToolChain().getTriple()); 105 llvm::Optional<StringRef> FamilyName = GetMcuFamilyName(CPU); 106 107 std::string Linker = getToolChain().GetProgramPath(getShortName()); 108 ArgStringList CmdArgs; 109 AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); 110 111 CmdArgs.push_back("-o"); 112 CmdArgs.push_back(Output.getFilename()); 113 114 // Enable garbage collection of unused sections. 115 CmdArgs.push_back("--gc-sections"); 116 117 // Add library search paths before we specify libraries. 118 Args.AddAllArgs(CmdArgs, options::OPT_L); 119 getToolChain().AddFilePathLibArgs(Args, CmdArgs); 120 121 // If the family name is known, we can link with the device-specific libgcc. 122 // Without it, libgcc will simply not be linked. This matches avr-gcc 123 // behavior. 124 if (LinkStdlib) { 125 assert(!CPU.empty() && "CPU name must be known in order to link stdlibs"); 126 127 // Add the object file for the CRT. 128 std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); 129 CmdArgs.push_back(Args.MakeArgString(CrtFileName)); 130 131 CmdArgs.push_back("-lgcc"); 132 CmdArgs.push_back("-lm"); 133 CmdArgs.push_back("-lc"); 134 135 // Add the link library specific to the MCU. 136 CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU)); 137 138 // Specify the family name as the emulation mode to use. 139 // This is almost always required because otherwise avr-ld 140 // will assume 'avr2' and warn about the program being larger 141 // than the bare minimum supports. 142 CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); 143 } 144 145 C.addCommand( 146 std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), 147 Args.MakeArgString(Linker), CmdArgs, Inputs)); 148 } 149 150 llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const { 151 for (StringRef PossiblePath : PossibleAVRLibcLocations) { 152 // Return the first avr-libc installation that exists. 153 if (llvm::sys::fs::is_directory(PossiblePath)) 154 return Optional<std::string>(std::string(PossiblePath)); 155 } 156 157 return llvm::None; 158 } 159