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; @@ -413,8 +414,8 @@ : 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. @@ -458,6 +459,41 @@ 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 compiler-rt build with 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"; + } + // Since the libgcc distributed with avr-gcc always named 'libgcc.a' even + // on windows, we should also build compiler-rt with a '.a' suffix. + 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); } @@ -499,6 +535,12 @@ 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) && @@ -514,10 +556,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; } } @@ -546,7 +591,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"); @@ -555,6 +604,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)); + } + // Add specific options for different linkers. if (Linker.find("avr-ld") != std::string::npos) { // Specify the family name as the emulation mode to use. Index: clang/test/Driver/avr-toolchain.c =================================================================== --- clang/test/Driver/avr-toolchain.c +++ clang/test/Driver/avr-toolchain.c @@ -69,3 +69,17 @@ // LLD-SAME: "--defsym=__EEPROM_REGION_LENGTH__=1024" // LLD-NOT: "avr-ld" // LLD-NOT: "-mavr5" + +// 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"