Author: Martin Storsjö Date: 2021-10-29T09:32:36+03:00 New Revision: d758069f5e0d483f85ed1ee2c84b3955238eedce
URL: https://github.com/llvm/llvm-project/commit/d758069f5e0d483f85ed1ee2c84b3955238eedce DIFF: https://github.com/llvm/llvm-project/commit/d758069f5e0d483f85ed1ee2c84b3955238eedce.diff LOG: [clang] [MinGW] Guess the right ix86 arch name spelling as sysroot For x86, most contempory mingw toolchains use i686 as 32 bit x86 arch target. As long as the target triple is set to the right form, this works fine, either as the compiler's default target, or via e.g. a triple prefix like i686-w64-mingw32-clang. However, if the unprefixed toolchain targets x86_64, but the user tries to switch it to target 32 bit by adding the -m32 option, the computeTargetTriple function in Clang, together with Triple::get32BitArchVariant, sets the arch to i386. This causes the right sysroot to not be found. When targeting an arch where there are potential spelling ambiguities with respect to the sysroots (i386 and arm), check if the driver can find a sysroot with the arch name - if not, try a couple other candidates. Differential Revision: https://reviews.llvm.org/D111952 Added: Modified: clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChains/MinGW.cpp clang/lib/Driver/ToolChains/MinGW.h clang/test/Driver/mingw-sysroot.cpp Removed: ################################################################################ diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 2e69e6c50f4af..cd13a6d8b8303 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -525,8 +525,11 @@ static llvm::Triple computeTargetTriple(const Driver &D, Target.setEnvironment(llvm::Triple::CODE16); } - if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) + if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) { Target.setArch(AT); + if (Target.isWindowsGNUEnvironment()) + toolchains::MinGW::fixTripleArch(D, Target, Args); + } } // Handle -miamcu flag. diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 0bdeff38f52ec..b2a5b3782957d 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -369,9 +369,9 @@ void toolchains::MinGW::findGccLibDir() { } } -llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { +static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) { llvm::SmallVector<llvm::SmallString<32>, 2> Gccs; - Gccs.emplace_back(getTriple().getArchName()); + Gccs.emplace_back(T.getArchName()); Gccs[0] += "-w64-mingw32-gcc"; Gccs.emplace_back("mingw32-gcc"); // Please do not add "gcc" here @@ -381,13 +381,14 @@ llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { return make_error_code(std::errc::no_such_file_or_directory); } -llvm::ErrorOr<std::string> toolchains::MinGW::findClangRelativeSysroot() { +static llvm::ErrorOr<std::string> +findClangRelativeSysroot(const Driver &D, const llvm::Triple &T, + std::string &SubdirName) { llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs; - Subdirs.emplace_back(getTriple().str()); - Subdirs.emplace_back(getTriple().getArchName()); + Subdirs.emplace_back(T.str()); + Subdirs.emplace_back(T.getArchName()); Subdirs[1] += "-w64-mingw32"; - StringRef ClangRoot = - llvm::sys::path::parent_path(getDriver().getInstalledDir()); + StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir()); StringRef Sep = llvm::sys::path::get_separator(); for (StringRef CandidateSubdir : Subdirs) { if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) { @@ -404,13 +405,16 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + // The sequence for detecting a sysroot here should be kept in sync with + // the testTriple function below. if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; // Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the // base as it could still be a base for a gcc setup with libgcc. - else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot()) + else if (llvm::ErrorOr<std::string> TargetSubdir = + findClangRelativeSysroot(getDriver(), getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); - else if (llvm::ErrorOr<std::string> GPPName = findGcc()) + else if (llvm::ErrorOr<std::string> GPPName = findGcc(getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else @@ -625,3 +629,55 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( break; } } + +static bool testTriple(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) { + // If an explicit sysroot is set, that will be used and we shouldn't try to + // detect anything else. + std::string SubdirName; + if (D.SysRoot.size()) + return true; + if (llvm::ErrorOr<std::string> TargetSubdir = + findClangRelativeSysroot(D, Triple, SubdirName)) + return true; + if (llvm::ErrorOr<std::string> GPPName = findGcc(Triple)) + return true; + // If we neither found a colocated sysroot or a matching gcc executable, + // conclude that we can't know if this is the correct spelling of the triple. + return false; +} + +static llvm::Triple adjustTriple(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) { + // First test if the original triple can find a sysroot with the triple + // name. + if (testTriple(D, Triple, Args)) + return Triple; + llvm::SmallVector<llvm::StringRef, 3> Archs; + // If not, test a couple other possible arch names that might be what was + // intended. + if (Triple.getArch() == llvm::Triple::x86) { + Archs.emplace_back("i386"); + Archs.emplace_back("i586"); + Archs.emplace_back("i686"); + } else if (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) { + Archs.emplace_back("armv7"); + } + for (auto A : Archs) { + llvm::Triple TestTriple(Triple); + TestTriple.setArchName(A); + if (testTriple(D, TestTriple, Args)) + return TestTriple; + } + // If none was found, just proceed with the original value. + return Triple; +} + +void toolchains::MinGW::fixTripleArch(const Driver &D, llvm::Triple &Triple, + const ArgList &Args) { + if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) + Triple = adjustTriple(D, Triple, Args); +} diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h index efc50b4f9ee29..f9659f04fbb91 100644 --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -60,6 +60,9 @@ class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { MinGW(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); + static void fixTripleArch(const Driver &D, llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + bool HasNativeLLVMSupport() const override; bool IsIntegratedAssemblerDefault() const override; @@ -103,8 +106,6 @@ class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; mutable std::unique_ptr<tools::gcc::Compiler> Compiler; void findGccLibDir(); - llvm::ErrorOr<std::string> findGcc(); - llvm::ErrorOr<std::string> findClangRelativeSysroot(); bool NativeLLVMSupport; }; diff --git a/clang/test/Driver/mingw-sysroot.cpp b/clang/test/Driver/mingw-sysroot.cpp index 8a2fb7d373a89..843bf46e66c97 100644 --- a/clang/test/Driver/mingw-sysroot.cpp +++ b/clang/test/Driver/mingw-sysroot.cpp @@ -12,6 +12,7 @@ // RUN: mkdir -p %T/testroot-clang/bin // RUN: ln -s %clang %T/testroot-clang/bin/x86_64-w64-mingw32-clang // RUN: ln -s %S/Inputs/mingw_ubuntu_posix_tree/usr/x86_64-w64-mingw32 %T/testroot-clang/x86_64-w64-mingw32 +// RUN: ln -s %S/Inputs/mingw_arch_tree/usr/i686-w64-mingw32 %T/testroot-clang/i686-w64-mingw32 // If we find a gcc in the path with the right triplet prefix, pick that as @@ -36,3 +37,14 @@ // the libgcc directory: // RUN: env "PATH=%T/testroot-gcc/bin:%PATH%" %T/testroot-gcc/bin/x86_64-w64-mingw32-clang -target x86_64-w64-mingw32 -rtlib=platform -stdlib=libstdc++ --sysroot="" -c -### %s 2>&1 | FileCheck -check-prefix=CHECK_TESTROOT_GCC %s + + +// If the user requests a diff erent arch via the -m32 option, which changes +// x86_64 into i386, check that the driver notices that it can't find a +// sysroot for i386 but there is one for i686, and uses that one. +// (In practice, the real usecase is when using an unprefixed native clang +// that defaults to x86_64 mingw, but it's easier to test this in cross setups +// with symlinks, like the other tests here.) + +// RUN: env "PATH=%T/testroot-gcc/bin:%PATH%" %T/testroot-clang/bin/x86_64-w64-mingw32-clang --target=x86_64-w64-mingw32 -m32 -rtlib=compiler-rt -stdlib=libstdc++ --sysroot="" -c -### %s 2>&1 | FileCheck -check-prefix=CHECK_TESTROOT_CLANG_I686 %s +// CHECK_TESTROOT_CLANG_I686: "{{[^"]+}}/testroot-clang{{/|\\\\}}i686-w64-mingw32{{/|\\\\}}include" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits