Index: cmake/caches/BaremetalARM.cmake =================================================================== --- /dev/null +++ cmake/caches/BaremetalARM.cmake @@ -0,0 +1,43 @@ +set(LLVM_TARGETS_TO_BUILD ARM;X86 CACHE STRING "") + +# Builtins +set(LLVM_BUILTIN_TARGETS "armv6m-none-eabi;armv7m-none-eabi;armv7em-none-eabi" CACHE STRING "Builtin Targets") + +set(BUILTINS_armv6m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV6M_SYSROOT} CACHE STRING "armv6m-none-eabi Sysroot") +set(BUILTINS_armv6m-none-eabi_CMAKE_SYSTEM_NAME BareMetal CACHE STRING "armv6m-none-eabi System Name") +set(BUILTINS_armv6m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "Baremetal build") + +set(BUILTINS_armv7m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7M_SYSROOT} CACHE STRING "armv7m-none-eabi Sysroot") +set(BUILTINS_armv7m-none-eabi_CMAKE_SYSTEM_NAME BareMetal CACHE STRING "armv7m-none-eabi System Name") +set(BUILTINS_armv7m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "Baremetal build") + +set(BUILTINS_armv7em-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7EM_SYSROOT} CACHE STRING "armv7em-none-eabi Sysroot") +set(BUILTINS_armv7em-none-eabi_CMAKE_SYSTEM_NAME BareMetal CACHE STRING "armv7em-none-eabi System Name") +set(BUILTINS_armv7em-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "Baremetal build") + +set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "") +set(LLVM_TOOLCHAIN_TOOLS + llc + llvm-ar + llvm-cxxfilt + llvm-dwarfdump + llvm-dsymutil + llvm-nm + llvm-objdump + llvm-ranlib + llvm-readobj + llvm-size + llvm-symbolizer + opt + CACHE STRING "") + +set(LLVM_DISTRIBUTION_COMPONENTS + clang + lld + clang-headers + builtins-armv6m-none-eabi + builtins-armv7m-none-eabi + builtins-armv7em-none-eabi + runtimes + ${LLVM_TOOLCHAIN_TOOLS} + CACHE STRING "") Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -30,6 +30,7 @@ ToolChains/AMDGPU.cpp ToolChains/AVR.cpp ToolChains/Bitrig.cpp + ToolChains/BareMetal.cpp ToolChains/Clang.cpp ToolChains/CloudABI.cpp ToolChains/CommonArgs.cpp Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -22,6 +22,7 @@ #include "ToolChains/FreeBSD.h" #include "ToolChains/Fuchsia.h" #include "ToolChains/Gnu.h" +#include "ToolChains/BareMetal.h" #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" #include "ToolChains/Lanai.h" @@ -3819,6 +3820,8 @@ if (Target.getVendor() == llvm::Triple::Myriad) TC = llvm::make_unique(*this, Target, Args); + else if (toolchains::BareMetal::handlesTarget(Target)) + TC = llvm::make_unique(*this, Target, Args); else if (Target.isOSBinFormatELF()) TC = llvm::make_unique(*this, Target, Args); else if (Target.isOSBinFormatMachO()) Index: lib/Driver/ToolChains/BareMetal.h =================================================================== --- /dev/null +++ lib/Driver/ToolChains/BareMetal.h @@ -0,0 +1,93 @@ +//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +#include + +namespace clang { +namespace driver { + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { +public: + BareMetal(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~BareMetal() override; + + static bool handlesTarget(const llvm::Triple &Triple); +protected: + Tool *buildLinker() const override; + +public: + bool useIntegratedAs() const override { return true; } + bool isCrossCompiling() const override { return true; } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return true; } + bool SupportsObjCGC() const override { return false; } + std::string getThreadModel() const override; + bool isThreadModelSupported(const StringRef Model) const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + + 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, + llvm::opt::ArgStringList &CC1Args) const override; + + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + std::string findLibCxxIncludePath() const; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; +}; + +} // namespace toolchains + +namespace tools { +namespace baremetal { + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {} + bool isLinkJob() const override { return true; } + bool hasIntegratedCPP() const override { return false; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // namespace baremetal +} // namespace tools + +} // namespace driver +} // namespace clang + +#endif Index: lib/Driver/ToolChains/BareMetal.cpp =================================================================== --- /dev/null +++ lib/Driver/ToolChains/BareMetal.cpp @@ -0,0 +1,197 @@ +//===--- BaremMetal.cpp - Bare Metal ToolChain ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BareMetal.h" + +#include "CommonArgs.h" +#include "InputInfo.h" + +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::opt; +using namespace clang; +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; + +BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); +} + +BareMetal::~BareMetal() {} + +/// 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; +} + +bool BareMetal::handlesTarget(const llvm::Triple &Triple) { + return isARMBareMetal(Triple); +} + +Tool *BareMetal::buildLinker() const { + return new tools::baremetal::Linker(*this); +} + +std::string BareMetal::getThreadModel() const { + return "single"; +} + +bool BareMetal::isThreadModelSupported(const StringRef Model) const { + return Model == "single"; +} + +std::string BareMetal::getRuntimesDir() const { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "lib", "baremetal"); + return Dir.str(); +} + +void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { + SmallString<128> Dir(getDriver().SysRoot); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } +} + +void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CC1Args.push_back("-nostdsysteminc"); +} + +std::string BareMetal::findLibCxxIncludePath() const { + StringRef SysRoot = getDriver().SysRoot; + if (SysRoot.empty()) + return ""; + + SmallString<128> Dir(SysRoot); + llvm::sys::path::append(Dir, "include", "c++", "v1"); + return Dir.str(); +} + +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)) + return; + + std::string Path = findLibCxxIncludePath(); + if (!Path.empty()) + addSystemInclude(DriverArgs, CC1Args, Path); +} + +ToolChain::CXXStdlibType +BareMetal::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value == "libc++") + return ToolChain::CST_Libcxx; + else if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + break; + case ToolChain::CST_Libstdcxx: + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("-lsupc++"); + break; + } + CmdArgs.push_back("-lunwind"); +} + +void BareMetal::AddLinkRuntimeLib(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" + + getTriple().getArchName() + ".a")); +} + +void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + auto &TC = static_cast(getToolChain()); + + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + + CmdArgs.push_back("-Bstatic"); + + CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); + + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_r}); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (C.getDriver().CCCIsCXX()) + TC.AddCXXStdlibLibArgs(Args, CmdArgs); + + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lm"); + + TC.AddLinkRuntimeLib(Args, CmdArgs); + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + C.addCommand(llvm::make_unique(JA, *this, + Args.MakeArgString(TC.GetLinkerPath()), + CmdArgs, Inputs)); +} Index: test/Driver/baremetal.cpp =================================================================== --- /dev/null +++ test/Driver/baremetal.cpp @@ -0,0 +1,69 @@ +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target armv6m-none-eabi \ +// RUN: -T semihosted.lds \ +// RUN: -L some/directory/user/asked/for \ +// RUN: --sysroot=%S/Inputs/baremetal_arm \ +// RUN: | FileCheck --check-prefix=CHECK-V6M-C %s +// CHECK-V6M-C: "[[PREFIX_DIR:.*]]/bin/clang" "-cc1" "-triple" "thumbv6m-none--eabi" +// CHECK-V6M-C-SAME: "-resource-dir" "[[PREFIX_DIR]]/lib/clang/[[VERSION:[^"]*]]" +// CHECK-V6M-C-SAME: "-isysroot" "[[SYSROOT:[^"]*]]" +// CHECK-V6M-C-SAME: "-internal-isystem" "[[SYSROOT]]/include/c++/v1" +// CHECk-V6M-C-SAME: "-internal-isystem" "[[SYSROOT]]/include" +// CHECK-V6M-C-SAME: "-x" "c++" "{{.*}}baremetal.cpp" +// CHECK-V6M-C-NEXT: "[[PREFIX_DIR:.*]]/bin/ld.lld" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-C-SAME: "-L[[PREFIX_DIR]]/lib/clang/[[VERSION]]/lib/baremetal" +// CHECK-V6M-C-SAME: "-T" "semihosted.lds" "-Lsome/directory/user/asked/for" +// CHECK-V6M-C-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a" +// CHECK-V6M-C-SAME: "-o" "{{.*}}.o" + +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target armv6m-none-eabi \ +// RUN: -nostdlibinc -nobuiltininc \ +// RUN: --sysroot=%S/Inputs/baremetal_arm \ +// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBINC %s +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target armv6m-none-eabi \ +// RUN: -nostdinc \ +// RUN: --sysroot=%S/Inputs/baremetal_arm \ +// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBINC %s +// CHECK-V6M-LIBINC-NOT: "-internal-isystem" + +// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target armv6m-none-eabi \ +// RUN: | FileCheck --check-prefix=CHECK-V6M-DEFAULTCXX %s +// CHECK-V6M-DEFAULTCXX: "[[PREFIX_DIR:.*]]/bin/ld.lld" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-DEFAULTCXX-SAME: "-L[[PREFIX_DIR]]/lib/clang/{{.*}}/lib/baremetal" +// CHECK-V6M-DEFAULTCXX-SAME: "-lc++" "-lc++abi" "-lunwind" +// CHECK-V6M-DEFAULTCXX-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a" +// CHECK-V6M-DEFAULTCXX-SAME: "-o" "{{.*}}.o" + +// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target armv6m-none-eabi \ +// RUN: -stdlib=libc++ \ +// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBCXX %s +// CHECK-V6M-LIBCXX: "[[PREFIX_DIR:.*]]/bin/ld.lld" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-LIBCXX-SAME: "-L[[PREFIX_DIR]]/lib/clang/{{.*}}/lib/baremetal" +// CHECK-V6M-LIBCXX-SAME: "-lc++" "-lc++abi" "-lunwind" +// CHECK-V6M-LIBCXX-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a" +// CHECK-V6M-LIBCXX-SAME: "-o" "{{.*}}.o" + +// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target armv6m-none-eabi \ +// RUN: -stdlib=libstdc++ \ +// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBSTDCXX %s +// CHECK-V6M-LIBSTDCXX: "[[PREFIX_DIR:.*]]/bin/ld.lld" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-LIBSTDCXX-SAME: "-L[[PREFIX_DIR]]/lib/clang/{{.*}}/lib/baremetal" +// CHECK-V6M-LIBSTDCXX-SAME: "-lstdc++" "-lsupc++" "-lunwind" +// CHECK-V6M-LIBSTDCXX-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a" +// CHECK-V6M-LIBSTDCXX-SAME: "-o" "{{.*}}.o" + +// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: -target armv6m-none-eabi \ +// RUN: -nodefaultlibs \ +// RUN: | FileCheck --check-prefix=CHECK-V6M-NDL %s +// CHECK-V6M-NDL: "[[PREFIX_DIR:.*]]/bin/ld.lld" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-NDL-SAME: "-L[[PREFIX_DIR]]/lib/clang/{{.*}}/lib/baremetal" "-o" "{{.*}}.o" + +// RUN: %clangxx -target arm-none-eabi -v 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-THREAD-MODEL +// CHECK-THREAD-MODEL: Thread model: single