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/&lt;lib name&gt;/ 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/&lt;lib name&gt;/ - 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

Reply via email to