llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Volodymyr Turanskyy (voltur01) <details> <summary>Changes</summary> Support the --cstdlib command line option to select the corresponding C library if multiple libraries are provided by a toolchain. This patch: - Adds the logic to use the C library name set by --cstdlib to form the lib/clang-runtimes/<lib name>/ path as the sysroot. - Adds the CLANG_DEFAULT_C_STDLIB CMake option to define which C library is installed directly under lib/clang-runtimes/ to allow using --cstdlib to target this library by its name. - Reports selected library not found error if the library set by --cstdlib does not exist under lib/clang-runtimes/<lib name>/ - otherwise an error about a missing header file is usually reported that does not explain the issue. - Adds the nano variant of newlib to the list of supported C libraries. The implementation lifts computeClangRuntimesSysRoot() and dependencies to a member function to be able to get the --cstdlib provided value without passing in Args, because Args are not available in the virtual computeSysRoot() that cannot be extended with Args itself. --- Full diff: https://github.com/llvm/llvm-project/pull/185870.diff 9 Files Affected: - (modified) clang/CMakeLists.txt (+13) - (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+2) - (modified) clang/include/clang/Config/config.h.cmake (+3) - (modified) clang/include/clang/Driver/ToolChain.h (+3) - (modified) clang/include/clang/Options/Options.td (+1-1) - (modified) clang/lib/Driver/ToolChain.cpp (+18) - (modified) clang/lib/Driver/ToolChains/BareMetal.cpp (+21-8) - (modified) clang/lib/Driver/ToolChains/BareMetal.h (+8) - (added) clang/test/Driver/baremetal-cstdlib.cpp (+53) ``````````diff diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index f0d10603374b9..09f8cbbf43476 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -255,6 +255,19 @@ if (NOT(CLANG_DEFAULT_CXX_STDLIB STREQUAL "" OR "Default C++ stdlib to use (\"libstdc++\" or \"libc++\", empty for platform default" FORCE) endif() +set(CLANG_DEFAULT_C_STDLIB "" CACHE STRING + "Default C stdlib to use (\"newlib\", \"newlib-nano\", \"picolibc\", \"llvm-libc\", or \"system\", empty for platform default)") +if (NOT(CLANG_DEFAULT_C_STDLIB STREQUAL "" OR + CLANG_DEFAULT_C_STDLIB STREQUAL "newlib" OR + CLANG_DEFAULT_C_STDLIB STREQUAL "newlib-nano" OR + CLANG_DEFAULT_C_STDLIB STREQUAL "picolibc" OR + CLANG_DEFAULT_C_STDLIB STREQUAL "llvm-libc" OR + CLANG_DEFAULT_C_STDLIB STREQUAL "system")) + message(WARNING "Resetting default C stdlib to use platform default") + set(CLANG_DEFAULT_C_STDLIB "" CACHE STRING + "Default C stdlib to use (\"newlib\", \"newlib-nano\", \"picolibc\", \"llvm-libc\", or \"system\", empty for platform default)" FORCE) +endif() + set(CLANG_DEFAULT_RTLIB "" CACHE STRING "Default runtime library to use (\"libgcc\" or \"compiler-rt\", empty for platform default)") if (NOT(CLANG_DEFAULT_RTLIB STREQUAL "" OR diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 972cc87464769..b1c3f41eff17c 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -189,6 +189,8 @@ def err_drv_incompatible_options : Error< "the combination of '%0' and '%1' is incompatible">; def err_drv_invalid_cstdlib_name : Error< "invalid C library name in argument '%0'">; +def err_drv_cstdlib_not_found : Error< + "selected C library '%0' not found: '%1'">; def err_drv_invalid_stdlib_name : Error< "invalid library name in argument '%0'">; def err_drv_invalid_output_with_multiple_archs : Error< diff --git a/clang/include/clang/Config/config.h.cmake b/clang/include/clang/Config/config.h.cmake index 00c352b458c34..d965ae63b2d03 100644 --- a/clang/include/clang/Config/config.h.cmake +++ b/clang/include/clang/Config/config.h.cmake @@ -17,6 +17,9 @@ /* Default C++ stdlib to use. */ #define CLANG_DEFAULT_CXX_STDLIB "${CLANG_DEFAULT_CXX_STDLIB}" +/* Default C stdlib to use. */ +#define CLANG_DEFAULT_C_STDLIB "${CLANG_DEFAULT_C_STDLIB}" + /* Default runtime library to use. */ #define CLANG_DEFAULT_RTLIB "${CLANG_DEFAULT_RTLIB}" diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 5e111c43b717d..a0ae86e72ecb5 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -111,6 +111,7 @@ class ToolChain { enum CStdlibType { CST_Newlib, + CST_NewlibNano, CST_Picolibc, CST_LLVMLibC, CST_System, @@ -741,6 +742,8 @@ class ToolChain { // compilation arguments. Defaults to CST_System when no --cstdlib= flag // is provided. virtual CStdlibType GetCStdlibType(const llvm::opt::ArgList &Args) const; + // Return the canonical validated C standard library name. + static llvm::StringRef GetCStdlibName(CStdlibType CStdlib); // Detect the highest available version of libc++ in include path. virtual std::string detectLibcxxVersion(StringRef IncludePath) const; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 4bbdd9c8c0e58..dfc7c4fb1fc79 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -6488,7 +6488,7 @@ def stdlib_EQ : Joined<["-", "--"], "stdlib=">, def cstdlib_EQ : Joined<["--"], "cstdlib=">, Visibility<[ClangOption]>, HelpText<"C standard library to use">, - Values<"newlib,picolibc,llvm-libc,system">; + Values<"newlib,newlib-nano,picolibc,llvm-libc,system">; def stdlibxx_isystem : JoinedOrSeparate<["-"], "stdlib++-isystem">, Group<clang_i_Group>, HelpText<"Use directory as the C++ standard library include path">, diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index ac66ccbae6f39..7c5e03498e5b4 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1422,6 +1422,8 @@ ToolChain::CStdlibType ToolChain::GetCStdlibType(const ArgList &Args) const { if (LibName == "newlib") cStdlibType = ToolChain::CST_Newlib; + else if (LibName == "newlib-nano") + cStdlibType = ToolChain::CST_NewlibNano; else if (LibName == "picolibc") cStdlibType = ToolChain::CST_Picolibc; else if (LibName == "llvm-libc") @@ -1438,6 +1440,22 @@ ToolChain::CStdlibType ToolChain::GetCStdlibType(const ArgList &Args) const { return *cStdlibType; } +StringRef ToolChain::GetCStdlibName(CStdlibType CStdlib) { + switch (CStdlib) { + case ToolChain::CST_Newlib: + return "newlib"; + case ToolChain::CST_NewlibNano: + return "newlib-nano"; + case ToolChain::CST_Picolibc: + return "picolibc"; + case ToolChain::CST_LLVMLibC: + return "llvm-libc"; + case ToolChain::CST_System: + return "system"; + } + llvm_unreachable("Unknown C standard library type"); +} + /// Utility function to add a system framework directory to CC1 arguments. void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index 5e974527774eb..39192eb8ee77c 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -9,6 +9,7 @@ #include "BareMetal.h" #include "Gnu.h" +#include "clang/Config/config.h" #include "clang/Driver/CommonArgs.h" #include "clang/Driver/InputInfo.h" @@ -115,14 +116,25 @@ static bool findRISCVMultilibs(const Driver &D, return false; } -static std::string computeClangRuntimesSysRoot(const Driver &D, - bool IncludeTriple) { +std::string BareMetal::computeClangRuntimesSysRoot(bool IncludeTriple) const { + const Driver &D = getDriver(); if (!D.SysRoot.empty()) return D.SysRoot; SmallString<128> SysRootDir(D.Dir); llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes"); + StringRef CStdlibName = ToolChain::GetCStdlibName(SelectedCStdlib); + if (CStdlibName != "system" && CStdlibName != CLANG_DEFAULT_C_STDLIB) { + llvm::sys::path::append(SysRootDir, CStdlibName); + + if (!MissingCStdlibDiagEmitted && !D.getVFS().exists(SysRootDir)) { + D.Diag(diag::err_drv_cstdlib_not_found) + << CStdlibName.str() << SysRootDir.str(); + MissingCStdlibDiagEmitted = true; + } + } + if (IncludeTriple) llvm::sys::path::append(SysRootDir, D.getTargetTriple()); @@ -189,7 +201,7 @@ std::string BareMetal::computeSysRoot() const { return std::string(inferredSysRoot); // Use the clang-runtimes path. - return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true); + return computeClangRuntimesSysRoot(/*IncludeTriple*/ true); } std::string BareMetal::getCompilerRTPath() const { @@ -219,6 +231,7 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { IsGCCInstallationValid = initGCCInstallation(Triple, Args); + SelectedCStdlib = GetCStdlibType(Args); std::string ComputedSysRoot = computeSysRoot(); if (IsGCCInstallationValid) { if (!isRISCVBareMetal(Triple)) @@ -303,9 +316,9 @@ findMultilibsFromYAML(const ToolChain &TC, const Driver &D, static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml"; -static std::optional<llvm::SmallString<128>> -getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) { +std::optional<llvm::SmallString<128>> +BareMetal::getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) const { llvm::SmallString<128> MultilibPath; if (Arg *ConfigFileArg = Args.getLastArg(options::OPT_multi_lib_config)) { MultilibPath = ConfigFileArg->getValue(); @@ -314,7 +327,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple, return {}; } } else { - MultilibPath = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false); + MultilibPath = computeClangRuntimesSysRoot(/*IncludeTriple=*/false); llvm::sys::path::append(MultilibPath, MultilibFilename); } return MultilibPath; @@ -332,7 +345,7 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, if (D.getVFS().exists(*MultilibPath)) { // If multilib.yaml is found, update sysroot so it doesn't use a target // specific suffix - SysRoot = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false); + SysRoot = computeClangRuntimesSysRoot(/*IncludeTriple=*/false); SmallVector<StringRef> CustomFlagMacroDefines; findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result, CustomFlagMacroDefines); diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h index d3d415b337a0b..32a7000a5f79d 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.h +++ b/clang/lib/Driver/ToolChains/BareMetal.h @@ -12,7 +12,9 @@ #include "ToolChains/Gnu.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/SmallString.h" +#include <optional> #include <string> namespace clang { @@ -86,8 +88,14 @@ class LLVM_LIBRARY_VISIBILITY BareMetal : public Generic_ELF { using OrderedMultilibs = llvm::iterator_range<llvm::SmallVector<Multilib>::const_reverse_iterator>; OrderedMultilibs getOrderedMultilibs() const; + std::string computeClangRuntimesSysRoot(bool IncludeTriple) const; + std::optional<llvm::SmallString<128>> + getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) const; std::string SysRoot; + CStdlibType SelectedCStdlib = ToolChain::CST_System; + mutable bool MissingCStdlibDiagEmitted = false; bool IsGCCInstallationValid; diff --git a/clang/test/Driver/baremetal-cstdlib.cpp b/clang/test/Driver/baremetal-cstdlib.cpp new file mode 100644 index 0000000000000..b8451faf7e6ff --- /dev/null +++ b/clang/test/Driver/baremetal-cstdlib.cpp @@ -0,0 +1,53 @@ +// UNSUPPORTED: system-windows + +// RUN: rm -rf %t.dir/baremetal_cstdlib +// RUN: mkdir -p %t.dir/baremetal_cstdlib/bin +// RUN: mkdir -p %t.dir/baremetal_cstdlib/lib/clang-runtimes +// RUN: mkdir -p %t.dir/baremetal_cstdlib/lib/clang-runtimes/newlib +// RUN: mkdir -p %t.dir/baremetal_cstdlib/lib/clang-runtimes/newlib-nano +// RUN: mkdir -p %t.dir/baremetal_cstdlib/lib/clang-runtimes/picolibc +// RUN: mkdir -p %t.dir/baremetal_cstdlib/lib/clang-runtimes/llvm-libc +// RUN: cp %S/baremetal-multilib.yaml %t.dir/baremetal_cstdlib/lib/clang-runtimes/multilib.yaml +// RUN: cp %S/baremetal-multilib.yaml %t.dir/baremetal_cstdlib/lib/clang-runtimes/newlib/multilib.yaml +// RUN: cp %S/baremetal-multilib.yaml %t.dir/baremetal_cstdlib/lib/clang-runtimes/newlib-nano/multilib.yaml +// RUN: cp %S/baremetal-multilib.yaml %t.dir/baremetal_cstdlib/lib/clang-runtimes/picolibc/multilib.yaml +// RUN: cp %S/baremetal-multilib.yaml %t.dir/baremetal_cstdlib/lib/clang-runtimes/llvm-libc/multilib.yaml +// RUN: ln -s %clang %t.dir/baremetal_cstdlib/bin/clang + +// RUN: %t.dir/baremetal_cstdlib/bin/clang -no-canonical-prefixes %s -### -o %t.out 2>&1 \ +// RUN: -target thumbv8m.main-none-eabihf -mfpu=fpv5-d16 \ +// RUN: | FileCheck --check-prefix=CHECK-DEFAULT %s +// CHECK-DEFAULT: "-internal-isystem" "{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-DEFAULT: "-L{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}lib" + +// RUN: %t.dir/baremetal_cstdlib/bin/clang -no-canonical-prefixes %s -### -o %t.out 2>&1 \ +// RUN: -target thumbv8m.main-none-eabihf -mfpu=fpv5-d16 --cstdlib=system \ +// RUN: | FileCheck --check-prefix=CHECK-SYSTEM %s +// CHECK-SYSTEM: "-internal-isystem" "{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-SYSTEM: "-L{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}lib" + +// RUN: %t.dir/baremetal_cstdlib/bin/clang -no-canonical-prefixes %s -### -o %t.out 2>&1 \ +// RUN: -target thumbv8m.main-none-eabihf -mfpu=fpv5-d16 --cstdlib=picolibc \ +// RUN: | FileCheck --check-prefix=CHECK-PICOLIBC %s +// CHECK-PICOLIBC: "-internal-isystem" "{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}picolibc{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-PICOLIBC: "-L{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}picolibc{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}lib" + +// RUN: %t.dir/baremetal_cstdlib/bin/clang -no-canonical-prefixes %s -### -o %t.out 2>&1 \ +// RUN: -target thumbv8m.main-none-eabihf -mfpu=fpv5-d16 --cstdlib=newlib \ +// RUN: | FileCheck --check-prefix=CHECK-NEWLIB %s +// CHECK-NEWLIB: "-internal-isystem" "{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}newlib{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-NEWLIB: "-L{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}newlib{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}lib" + +// RUN: %t.dir/baremetal_cstdlib/bin/clang -no-canonical-prefixes %s -### -o %t.out 2>&1 \ +// RUN: -target thumbv8m.main-none-eabihf -mfpu=fpv5-d16 --cstdlib=newlib-nano \ +// RUN: | FileCheck --check-prefix=CHECK-NEWLIB-NANO %s +// CHECK-NEWLIB-NANO: "-internal-isystem" "{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}newlib-nano{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-NEWLIB-NANO: "-L{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}newlib-nano{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}lib" + +// RUN: %t.dir/baremetal_cstdlib/bin/clang -no-canonical-prefixes %s -### -o %t.out 2>&1 \ +// RUN: -target thumbv8m.main-none-eabihf -mfpu=fpv5-d16 --cstdlib=llvm-libc \ +// RUN: | FileCheck --check-prefix=CHECK-LLVM-LIBC %s +// CHECK-LLVM-LIBC: "-internal-isystem" "{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}llvm-libc{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-LLVM-LIBC: "-L{{.*}}baremetal_cstdlib{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}llvm-libc{{[/\\]+}}arm-none-eabi{{[/\\]+}}thumb{{[/\\]+}}v8-m.main{{[/\\]+}}fp{{[/\\]+}}lib" + +int main() { return 0; } `````````` </details> https://github.com/llvm/llvm-project/pull/185870 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
