[clang] ab2c80b - [Driver] BareMetal ToolChain multilib layering

Michael Platings via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 13 22:47:26 PDT 2023


Author: Michael Platings
Date: 2023-06-14T06:46:41+01:00
New Revision: ab2c80bb125634816e39a1e4787a5a103cd03a74

URL: https://github.com/llvm/llvm-project/commit/ab2c80bb125634816e39a1e4787a5a103cd03a74
DIFF: https://github.com/llvm/llvm-project/commit/ab2c80bb125634816e39a1e4787a5a103cd03a74.diff

LOG: [Driver] BareMetal ToolChain multilib layering

This enables layering baremetal multilibs on top of each other.
For example a multilib containing only a no-exceptions libc++ could be
layered on top of a multilib containing C libs. This avoids the need
to duplicate the C library for every libc++ variant.

Differential Revision: https://reviews.llvm.org/D143075

Added: 
    clang/test/Driver/baremetal-multilib-layered.yaml

Modified: 
    clang/lib/Driver/ToolChains/BareMetal.cpp
    clang/lib/Driver/ToolChains/BareMetal.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index 748f24e151aa5..17fd1f88975b9 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -103,9 +103,12 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
   findMultilibs(D, Triple, Args);
   SmallString<128> SysRoot(computeSysRoot());
   if (!SysRoot.empty()) {
-    llvm::sys::path::append(SysRoot, "lib");
-    getFilePaths().push_back(std::string(SysRoot));
-    getLibraryPaths().push_back(std::string(SysRoot));
+    for (const Multilib &M : getOrderedMultilibs()) {
+      SmallString<128> Dir(SysRoot);
+      llvm::sys::path::append(Dir, M.osSuffix(), "lib");
+      getFilePaths().push_back(std::string(Dir));
+      getLibraryPaths().push_back(std::string(Dir));
+    }
   }
 }
 
@@ -222,10 +225,17 @@ Tool *BareMetal::buildLinker() const {
 }
 
 std::string BareMetal::computeSysRoot() const {
-  std::string Result = computeBaseSysRoot(getDriver(), getTriple());
+  return computeBaseSysRoot(getDriver(), getTriple());
+}
+
+BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
+  // Get multilibs in reverse order because they're ordered most-specific last.
   if (!SelectedMultilibs.empty())
-    Result += SelectedMultilibs.back().osSuffix();
-  return Result;
+    return llvm::reverse(SelectedMultilibs);
+
+  // No multilibs selected so return a single default multilib.
+  static const llvm::SmallVector<Multilib> Default = {Multilib()};
+  return llvm::reverse(Default);
 }
 
 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -240,10 +250,14 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
   }
 
   if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
-    SmallString<128> Dir(computeSysRoot());
-    if (!Dir.empty()) {
-      llvm::sys::path::append(Dir, "include");
-      addSystemInclude(DriverArgs, CC1Args, Dir.str());
+    const SmallString<128> SysRoot(computeSysRoot());
+    if (!SysRoot.empty()) {
+      for (const Multilib &M : getOrderedMultilibs()) {
+        SmallString<128> Dir(SysRoot);
+        llvm::sys::path::append(Dir, M.includeSuffix());
+        llvm::sys::path::append(Dir, "include");
+        addSystemInclude(DriverArgs, CC1Args, Dir.str());
+      }
     }
   }
 }
@@ -266,44 +280,47 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
   if (SysRoot.empty())
     return;
 
-  switch (GetCXXStdlibType(DriverArgs)) {
-  case ToolChain::CST_Libcxx: {
-    // First check sysroot/usr/include/c++/v1 if it exists.
-    SmallString<128> TargetDir(SysRoot);
-    llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
-    if (D.getVFS().exists(TargetDir)) {
-      addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
+  for (const Multilib &M : getOrderedMultilibs()) {
+    SmallString<128> Dir(SysRoot);
+    llvm::sys::path::append(Dir, M.gccSuffix());
+    switch (GetCXXStdlibType(DriverArgs)) {
+    case ToolChain::CST_Libcxx: {
+      // First check sysroot/usr/include/c++/v1 if it exists.
+      SmallString<128> TargetDir(Dir);
+      llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
+      if (D.getVFS().exists(TargetDir)) {
+        addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
+        break;
+      }
+      // Add generic path if nothing else succeeded so far.
+      llvm::sys::path::append(Dir, "include", "c++", "v1");
+      addSystemInclude(DriverArgs, CC1Args, Dir.str());
+      break;
+    }
+    case ToolChain::CST_Libstdcxx: {
+      llvm::sys::path::append(Dir, "include", "c++");
+      std::error_code EC;
+      Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
+      // Walk the subdirs, and find the one with the newest gcc version:
+      for (llvm::vfs::directory_iterator
+               LI = D.getVFS().dir_begin(Dir.str(), EC),
+               LE;
+           !EC && LI != LE; LI = LI.increment(EC)) {
+        StringRef VersionText = llvm::sys::path::filename(LI->path());
+        auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
+        if (CandidateVersion.Major == -1)
+          continue;
+        if (CandidateVersion <= Version)
+          continue;
+        Version = CandidateVersion;
+      }
+      if (Version.Major != -1) {
+        llvm::sys::path::append(Dir, Version.Text);
+        addSystemInclude(DriverArgs, CC1Args, Dir.str());
+      }
       break;
     }
-    // Add generic path if nothing else succeeded so far.
-    SmallString<128> Dir(SysRoot);
-    llvm::sys::path::append(Dir, "include", "c++", "v1");
-    addSystemInclude(DriverArgs, CC1Args, Dir.str());
-    break;
-  }
-  case ToolChain::CST_Libstdcxx: {
-    SmallString<128> Dir(SysRoot);
-    llvm::sys::path::append(Dir, "include", "c++");
-    std::error_code EC;
-    Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
-    // Walk the subdirs, and find the one with the newest gcc version:
-    for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir.str(), EC),
-                                       LE;
-         !EC && LI != LE; LI = LI.increment(EC)) {
-      StringRef VersionText = llvm::sys::path::filename(LI->path());
-      auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
-      if (CandidateVersion.Major == -1)
-        continue;
-      if (CandidateVersion <= Version)
-        continue;
-      Version = CandidateVersion;
     }
-    if (Version.Major == -1)
-      return;
-    llvm::sys::path::append(Dir, Version.Text);
-    addSystemInclude(DriverArgs, CC1Args, Dir.str());
-    break;
-  }
   }
 }
 

