diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -525,8 +525,11 @@ 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.h b/clang/lib/Driver/ToolChains/MinGW.h --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -60,6 +60,9 @@ 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 @@ mutable std::unique_ptr Preprocessor; mutable std::unique_ptr Compiler; void findGccLibDir(); - llvm::ErrorOr findGcc(); - llvm::ErrorOr findClangRelativeSysroot(); bool NativeLLVMSupport; }; diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -369,9 +369,9 @@ } } -llvm::ErrorOr toolchains::MinGW::findGcc() { +static llvm::ErrorOr findGcc(const llvm::Triple &T) { llvm::SmallVector, 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 @@ return make_error_code(std::errc::no_such_file_or_directory); } -llvm::ErrorOr toolchains::MinGW::findClangRelativeSysroot() { +static llvm::ErrorOr +findClangRelativeSysroot(const Driver &D, const llvm::Triple &T, + std::string &SysrootName) { llvm::SmallVector, 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 @@ 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 /../; if found, use /.. as the // base as it could still be a base for a gcc setup with libgcc. - else if (llvm::ErrorOr TargetSubdir = findClangRelativeSysroot()) + else if (llvm::ErrorOr TargetSubdir = + findClangRelativeSysroot(getDriver(), getTriple(), SysrootName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); - else if (llvm::ErrorOr GPPName = findGcc()) + else if (llvm::ErrorOr GPPName = findGcc(getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else @@ -625,3 +629,56 @@ 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 SysrootName; + if (D.SysRoot.size()) + return true; + if (llvm::ErrorOr TargetSubdir = + findClangRelativeSysroot(D, Triple, SysrootName)) + return true; + if (llvm::ErrorOr 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 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/test/Driver/mingw-sysroot.cpp b/clang/test/Driver/mingw-sysroot.cpp --- 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 different 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, this usecase is when using an unprefixed native clang +// that defaults to x86_64 mingw, but it's easier to test 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"