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,40 @@ CC1Args.push_back("-fno-use-cxa-atexit"); } +std::string +AVRToolChain::buildCompilerRTBasename(const llvm::opt::ArgList &Args, + StringRef Component, FileType Type, + bool AddArch) const { + std::string Arch; + // Each device family should has its own build with specific optimization. + if (AddArch) { + Optional FamilyName = GetMCUFamilyName(MCU); + if (FamilyName) + Arch = "-" + (*FamilyName).str(); + // Neither libgcc nor compiler-rt will be linked if no '-mmcu' specified. + // However we still append a default "-avr" for future changes. + else + Arch = "-avr"; + } + // libgcc distributed with avr-gcc always named 'libgcc.a' even on windows. + return (Twine("libclang_rt.") + Component + Arch + ".a").str(); +} + +std::string AVRToolChain::getCompilerRTPath() const { + // Return default path appended with "/avr", if it exists. + SmallString<128> Path(ToolChain::getCompilerRTPath()); + llvm::sys::path::append(Path, "avr"); + if (llvm::sys::fs::is_directory(Path)) + return std::string(Path.str()); + // Fall back to default. + return ToolChain::getCompilerRTPath(); +} + +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 +479,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 +506,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; } } @@ -499,7 +542,11 @@ 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"); @@ -508,6 +555,14 @@ CmdArgs.push_back("--end-group"); + // 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)); + } + // Specify the family name as the emulation mode to use. // This is almost always required because otherwise avr-ld // will assume 'avr2' and warn about the program being larger @@ -530,8 +585,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,17 @@ // 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" + +// RUN: %clang %s -### --target=avr --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=compiler-rt 2>&1 | FileCheck --check-prefix=NOMCU %s +// RUN: %clang %s -### --target=avr --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=libgcc 2>&1 | FileCheck --check-prefix=NOMCU %s +// NOMCU-NOT: libclang_rt +// NOMCU-NOT: "-lgcc"