https://github.com/daniel-levin updated https://github.com/llvm/llvm-project/pull/163000
>From c0ce9634a737a47b63dc3552bb7a15498b059c24 Mon Sep 17 00:00:00 2001 From: Daniel Levin <[email protected]> Date: Fri, 10 Oct 2025 14:54:03 +0000 Subject: [PATCH 1/2] [Clang][Solaris] Support --ld-path in Solaris driver --- clang/include/clang/Driver/ToolChain.h | 2 + clang/lib/Driver/ToolChains/CommonArgs.cpp | 8 +- clang/lib/Driver/ToolChains/Solaris.cpp | 119 ++++++++++++++------- clang/lib/Driver/ToolChains/Solaris.h | 31 +++++- 4 files changed, 119 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 1425714d34110..753742067fe8c 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -491,6 +491,8 @@ class ToolChain { } /// GetDefaultLinker - Get the default linker to use. + /// Note: this is distinct from the 'preferred' linker, which is optionally + /// set at compile time using CLANG_DEFAULT_LINKER. virtual const char *getDefaultLinker() const { return "ld"; } /// GetDefaultRuntimeLibType - Get the default runtime library variant to use. diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 16cc1db0a2235..87a6f9a89b904 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1480,11 +1480,11 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) { - bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args); + bool LinkerIsSolarisLinkEditor = solaris::isLinkerSolarisLinkEditor(TC, Args); // Solaris ld defaults to --export-dynamic behaviour but doesn't support // the option, so don't try to pass it. - if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) + if (TC.getTriple().isOSSolaris() && LinkerIsSolarisLinkEditor) return true; SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); if (llvm::sys::fs::exists(SanRT + ".syms")) { @@ -1500,14 +1500,14 @@ void tools::addAsNeededOption(const ToolChain &TC, bool as_needed) { assert(!TC.getTriple().isOSAIX() && "AIX linker does not support any form of --as-needed option yet."); - bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args); + bool LinkerIsSolarisLinkEditor = solaris::isLinkerSolarisLinkEditor(TC, Args); // While the Solaris 11.2 ld added --as-needed/--no-as-needed as aliases // for the native forms -z ignore/-z record, they are missing in Illumos, // so always use the native form. // GNU ld doesn't support -z ignore/-z record, so don't use them even on // Solaris. - if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) { + if (TC.getTriple().isOSSolaris() && LinkerIsSolarisLinkEditor) { CmdArgs.push_back("-z"); CmdArgs.push_back(as_needed ? "ignore" : "record"); } else { diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index 02aa59817449d..edd794d19cbe5 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -36,11 +36,12 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, gnutools::Assembler::ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput); } -bool solaris::isLinkerGnuLd(const ToolChain &TC, const ArgList &Args) { - // Only used if targetting Solaris. - const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ); - StringRef UseLinker = A ? A->getValue() : TC.getDriver().getPreferredLinker(); - return UseLinker == "bfd" || UseLinker == "gld"; +bool solaris::isLinkerSolarisLinkEditor(const ToolChain &TC, + const ArgList &Args) { + auto Determination = + solaris::LinkerDetermination::make(TC, Args, /* EmitDiagnostics */ false); + return Determination.Expectations == + solaris::LinkerExpectations::SolarisLinkEditor; } static bool getPIE(const ArgList &Args, const ToolChain &TC) { @@ -52,30 +53,11 @@ static bool getPIE(const ArgList &Args, const ToolChain &TC) { TC.isPIEDefault(Args)); } -// FIXME: Need to handle PreferredLinker here? std::string solaris::Linker::getLinkerPath(const ArgList &Args) const { - const ToolChain &ToolChain = getToolChain(); - if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { - StringRef UseLinker = A->getValue(); - if (!UseLinker.empty()) { - if (llvm::sys::path::is_absolute(UseLinker) && - llvm::sys::fs::can_execute(UseLinker)) - return std::string(UseLinker); - - // Accept 'bfd' and 'gld' as aliases for the GNU linker. - if (UseLinker == "bfd" || UseLinker == "gld") - // FIXME: Could also use /usr/bin/gld here. - return "/usr/gnu/bin/ld"; + auto Determination = + solaris::LinkerDetermination::make(getToolChain(), Args, true); - // Accept 'ld' as alias for the default linker - if (UseLinker != "ld") - ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name) - << A->getAsString(Args); - } - } - - // getDefaultLinker() always returns an absolute path. - return ToolChain.getDefaultLinker(); + return Determination.Linker; } void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -87,11 +69,11 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsPIE = getPIE(Args, ToolChain); - const bool LinkerIsGnuLd = isLinkerGnuLd(ToolChain, Args); + const bool LinkerIsSolarisLd = isLinkerSolarisLinkEditor(ToolChain, Args); ArgStringList CmdArgs; // Demangle C++ names in errors. GNU ld already defaults to --demangle. - if (!LinkerIsGnuLd) + if (LinkerIsSolarisLd) CmdArgs.push_back("-C"); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared, @@ -101,7 +83,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (IsPIE) { - if (LinkerIsGnuLd) { + if (!LinkerIsSolarisLd) { CmdArgs.push_back("-pie"); } else { CmdArgs.push_back("-z"); @@ -122,7 +104,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_pthreads); } - if (LinkerIsGnuLd) { + if (!LinkerIsSolarisLd) { // Set the correct linker emulation for 32- and 64-bit Solaris. switch (Arch) { case llvm::Triple::x86: @@ -256,7 +238,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Arch == llvm::Triple::x86_64 && (SA.needsAsanRt() || SA.needsStatsRt() || (SA.needsUbsanRt() && !SA.requiresMinimalRuntime())) && - !LinkerIsGnuLd) { + LinkerIsSolarisLd) { CmdArgs.push_back("-z"); CmdArgs.push_back("relax=transtls"); } @@ -344,10 +326,10 @@ SanitizerMask Solaris::getSupportedSanitizers() const { } const char *Solaris::getDefaultLinker() const { - // FIXME: Only handle Solaris ld and GNU ld here. - return llvm::StringSwitch<const char *>(getDriver().getPreferredLinker()) - .Cases("bfd", "gld", "/usr/gnu/bin/ld") - .Default("/usr/bin/ld"); + // The default linker on Solaris is _always_ the Solaris Link Editor. + // Recall that the driver's _default_ linker is distinct from the compile-time + // _preferred_ linker setting CLANG_DEFAULT_LINKER, which may even be empty. + return "/usr/bin/ld"; } Tool *Solaris::buildAssembler() const { @@ -423,3 +405,68 @@ void Solaris::addLibStdCxxIncludePaths( TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args); } + +solaris::LinkerDetermination +solaris::LinkerDetermination::make(const ToolChain &TC, const ArgList &Args, + bool EmitDiagnostics) { + // First, check --ld-path, then -fuse-ld, then the compile-time + // preferred linker (CLANG_DEFAULT_LINKER), then finally fall back to the + // platform's default - the Solaris Link Editor. This behavior is consonant + // with the other platforms' drivers. + + auto InferExpectations = + [](const std::string &s) -> solaris::LinkerExpectations { + if (s == "ld" || s == "/bin/ld" || s == "/usr/bin/ld") + return solaris::LinkerExpectations::SolarisLinkEditor; + return solaris::LinkerExpectations::GnuLdCompatibleArgParser; + }; + + if (const Arg *A = Args.getLastArg(options::OPT_ld_path_EQ)) { + StringRef UseLinker = A->getValue(); + if (!UseLinker.empty()) { + auto LinkerPath = std::string(UseLinker); + if (llvm::sys::fs::can_execute(LinkerPath)) + return solaris::LinkerDetermination(LinkerPath, + InferExpectations(LinkerPath)); + } + if (EmitDiagnostics) + TC.getDriver().Diag(diag::err_drv_invalid_linker_name) + << A->getAsString(Args); + } else if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + StringRef UseLinker = A->getValue(); + if (!UseLinker.empty()) { + if (llvm::sys::path::is_absolute(UseLinker) && + llvm::sys::fs::can_execute(UseLinker)) { + auto LinkerPath = std::string(UseLinker); + return solaris::LinkerDetermination(LinkerPath, + InferExpectations(LinkerPath)); + } + + // Accept 'bfd' and 'gld' as aliases for the GNU linker. + if (UseLinker == "bfd" || UseLinker == "gld") + return solaris::LinkerDetermination( + "/usr/gnu/bin/ld", + solaris::LinkerExpectations::GnuLdCompatibleArgParser); + + // Accept 'ld' as an alias for the default linker + if (UseLinker == "ld") + return solaris::LinkerDetermination( + "/usr/bin/ld", solaris::LinkerExpectations::SolarisLinkEditor); + + if (EmitDiagnostics) + TC.getDriver().Diag(diag::err_drv_invalid_linker_name) + << A->getAsString(Args); + } + } + + auto CompileTimePreferredLinker = TC.getDriver().getPreferredLinker(); + if (!CompileTimePreferredLinker.empty()) { + auto LinkerPath = std::string(CompileTimePreferredLinker); + return solaris::LinkerDetermination(LinkerPath, + InferExpectations(LinkerPath)); + } + + return solaris::LinkerDetermination( + std::string("/usr/bin/ld"), + solaris::LinkerExpectations::SolarisLinkEditor); +} diff --git a/clang/lib/Driver/ToolChains/Solaris.h b/clang/lib/Driver/ToolChains/Solaris.h index 9ec83b773da44..0d3a78ff09189 100644 --- a/clang/lib/Driver/ToolChains/Solaris.h +++ b/clang/lib/Driver/ToolChains/Solaris.h @@ -31,7 +31,8 @@ class LLVM_LIBRARY_VISIBILITY Assembler final : public gnutools::Assembler { const char *LinkingOutput) const override; }; -bool isLinkerGnuLd(const ToolChain &TC, const llvm::opt::ArgList &Args); +bool isLinkerSolarisLinkEditor(const ToolChain &TC, + const llvm::opt::ArgList &Args); class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: @@ -46,6 +47,34 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + +enum class LinkerExpectations { + GnuLdCompatibleArgParser, + /// The formal name for the built-in ld on Solaris. + SolarisLinkEditor, +}; + +/// We use Solaris's built-in linker by default. It has a unique command line +/// syntax and specific limitations. By contrast, other linkers such as lld, +/// Mold, and Wild are compatible with GNU ld's command line syntax. Knowing +/// _which_ linker to use is sufficient to determine the expectations of that +/// linker. Rather than spread ad-hoc string comparisons all over the driver, we +/// encapsulate the details of differences in the chosen linker here. +class LinkerDetermination final { + LinkerDetermination(std::string Linker, LinkerExpectations Expectations) + : Linker(Linker), Expectations(Expectations) {} + +public: + std::string Linker; + LinkerExpectations Expectations; + + /// Choose the correct linker based on arguments and compile-time options + /// recorded in the ToolChain. + static LinkerDetermination make(const ToolChain &TC, + const llvm::opt::ArgList &Args, + bool EmitDiagnostics); +}; + } // end namespace solaris } // end namespace tools >From cd5b23943ea8dd74bd0ca71a3a210a5fc4f3a8b5 Mon Sep 17 00:00:00 2001 From: Daniel Levin <[email protected]> Date: Wed, 22 Oct 2025 13:17:14 +0000 Subject: [PATCH 2/2] Reviewer feedback --- clang/lib/Driver/ToolChains/Solaris.cpp | 27 +++++++++---------------- clang/lib/Driver/ToolChains/Solaris.h | 12 +++-------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index edd794d19cbe5..7e727d816e560 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -40,8 +40,7 @@ bool solaris::isLinkerSolarisLinkEditor(const ToolChain &TC, const ArgList &Args) { auto Determination = solaris::LinkerDetermination::make(TC, Args, /* EmitDiagnostics */ false); - return Determination.Expectations == - solaris::LinkerExpectations::SolarisLinkEditor; + return Determination.IsSolarisLd; } static bool getPIE(const ArgList &Args, const ToolChain &TC) { @@ -414,11 +413,8 @@ solaris::LinkerDetermination::make(const ToolChain &TC, const ArgList &Args, // platform's default - the Solaris Link Editor. This behavior is consonant // with the other platforms' drivers. - auto InferExpectations = - [](const std::string &s) -> solaris::LinkerExpectations { - if (s == "ld" || s == "/bin/ld" || s == "/usr/bin/ld") - return solaris::LinkerExpectations::SolarisLinkEditor; - return solaris::LinkerExpectations::GnuLdCompatibleArgParser; + auto GuessIfSolarisLd = [](const std::string &s) -> bool { + return (s == "ld" || s == "/bin/ld" || s == "/usr/bin/ld"); }; if (const Arg *A = Args.getLastArg(options::OPT_ld_path_EQ)) { @@ -427,7 +423,7 @@ solaris::LinkerDetermination::make(const ToolChain &TC, const ArgList &Args, auto LinkerPath = std::string(UseLinker); if (llvm::sys::fs::can_execute(LinkerPath)) return solaris::LinkerDetermination(LinkerPath, - InferExpectations(LinkerPath)); + GuessIfSolarisLd(LinkerPath)); } if (EmitDiagnostics) TC.getDriver().Diag(diag::err_drv_invalid_linker_name) @@ -439,19 +435,16 @@ solaris::LinkerDetermination::make(const ToolChain &TC, const ArgList &Args, llvm::sys::fs::can_execute(UseLinker)) { auto LinkerPath = std::string(UseLinker); return solaris::LinkerDetermination(LinkerPath, - InferExpectations(LinkerPath)); + GuessIfSolarisLd(LinkerPath)); } // Accept 'bfd' and 'gld' as aliases for the GNU linker. if (UseLinker == "bfd" || UseLinker == "gld") - return solaris::LinkerDetermination( - "/usr/gnu/bin/ld", - solaris::LinkerExpectations::GnuLdCompatibleArgParser); + return solaris::LinkerDetermination("/usr/gnu/bin/ld", false); // Accept 'ld' as an alias for the default linker if (UseLinker == "ld") - return solaris::LinkerDetermination( - "/usr/bin/ld", solaris::LinkerExpectations::SolarisLinkEditor); + return solaris::LinkerDetermination("/usr/bin/ld", true); if (EmitDiagnostics) TC.getDriver().Diag(diag::err_drv_invalid_linker_name) @@ -463,10 +456,8 @@ solaris::LinkerDetermination::make(const ToolChain &TC, const ArgList &Args, if (!CompileTimePreferredLinker.empty()) { auto LinkerPath = std::string(CompileTimePreferredLinker); return solaris::LinkerDetermination(LinkerPath, - InferExpectations(LinkerPath)); + GuessIfSolarisLd(LinkerPath)); } - return solaris::LinkerDetermination( - std::string("/usr/bin/ld"), - solaris::LinkerExpectations::SolarisLinkEditor); + return solaris::LinkerDetermination(std::string("/usr/bin/ld"), true); } diff --git a/clang/lib/Driver/ToolChains/Solaris.h b/clang/lib/Driver/ToolChains/Solaris.h index 0d3a78ff09189..394ba648b53f2 100644 --- a/clang/lib/Driver/ToolChains/Solaris.h +++ b/clang/lib/Driver/ToolChains/Solaris.h @@ -48,12 +48,6 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { const char *LinkingOutput) const override; }; -enum class LinkerExpectations { - GnuLdCompatibleArgParser, - /// The formal name for the built-in ld on Solaris. - SolarisLinkEditor, -}; - /// We use Solaris's built-in linker by default. It has a unique command line /// syntax and specific limitations. By contrast, other linkers such as lld, /// Mold, and Wild are compatible with GNU ld's command line syntax. Knowing @@ -61,12 +55,12 @@ enum class LinkerExpectations { /// linker. Rather than spread ad-hoc string comparisons all over the driver, we /// encapsulate the details of differences in the chosen linker here. class LinkerDetermination final { - LinkerDetermination(std::string Linker, LinkerExpectations Expectations) - : Linker(Linker), Expectations(Expectations) {} + LinkerDetermination(std::string Linker, bool IsSolarisLd) + : Linker(Linker), IsSolarisLd(IsSolarisLd) {} public: std::string Linker; - LinkerExpectations Expectations; + bool IsSolarisLd; /// Choose the correct linker based on arguments and compile-time options /// recorded in the ToolChain. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
