Index: clang/lib/Driver/ToolChains/AVR.h =================================================================== --- clang/lib/Driver/ToolChains/AVR.h +++ clang/lib/Driver/ToolChains/AVR.h @@ -34,11 +34,20 @@ llvm::Optional findAVRLibcInstallation() const; StringRef getGCCInstallPath() const { return GCCInstallPath; } + std::string buildCompilerRTBasename(const llvm::opt::ArgList &Args, + StringRef Component, FileType Type, + bool AddArch) const override; + + std::string getCompilerRTPath() const override; + + ToolChain::RuntimeLibType GetDefaultRuntimeLibType() const override; + protected: Tool *buildLinker() const override; private: StringRef GCCInstallPath; + std::string MCU; }; } // end namespace toolchains Index: clang/lib/Driver/ToolChains/AVR.cpp =================================================================== --- clang/lib/Driver/ToolChains/AVR.cpp +++ clang/lib/Driver/ToolChains/AVR.cpp @@ -19,6 +19,7 @@ #include "llvm/MC/SubtargetFeature.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" using namespace clang::driver; using namespace clang::driver::toolchains; @@ -369,14 +370,13 @@ : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); - std::string CPU = getCPUName(D, Args, Triple); - if (CPU.empty()) + MCU = getCPUName(D, Args, Triple); + if (MCU.empty()) D.Diag(diag::warn_drv_avr_mcu_not_specified); // Only add default libraries if the user hasn't explicitly opted out. if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs) && - GCCInstallation.isValid()) { + !Args.hasArg(options::OPT_nodefaultlibs) && GCCInstallation.isValid()) { GCCInstallPath = GCCInstallation.getInstallPath(); std::string GCCParentPath(GCCInstallation.getParentLibPath()); getProgramPaths().push_back(GCCParentPath + "/../bin"); @@ -415,6 +415,43 @@ CC1Args.push_back("-fno-use-cxa-atexit"); } +std::string +AVRToolChain::buildCompilerRTBasename(const llvm::opt::ArgList &Args, + StringRef Component, FileType Type, + bool AddArch) const { + const char *Prefix = "lib"; + // libgcc distributed with avr-gcc always has '.a' suffix even on windows. + const char *Suffix = ".a"; + + // Each device family has its own compiler-rt build. + std::string Arch; + if (AddArch) { + Optional FamilyName = GetMCUFamilyName(MCU); + if (FamilyName) + Arch = "-" + (*FamilyName).str(); + } + + return (Prefix + Twine("clang_rt.") + Component + Arch + Suffix).str(); +} + +std::string AVRToolChain::getCompilerRTPath() const { + // Return "$ResourceDir/lib/avr/" if exists. + SmallString<128> Path0(getDriver().ResourceDir); + llvm::sys::path::append(Path0, "lib", "avr"); + if (llvm::sys::fs::is_directory(Path0)) + return std::string(Path0.str()); + + // Fall back to "ResourceDir/lib/". + SmallString<128> Path1(getDriver().ResourceDir); + llvm::sys::path::append(Path1, "lib"); + return std::string(Path1.str()); +} + +ToolChain::RuntimeLibType AVRToolChain::GetDefaultRuntimeLibType() const { + return GCCInstallation.isValid() ? ToolChain::RLT_Libgcc + : ToolChain::RLT_CompilerRT; +} + Tool *AVRToolChain::buildLinker() const { return new tools::AVR::Linker(getTriple(), *this); } @@ -445,13 +482,19 @@ Args.AddAllArgs(CmdArgs, options::OPT_L); getToolChain().AddFilePathLibArgs(Args, CmdArgs); + // Get the runtime library, currently we only support libgcc and compiler-rt. + auto RtLib = TC.GetRuntimeLibType(Args); + assert( + (RtLib == ToolChain::RLT_Libgcc || RtLib == ToolChain::RLT_CompilerRT) && + "unknown runtime library"); + // Only add default libraries if the user hasn't explicitly opted out. bool LinkStdlib = false; if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (!CPU.empty()) { - Optional FamilyName = GetMCUFamilyName(CPU); - Optional AVRLibcRoot = TC.findAVRLibcInstallation(); + Optional FamilyName = GetMCUFamilyName(CPU); + Optional AVRLibcRoot = TC.findAVRLibcInstallation(); if (!FamilyName) { // We do not have an entry for this CPU in the family @@ -466,10 +509,13 @@ D.Diag(diag::warn_drv_avr_libc_not_found); } else { std::string SubPath = GetMCUSubPath(CPU); + // Add avr-libc path. CmdArgs.push_back( Args.MakeArgString(Twine("-L") + *AVRLibcRoot + "/lib/" + SubPath)); - CmdArgs.push_back( - Args.MakeArgString("-L" + TC.getGCCInstallPath() + "/" + SubPath)); + // Add path of libgcc. + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back(Args.MakeArgString("-L" + TC.getGCCInstallPath() + + "/" + SubPath)); LinkStdlib = true; } } @@ -493,13 +539,25 @@ if (LinkStdlib) { assert(!CPU.empty() && "CPU name must be known in order to link stdlibs"); + // Link to compiler-rt. + if (RtLib == ToolChain::RLT_CompilerRT) { + std::string RtLib = + getToolChain().getCompilerRT(Args, "builtins", ToolChain::FT_Static); + if (llvm::sys::fs::exists(RtLib)) + CmdArgs.push_back(Args.MakeArgString(RtLib)); + } + CmdArgs.push_back("--start-group"); // Add the object file for the CRT. std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); CmdArgs.push_back(Args.MakeArgString(CrtFileName)); - CmdArgs.push_back("-lgcc"); + // Link to libgcc. + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back("-lgcc"); + + // Link to generic libraries of avr-libc. CmdArgs.push_back("-lm"); CmdArgs.push_back("-lc"); @@ -530,8 +588,8 @@ if (llvm::sys::fs::is_directory(Path)) return Path; - // Search avr-libc installation from possible locations, and return the first - // one that exists, if there is no avr-gcc installed. + // Search avr-libc installation from possible locations, and return the + // first one that exists, if there is no avr-gcc installed. for (StringRef PossiblePath : PossibleAVRLibcLocations) { std::string Path = getDriver().SysRoot + PossiblePath.str(); if (llvm::sys::fs::is_directory(Path)) Index: clang/test/Driver/avr-toolchain.c =================================================================== --- clang/test/Driver/avr-toolchain.c +++ clang/test/Driver/avr-toolchain.c @@ -58,3 +58,12 @@ // NOGCC-NOT: warning: {{.*}} microcontroller // NOGCC-NOT: warning: {{.*}} avr-libc // NOGCC-NOT: warning: {{.*}} data section address + +// RUN: %clang %s -### --target=avr -mmcu=atmega328 --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir 2>&1 | FileCheck --check-prefix=LIBGCC %s +// RUN: %clang %s -### --target=avr -mmcu=atmega328 --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=libgcc 2>&1 | FileCheck --check-prefix=LIBGCC %s +// LIBGCC: "-lgcc" +// LIBGCC-NOT: libclang_rt + +// RUN: %clang %s -### --target=avr -mmcu=atmega328 --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=compiler-rt 2>&1 | FileCheck --check-prefix=COMRT %s +// COMRT: libclang_rt.builtins-avr5.a +// COMRT-NOT: "-lgcc"