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 @@ -71,6 +71,11 @@ void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; std::string computeSysRoot() const override; + +private: + using OrderedMultilibs = + llvm::iterator_range::const_reverse_iterator>; + OrderedMultilibs getOrderedMultilibs() const; }; } // namespace toolchains 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 @@ -103,9 +103,12 @@ 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 @@ } 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 Default = {Multilib()}; + return llvm::reverse(Default); } void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -240,10 +250,14 @@ } 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 @@ 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/test/Driver/baremetal-multilib-layered.yaml b/clang/test/Driver/baremetal-multilib-layered.yaml new file mode 100644 --- /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] +...