diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -6165,7 +6165,7 @@ if (Target.getVendor() == llvm::Triple::Myriad) TC = std::make_unique(*this, Target, Args); - else if (toolchains::BareMetal::handlesTarget(Target)) + else if (Target.isBareMetal()) TC = std::make_unique(*this, Target, Args); else if (Target.isOSBinFormatELF()) TC = std::make_unique(*this, Target, Args); diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -422,6 +422,9 @@ const llvm::Triple &Triple = TC.getTriple(); bool IsWindows = Triple.isOSWindows(); + if (Triple.isBareMetal()) + return Triple.getArchName(); + if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows) ? "armhf" @@ -459,7 +462,10 @@ std::string ToolChain::getCompilerRTPath() const { SmallString<128> Path(getDriver().ResourceDir); - if (Triple.isOSUnknown()) { + if (Triple.isBareMetal()) { + llvm::sys::path::append(Path, "lib", getOSLibName()); + Path += SelectedMultilib.gccSuffix(); + } else if (Triple.isOSUnknown()) { llvm::sys::path::append(Path, "lib"); } else { llvm::sys::path::append(Path, "lib", getOSLibName()); diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h --- a/clang/lib/Driver/ToolChains/BareMetal.h +++ b/clang/lib/Driver/ToolChains/BareMetal.h @@ -25,19 +25,11 @@ const llvm::opt::ArgList &Args); ~BareMetal() override = default; - static bool handlesTarget(const llvm::Triple &Triple); - void findMultilibs(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); protected: Tool *buildLinker() const override; - - std::string buildCompilerRTBasename(const llvm::opt::ArgList &Args, - StringRef Component, - FileType Type = ToolChain::FT_Static, - bool AddArch = true) const override; - public: bool useIntegratedAs() const override { return true; } bool isCrossCompiling() const override { return true; } @@ -50,8 +42,6 @@ StringRef getOSLibName() const override { return "baremetal"; } - std::string getCompilerRTPath() const override; - RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } @@ -61,7 +51,6 @@ const char *getDefaultLinker() const override { return "ld.lld"; } - std::string getRuntimesDir() const; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -92,7 +92,7 @@ } BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) + const ArgList &Args) : ToolChain(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) @@ -106,57 +106,10 @@ } } -/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? -static bool isARMBareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::arm && - Triple.getArch() != llvm::Triple::thumb) - return false; - - if (Triple.getVendor() != llvm::Triple::UnknownVendor) - return false; - - if (Triple.getOS() != llvm::Triple::UnknownOS) - return false; - - if (Triple.getEnvironment() != llvm::Triple::EABI && - Triple.getEnvironment() != llvm::Triple::EABIHF) - return false; - - return true; -} - -/// Is the triple aarch64-none-elf? -static bool isAArch64BareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::aarch64) - return false; - - if (Triple.getVendor() != llvm::Triple::UnknownVendor) - return false; - - if (Triple.getOS() != llvm::Triple::UnknownOS) - return false; - - return Triple.getEnvironmentName() == "elf"; -} - -static bool isRISCVBareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::riscv32 && - Triple.getArch() != llvm::Triple::riscv64) - return false; - - if (Triple.getVendor() != llvm::Triple::UnknownVendor) - return false; - - if (Triple.getOS() != llvm::Triple::UnknownOS) - return false; - - return Triple.getEnvironmentName() == "elf"; -} - void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) { DetectedMultilibs Result; - if (isRISCVBareMetal(Triple)) { + if (Triple.isRISCVBareMetal()) { if (findRISCVMultilibs(D, Triple, Args, Result)) { SelectedMultilib = Result.SelectedMultilib; Multilibs = Result.Multilibs; @@ -164,30 +117,10 @@ } } -bool BareMetal::handlesTarget(const llvm::Triple &Triple) { - return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || - isRISCVBareMetal(Triple); -} - Tool *BareMetal::buildLinker() const { return new tools::baremetal::Linker(*this); } -std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); } - -std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &, - StringRef, FileType, - bool) const { - return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str(); -} - -std::string BareMetal::getRuntimesDir() const { - SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append(Dir, "lib", "baremetal"); - Dir += SelectedMultilib.gccSuffix(); - return std::string(Dir.str()); -} - std::string BareMetal::computeSysRoot() const { if (!getDriver().SysRoot.empty()) return getDriver().SysRoot + SelectedMultilib.osSuffix(); @@ -226,8 +159,8 @@ CC1Args.push_back("-nostdsysteminc"); } -void BareMetal::AddClangCXXStdlibIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { +void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) @@ -292,9 +225,15 @@ ArgStringList &CmdArgs) const { ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); switch (RLT) { - case ToolChain::RLT_CompilerRT: + case ToolChain::RLT_CompilerRT: { + const std::string fileName = getCompilerRT(Args, "builtins"); + std::string baseName = llvm::sys::path::filename(fileName).str(); + llvm::StringRef baseNameRef(baseName); + baseNameRef.consume_front("lib"); + baseNameRef.consume_back(".a"); CmdArgs.push_back( - Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName())); + Args.MakeArgString(std::string("-l") + baseNameRef.str())); + } return; case ToolChain::RLT_Libgcc: CmdArgs.push_back("-lgcc"); @@ -310,7 +249,7 @@ const char *LinkingOutput) const { ArgStringList CmdArgs; - auto &TC = static_cast(getToolChain()); + auto &TC = static_cast(getToolChain()); AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); @@ -322,11 +261,18 @@ TC.AddFilePathLibArgs(Args, CmdArgs); - CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); + for (const auto &LibPath : TC.getLibraryPaths()) { + CmdArgs.push_back(Args.MakeArgString("-L" + LibPath)); + } + const std::string fileName = TC.getCompilerRT(Args, "builtins"); + llvm::SmallString<128> pathBuf{fileName}; + llvm::sys::path::remove_filename(pathBuf); + CmdArgs.push_back(Args.MakeArgString(std::string("-L") + pathBuf.str())); if (TC.ShouldLinkCXXStdlib(Args)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + CmdArgs.push_back("-lc"); CmdArgs.push_back("-lm"); diff --git a/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/armv7m-vendor-none-eabi/libclang_rt.builtins.a b/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/armv7m-vendor-none-eabi/libclang_rt.builtins.a new file mode 100644 diff --git a/clang/test/Driver/baremetal.cpp b/clang/test/Driver/baremetal.cpp --- a/clang/test/Driver/baremetal.cpp +++ b/clang/test/Driver/baremetal.cpp @@ -31,6 +31,20 @@ // RUN: | FileCheck --check-prefix=CHECK-V6M-LIBINC %s // CHECK-V6M-LIBINC-NOT: "-internal-isystem" +// RUN: %clang -no-canonical-prefixes -rtlib=compiler-rt %s -### -o %t.o 2>&1 \ +// RUN: -target armv7m-vendor-none-eabi \ +// RUN: --sysroot=%S/Inputs/baremetal_arm \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \ +// RUN: | FileCheck --check-prefix=CHECK-ARMV7M-PER-TARGET %s +// CHECK-ARMV7M-PER-TARGET: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" +// CHECK-ARMV7M-PER-TARGET: "-isysroot" "[[SYSROOT:[^"]*]]" +// CHECK-ARMV7M-PER-TARGET: "-x" "c++" "{{.*}}baremetal.cpp" +// CHECK-ARMV7M-PER-TARGET: "{{[^"]*}}ld{{(\.(lld|bfd|gold))?}}{{(\.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-ARMV7M-PER-TARGET: "-L[[SYSROOT:[^"]+]]{{[/\\]+}}lib" +// CHECK-ARMV7M-PER-TARGET: "-L[[RESOURCE_DIR:[^"]+]]{{[/\\]+}}lib{{[/\\]+}}armv7m-vendor-none-eabi +// CHECK-ARMV7M-PER-TARGET: "-lc" "-lm" "-lclang_rt.builtins" +// CHECK-ARMV7M-PER-TARGET: "-o" "{{.*}}.o" + // RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: -target armv6m-none-eabi \ // RUN: --sysroot=%S/Inputs/baremetal_arm \ diff --git a/clang/test/Driver/print-libgcc-file-name-clangrt.c b/clang/test/Driver/print-libgcc-file-name-clangrt.c --- a/clang/test/Driver/print-libgcc-file-name-clangrt.c +++ b/clang/test/Driver/print-libgcc-file-name-clangrt.c @@ -48,3 +48,9 @@ // RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM-BAREMETAL %s // CHECK-CLANGRT-ARM-BAREMETAL: libclang_rt.builtins-armv7m.a + +// RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ +// RUN: --target=armv7m-vendor-none-eabi \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \ +// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM-BAREMETAL-PER-TARGET %s +// CHECK-CLANGRT-ARM-BAREMETAL-PER-TARGET: libclang_rt.builtins.a diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -912,6 +912,57 @@ return Env == Triple::GNUX32 || Env == Triple::MuslX32; } + /// Tests if the target is {arm,thumb}-none-none-{eabi,eabihf}. + bool isARMBareMetal() const { + if (getArch() != Triple::arm && getArch() != Triple::thumb) + return false; + + if (getVendor() != Triple::UnknownVendor) + return false; + + if (getOS() != Triple::UnknownOS) + return false; + + if (getEnvironment() != Triple::EABI && + getEnvironment() != Triple::EABIHF) + return false; + + return true; + } + + /// Tests if the target is aarch64-none-elf. + bool isAArch64BareMetal() const { + if (getArch() != Triple::aarch64) + return false; + + if (getVendor() != Triple::UnknownVendor) + return false; + + if (getOS() != Triple::UnknownOS) + return false; + + return getEnvironmentName() == "elf"; + } + + /// Tests if the target is riscv-none-none-elf. + bool isRISCVBareMetal() const { + if (getArch() != Triple::riscv32 && getArch() != llvm::Triple::riscv64) + return false; + + if (getVendor() != Triple::UnknownVendor) + return false; + + if (getOS() != Triple::UnknownOS) + return false; + + return getEnvironmentName() == "elf"; + } + + /// Tests if this is a bare metal target. + bool isBareMetal() const { + return isARMBareMetal() || isAArch64BareMetal() || isRISCVBareMetal(); + } + /// Tests whether the target supports comdat bool supportsCOMDAT() const { return !(isOSBinFormatMachO() || isOSBinFormatXCOFF());