diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -219,8 +219,8 @@ CC1ToolFunc CC1Main = nullptr; private: - /// Raw target triple. - std::string TargetTriple; + /// Raw target triple (not normalized, since it is used as a prefix). + llvm::Triple RawTargetTriple; /// Name to use when invoking gcc/g++. std::string CCCGenericGCCName; @@ -334,7 +334,7 @@ const std::string &getTitle() { return DriverTitle; } void setTitle(std::string Value) { DriverTitle = std::move(Value); } - std::string getTargetTriple() const { return TargetTriple; } + std::string getRawTargetTriple() const { return RawTargetTriple.str(); } /// Get the path to the main clang executable. const char *getClangProgramPath() const { 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 @@ -139,7 +139,7 @@ CCPrintHeadersFilename(), CCLogDiagnosticsFilename(), CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), - CCPrintProcessStats(false), TargetTriple(TargetTriple), + CCPrintProcessStats(false), RawTargetTriple(TargetTriple), CCCGenericGCCName(""), Saver(Alloc), CheckInputsExist(true), GenReproducer(false), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. @@ -437,15 +437,16 @@ /// /// This routine provides the logic to compute a target triple from various /// args passed to the driver and the default triple string. -static llvm::Triple computeTargetTriple(const Driver &D, - StringRef TargetTriple, +static llvm::Triple computeTargetTriple(const Driver &D, StringRef TargetTriple, const ArgList &Args, - StringRef DarwinArchName = "") { + StringRef DarwinArchName = "", + bool Normalize = true) { // FIXME: Already done in Compilation *Driver::BuildCompilation if (const Arg *A = Args.getLastArg(options::OPT_target)) TargetTriple = A->getValue(); - llvm::Triple Target(llvm::Triple::normalize(TargetTriple)); + llvm::Triple Target(Normalize ? llvm::Triple::normalize(TargetTriple) + : TargetTriple); // GNU/Hurd's triples should have been -hurd-gnu*, but were historically made // -gnu* only, and we can not change this, so we have to detect that case as @@ -1109,15 +1110,13 @@ // and getToolChain is const. if (IsCLMode()) { // clang-cl targets MSVC-style Win32. - llvm::Triple T(TargetTriple); + llvm::Triple T(RawTargetTriple); T.setOS(llvm::Triple::Win32); T.setVendor(llvm::Triple::PC); T.setEnvironment(llvm::Triple::MSVC); T.setObjectFormat(llvm::Triple::COFF); - TargetTriple = T.str(); + RawTargetTriple = T; } - if (const Arg *A = Args.getLastArg(options::OPT_target)) - TargetTriple = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_ccc_install_dir)) Dir = InstalledDir = A->getValue(); for (const Arg *A : Args.filtered(options::OPT_B)) { @@ -1173,9 +1172,22 @@ // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); - // Owned by the host. - const ToolChain &TC = getToolChain( - *UArgs, computeTargetTriple(*this, TargetTriple, *UArgs)); + // If command line flags such as -m32, etc. changed parts of the triple that + // are not just changes to normalization, we also need to update the raw + // triple string that is used to find tools. This ensures e.g. that clang -m32 + // searches for i386-*-ld instead of x86_64-*-ld when linking (and also uses + // the triple-prefixed library paths). + // Note: It is important that we don't normalize this triple to avoid adding + // empty triple components. + if (const Arg *A = Args.getLastArg(options::OPT_target)) + RawTargetTriple = llvm::Triple(A->getValue()); + llvm::Triple EffectiveTriple = computeTargetTriple( + *this, RawTargetTriple.str(), *UArgs, "", /*Normalize=*/false); + if (RawTargetTriple != EffectiveTriple) + RawTargetTriple = EffectiveTriple; + // Owned by the host (and unlike RawTargetTriple this triple is normalized). + const ToolChain &TC = + getToolChain(*UArgs, llvm::Triple(EffectiveTriple.normalize())); // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs, @@ -4562,7 +4574,7 @@ if (!ArchName.empty()) TC = &getToolChain(C.getArgs(), - computeTargetTriple(*this, TargetTriple, + computeTargetTriple(*this, RawTargetTriple.str(), C.getArgs(), ArchName)); else TC = &C.getDefaultToolChain(); @@ -4752,8 +4764,7 @@ } const char *Driver::getDefaultImageName() const { - llvm::Triple Target(llvm::Triple::normalize(TargetTriple)); - return Target.isOSWindows() ? "a.exe" : "a.out"; + return RawTargetTriple.isOSWindows() ? "a.exe" : "a.out"; } /// Create output filename based on ArgValue, which could either be a @@ -5067,8 +5078,7 @@ void Driver::generatePrefixedToolNames( StringRef Tool, const ToolChain &TC, SmallVectorImpl &Names) const { - // FIXME: Needs a better variable than TargetTriple - Names.emplace_back((TargetTriple + "-" + Tool).str()); + Names.emplace_back((RawTargetTriple.str() + "-" + Tool).str()); Names.emplace_back(Tool); } diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -487,7 +487,7 @@ // First try the triple passed to driver as --target=. P.assign(D.ResourceDir); - llvm::sys::path::append(P, "lib", D.getTargetTriple()); + llvm::sys::path::append(P, "lib", D.getRawTargetTriple()); if (getVFS().exists(P)) return llvm::Optional(std::string(P.str())); @@ -505,7 +505,7 @@ // First try the triple passed to driver as --target=. P.assign(D.Dir); - llvm::sys::path::append(P, "..", "lib", D.getTargetTriple(), "c++"); + llvm::sys::path::append(P, "..", "lib", D.getRawTargetTriple(), "c++"); if (getVFS().exists(P)) return llvm::Optional(std::string(P.str())); 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 @@ -179,7 +179,7 @@ SmallString<128> SysRootDir; llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes", - getDriver().getTargetTriple()); + getDriver().getRawTargetTriple()); SysRootDir += SelectedMultilib.osSuffix(); return std::string(SysRootDir); diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -41,7 +41,7 @@ return true; SmallString<128> GCCDir; - llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(), + llvm::sys::path::append(GCCDir, D.Dir, "..", D.getRawTargetTriple(), "lib/crt0.o"); return llvm::sys::fs::exists(GCCDir); } @@ -129,7 +129,7 @@ // Use the triple as provided to the driver. Unlike the parsed triple // this has not been normalized to always contain every field. llvm::sys::path::append(SysRootDir, getDriver().Dir, "..", - getDriver().getTargetTriple()); + getDriver().getRawTargetTriple()); } if (!llvm::sys::fs::exists(SysRootDir)) diff --git a/clang/test/Driver/Inputs/basic_freebsd64_tree/usr/bin/i386-unknown-freebsd12.2-ld b/clang/test/Driver/Inputs/basic_freebsd64_tree/usr/bin/i386-unknown-freebsd12.2-ld new file mode 100755 --- /dev/null +++ b/clang/test/Driver/Inputs/basic_freebsd64_tree/usr/bin/i386-unknown-freebsd12.2-ld @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/Inputs/basic_freebsd64_tree/usr/bin/x86_64-unknown-freebsd12.2-ld b/clang/test/Driver/Inputs/basic_freebsd64_tree/usr/bin/x86_64-unknown-freebsd12.2-ld new file mode 100755 --- /dev/null +++ b/clang/test/Driver/Inputs/basic_freebsd64_tree/usr/bin/x86_64-unknown-freebsd12.2-ld @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/freebsd-m32.c b/clang/test/Driver/freebsd-m32.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/freebsd-m32.c @@ -0,0 +1,52 @@ +// Check that building with -m32 links with x86_64-unknown-freebsd12.2-ld +// instead of x86_64-unknown-freebsd12.2-ld. + +/// We should select x86_64-unknown-freebsd12.2-ld since it matches the triple argument +/// Note: The paths specified by -B are not searched for triple-prefixed tools, so +/// we also have to set $PATH. +// RUN: env PATH=%S/Inputs/basic_freebsd64_tree/usr/bin %clang -no-canonical-prefixes \ +// RUN: -target x86_64-unknown-freebsd12.2 %s \ +// RUN: -B%S/Inputs/basic_freebsd64_tree/usr/bin -### 2>&1 | FileCheck %s --check-prefix=PREFIXED-64 +// PREFIXED-64: "-cc1" "-triple" "x86_64-unknown-freebsd12.2" +// PREFIXED-64-NEXT: "{{.+}}/Inputs/basic_freebsd64_tree/usr/bin/x86_64-unknown-freebsd12.2-ld" "--eh-frame-hdr" +// RUN: env PATH=/this/path/does/not/exist %clang -no-canonical-prefixes \ +// RUN: -target x86_64-unknown-freebsd12.2 %s \ +// RUN: -B%S/Inputs/basic_freebsd64_tree/usr/bin -### 2>&1 | FileCheck %s --check-prefix=MINUS-B-NO-TRIPLE-PREFIX +// MINUS-B-NO-TRIPLE-PREFIX: "-cc1" "-triple" "x86_64-unknown-freebsd12.2" +// MINUS-B-NO-TRIPLE-PREFIX-NEXT: "ld" "--eh-frame-hdr" + +/// The triple passed to clang -cc1 should be normalized, but the prefix when searching +/// for ld should not be normalized. Since there is no x86_64-freebsd12.2-ld, passing +/// -target x86_64-freebsd12.2 should not find a a valid linker: +// RUN: env PATH=%S/Inputs/basic_freebsd64_tree/usr/bin %clang -no-canonical-prefixes \ +// RUN: -target x86_64-freebsd12.2 %s \ +// RUN: -B%S/Inputs/basic_freebsd64_tree/usr/bin -### 2>&1 | FileCheck %s --check-prefix=NO-NORMALIZE-LD-PREFIX-64 +// NO-NORMALIZE-LD-PREFIX-64: "-cc1" "-triple" "x86_64-unknown-freebsd12.2" +// NO-NORMALIZE-LD-PREFIX-64: "ld" "--eh-frame-hdr" + +/// We should search for i386-unknown-freebsd12.2-ld when -m32 is passed: +// RUN: env PATH=%S/Inputs/basic_freebsd64_tree/usr/bin %clang -no-canonical-prefixes \ +// RUN: -target x86_64-unknown-freebsd12.2 %s -m32 \ +// RUN: -B%S/Inputs/basic_freebsd64_tree/usr/bin -### 2>&1 | FileCheck %s --check-prefix=PREFIXED-M32 +// PREFIXED-M32: "-cc1" "-triple" "i386-unknown-freebsd12.2" +// PREFIXED-M32-NEXT: "{{.+}}/Inputs/basic_freebsd64_tree/usr/bin/i386-unknown-freebsd12.2-ld" "--eh-frame-hdr" +/// Only the -cc1 triple should be normalized even when adjusted by -m32: +// RUN: env PATH=%S/Inputs/basic_freebsd64_tree/usr/bin %clang -no-canonical-prefixes \ +// RUN: -target x86_64-freebsd12.2 %s -m32 \ +// RUN: -B%S/Inputs/basic_freebsd64_tree/usr/bin -### 2>&1 | FileCheck %s --check-prefix=NO-NORMALIZE-LD-PREFIX-M32 +// NO-NORMALIZE-LD-PREFIX-M32: "-cc1" "-triple" "i386-unknown-freebsd12.2" +// NO-NORMALIZE-LD-PREFIX-M32-NEXT: "ld" "--eh-frame-hdr" + +/// Check that -m32 also affects the library name for the sanitizer runtime. +// RUN: env PATH=%S/Inputs/basic_freebsd64_tree/usr/bin %clang -no-canonical-prefixes \ +// RUN: -target x86_64-unknown-freebsd12.2 %s -fsanitize=address \ +// RUN: -B%S/Inputs/basic_freebsd64_tree/usr/bin -### 2>&1 | FileCheck %s --check-prefix=ASAN-64 +// ASAN-64: "-cc1" "-triple" "x86_64-unknown-freebsd12.2" +// ASAN-64-NEXT: "{{.+}}/Inputs/basic_freebsd64_tree/usr/bin/x86_64-unknown-freebsd12.2-ld" "--eh-frame-hdr" +// ASAN-64-SAME: lib/freebsd/libclang_rt.asan-x86_64.a" +// RUN: env PATH=%S/Inputs/basic_freebsd64_tree/usr/bin %clang -no-canonical-prefixes \ +// RUN: -target x86_64-unknown-freebsd12.2 %s -fsanitize=address -m32 \ +// RUN: -B%S/Inputs/basic_freebsd64_tree/usr/bin -### 2>&1 | FileCheck %s --check-prefix=ASAN-M32 +// ASAN-M32: "-cc1" "-triple" "i386-unknown-freebsd12.2" +// ASAN-M32-NEXT: "{{.+}}/Inputs/basic_freebsd64_tree/usr/bin/i386-unknown-freebsd12.2-ld" "--eh-frame-hdr" +// ASAN-M32-SAME: lib/freebsd/libclang_rt.asan-i386.a"