diff  --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h
index 54de97c734c19..e594b12a7c924 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.h
+++ b/clang/lib/Driver/ToolChains/BareMetal.h
@@ -71,6 +71,11 @@ class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain {
   void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
                          llvm::opt::ArgStringList &CmdArgs) const;
   std::string computeSysRoot() const override;
+
+private:
+  using OrderedMultilibs =
+      llvm::iterator_range<llvm::SmallVector<Multilib>::const_reverse_iterator>;
+  OrderedMultilibs getOrderedMultilibs() const;
 };
 
 } // namespace toolchains

diff  --git a/clang/test/Driver/baremetal-multilib-layered.yaml b/clang/test/Driver/baremetal-multilib-layered.yaml
new file mode 100644
index 0000000000000..2f86f8e3ea4f5
--- /dev/null
+++ b/clang/test/Driver/baremetal-multilib-layered.yaml
@@ -0,0 +1,45 @@
+# REQUIRES: shell
+# UNSUPPORTED: system-windows
+
+# This test demonstrates "layered" multilib in which more than one
+# multilib is matched.
+# For example a multilib containing only a no-exceptions libc++ could
+# be layered on top of a multilib containing C libs. This avoids the
+# need to duplicate the C library for every libc++ variant.
+# However -fno-exceptions is not yet supported for multilib selection
+# so we use a more contrived -mfloat-abi example instead.
+
+# RUN: rm -rf %T/baremetal_multilib_layered
+# RUN: mkdir -p %T/baremetal_multilib_layered/bin
+# RUN: mkdir -p %T/baremetal_multilib_layered/lib/clang-runtimes
+# RUN: ln -s %clang %T/baremetal_multilib_layered/bin/clang
+# RUN: ln -s %s %T/baremetal_multilib_layered/lib/clang-runtimes/multilib.yaml
+
+# RUN: %T/baremetal_multilib_layered/bin/clang -no-canonical-prefixes -x c++ %s -### -o %t.out 2>&1 \
+# RUN:     --target=thumbv7m-none-eabi -mfloat-abi=softfp --sysroot= \
+# RUN:   | FileCheck -DSYSROOT=%T/baremetal_multilib_layered %s
+# CHECK:      "-cc1" "-triple" "thumbv7m-none-unknown-eabi"
+# CHECK-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/softfp/include/c++/v1"
+# CHECK-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/soft/include/c++/v1"
+# CHECK-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/softfp/include"
+# CHECK-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/soft/include"
+# CHECK-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/softfp/lib"
+# CHECK-SAME: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/soft/lib"
+
+# RUN: %T/baremetal_multilib_layered/bin/clang -no-canonical-prefixes -print-multi-directory 2>&1 \
+# RUN:     --target=arm-none-eabi -mfloat-abi=softfp --sysroot= \
+# RUN:   | FileCheck --check-prefix=CHECK-PRINT-MULTI-DIRECTORY %s
+# CHECK-PRINT-MULTI-DIRECTORY:      soft
+# CHECK-PRINT-MULTI-DIRECTORY-NEXT: softfp
+
+---
+MultilibVersion: 1.0
+Variants:
+- Dir: soft
+  Flags: [-mfloat-abi=soft]
+- Dir: softfp
+  Flags: [-mfloat-abi=softfp]
+Mappings:
+- Match: -mfloat-abi=softfp
+  Flags: [-mfloat-abi=soft]
+...


        


More information about the cfe-commits mailing list