Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -2647,6 +2647,9 @@ def single__module : Flag<["-"], "single_module">; def specs_EQ : Joined<["-", "--"], "specs=">; def specs : Separate<["-", "--"], "specs">, Flags<[Unsupported]>; +def static_EQ : CommaJoined<["-"], "static=">, + MetaVarName<"">, + HelpText<"Link in specified components statically">; def static_libgcc : Flag<["-"], "static-libgcc">; def static_libstdcxx : Flag<["-"], "static-libstdc++">; def static : Flag<["-", "--"], "static">, Flags<[NoArgumentUnused]>; Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -17,6 +17,7 @@ #include "clang/Driver/Multilib.h" #include "clang/Driver/Types.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" @@ -105,6 +106,11 @@ UNW_Libgcc }; + enum LibType { + LT_cxxstdlib, + LT_rtlib, + }; + enum RTTIMode { RM_Enabled, RM_Disabled, @@ -146,6 +152,7 @@ mutable std::unique_ptr SanitizerArguments; mutable std::unique_ptr XRayArguments; + mutable llvm::DenseSet StaticLibs; /// The effective clang triple for the current Job. mutable llvm::Triple EffectiveTriple; @@ -242,6 +249,8 @@ const XRayArgs& getXRayArgs() const; + bool linksStaticLib(LibType Lib) const { return StaticLibs.count(Lib); } + // Returns the Arg * that explicitly turned on/off rtti, or nullptr. const llvm::opt::Arg *getRTTIArg() const { return CachedRTTIArg; } Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -84,6 +84,28 @@ std::string CandidateLibPath = getArchSpecificLibPath(); if (getVFS().exists(CandidateLibPath)) getFilePaths().push_back(CandidateLibPath); + + std::vector Libs; + for (const Arg *A : Args.filtered(options::OPT_static_EQ)) { + A->claim(); + for (StringRef C : A->getValues()) { + if (C == "c++stdlib") + StaticLibs.insert(LT_cxxstdlib); + else if (C == "rtlib") + StaticLibs.insert(LT_rtlib); + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << C; + } + } + + if (Args.hasArg(options::OPT_static)) + for (LibType L : {LT_cxxstdlib, LT_rtlib}) + StaticLibs.insert(L); + if (Args.hasArg(options::OPT_static_libstdcxx)) + StaticLibs.insert(LT_cxxstdlib); + if (Args.hasArg(options::OPT_static_libgcc)) + StaticLibs.insert(LT_rtlib); } void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) { Index: lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- lib/Driver/ToolChains/CommonArgs.cpp +++ lib/Driver/ToolChains/CommonArgs.cpp @@ -1134,9 +1134,10 @@ enum class LibGccType { UnspecifiedLibGcc, StaticLibGcc, SharedLibGcc }; -static LibGccType getLibGccType(const Driver &D, const ArgList &Args) { - if (Args.hasArg(options::OPT_static_libgcc) || - Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie)) +static LibGccType getLibGccType(const ToolChain &TC, const Driver &D, + const ArgList &Args) { + if (TC.linksStaticLib(ToolChain::LT_rtlib) || + Args.hasArg(options::OPT_static_pie)) return LibGccType::StaticLibGcc; if (Args.hasArg(options::OPT_shared_libgcc) || D.CCCIsCXX()) return LibGccType::SharedLibGcc; @@ -1165,7 +1166,7 @@ UNW == ToolChain::UNW_None) return; - LibGccType LGT = getLibGccType(D, Args); + LibGccType LGT = getLibGccType(TC, D, Args); bool AsNeeded = LGT == LibGccType::UnspecifiedLibGcc && !TC.getTriple().isAndroid() && !TC.getTriple().isOSCygMing(); if (AsNeeded) @@ -1175,7 +1176,7 @@ case ToolChain::UNW_None: return; case ToolChain::UNW_Libgcc: { - LibGccType LGT = getLibGccType(D, Args); + LibGccType LGT = getLibGccType(TC, D, Args); if (LGT == LibGccType::StaticLibGcc) CmdArgs.push_back("-lgcc_eh"); else @@ -1193,7 +1194,7 @@ static void AddLibgcc(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { - LibGccType LGT = getLibGccType(D, Args); + LibGccType LGT = getLibGccType(TC, D, Args); if (LGT != LibGccType::SharedLibGcc) CmdArgs.push_back("-lgcc"); AddUnwindLibrary(TC, D, CmdArgs, Args); Index: lib/Driver/ToolChains/CrossWindows.cpp =================================================================== --- lib/Driver/ToolChains/CrossWindows.cpp +++ lib/Driver/ToolChains/CrossWindows.cpp @@ -167,12 +167,12 @@ AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); if (TC.ShouldLinkCXXStdlib(Args)) { - bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); - if (StaticCXX) + bool StaticCXXStdlib = TC.linksStaticLib(ToolChain::LT_cxxstdlib) && + !Args.hasArg(options::OPT_static); + if (StaticCXXStdlib) CmdArgs.push_back("-Bstatic"); TC.AddCXXStdlibLibArgs(Args, CmdArgs); - if (StaticCXX) + if (StaticCXXStdlib) CmdArgs.push_back("-Bdynamic"); } Index: lib/Driver/ToolChains/DragonFly.cpp =================================================================== --- lib/Driver/ToolChains/DragonFly.cpp +++ lib/Driver/ToolChains/DragonFly.cpp @@ -53,7 +53,8 @@ const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); + const ToolChain &TC = getToolChain(); + const Driver &D = TC.getDriver(); ArgStringList CmdArgs; if (!D.SysRoot.empty()) @@ -138,10 +139,9 @@ CmdArgs.push_back("-lc"); } - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_static_libgcc)) { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lgcc_eh"); + if (TC.linksStaticLib(ToolChain::LT_rtlib)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lgcc_eh"); } else { if (Args.hasArg(options::OPT_shared_libgcc)) { CmdArgs.push_back("-lgcc_pic"); Index: lib/Driver/ToolChains/Fuchsia.cpp =================================================================== --- lib/Driver/ToolChains/Fuchsia.cpp +++ lib/Driver/ToolChains/Fuchsia.cpp @@ -123,14 +123,15 @@ if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { - bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); + bool StaticCXXStdlib = + ToolChain.linksStaticLib(ToolChain::LT_cxxstdlib) && + !Args.hasArg(options::OPT_static); CmdArgs.push_back("--push-state"); CmdArgs.push_back("--as-needed"); - if (OnlyLibstdcxxStatic) + if (StaticCXXStdlib) CmdArgs.push_back("-Bstatic"); ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) + if (StaticCXXStdlib) CmdArgs.push_back("-Bdynamic"); CmdArgs.push_back("-lm"); CmdArgs.push_back("--pop-state"); Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -528,12 +528,13 @@ if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { - bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); - if (OnlyLibstdcxxStatic) + bool StaticCXXStdlib = + ToolChain.linksStaticLib(ToolChain::LT_cxxstdlib) && + !Args.hasArg(options::OPT_static); + if (StaticCXXStdlib) CmdArgs.push_back("-Bstatic"); ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) + if (StaticCXXStdlib) CmdArgs.push_back("-Bdynamic"); } CmdArgs.push_back("-lm"); Index: lib/Driver/ToolChains/Hexagon.cpp =================================================================== --- lib/Driver/ToolChains/Hexagon.cpp +++ lib/Driver/ToolChains/Hexagon.cpp @@ -218,7 +218,6 @@ Args.ClaimAllArgs(options::OPT_emit_llvm); Args.ClaimAllArgs(options::OPT_w); // Other warning options are already // handled somewhere else. - Args.ClaimAllArgs(options::OPT_static_libgcc); //---------------------------------------------------------------------------- // Index: lib/Driver/ToolChains/MinGW.cpp =================================================================== --- lib/Driver/ToolChains/MinGW.cpp +++ lib/Driver/ToolChains/MinGW.cpp @@ -65,8 +65,7 @@ // Make use of compiler-rt if --rtlib option is used ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args); if (RLT == ToolChain::RLT_Libgcc) { - bool Static = Args.hasArg(options::OPT_static_libgcc) || - Args.hasArg(options::OPT_static); + bool Static = getToolChain().linksStaticLib(ToolChain::LT_rtlib); bool Shared = Args.hasArg(options::OPT_shared); bool CXX = getToolChain().getDriver().CCCIsCXX(); @@ -191,12 +190,12 @@ // TODO: Add profile stuff here if (TC.ShouldLinkCXXStdlib(Args)) { - bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); - if (OnlyLibstdcxxStatic) + bool StaticCXXStdlib = TC.linksStaticLib(ToolChain::LT_cxxstdlib) && + !Args.hasArg(options::OPT_static); + if (StaticCXXStdlib) CmdArgs.push_back("-Bstatic"); TC.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) + if (StaticCXXStdlib) CmdArgs.push_back("-Bdynamic"); } Index: lib/Driver/ToolChains/Myriad.cpp =================================================================== --- lib/Driver/ToolChains/Myriad.cpp +++ lib/Driver/ToolChains/Myriad.cpp @@ -144,7 +144,6 @@ // Eat some arguments that may be present but have no effect. Args.ClaimAllArgs(options::OPT_g_Group); Args.ClaimAllArgs(options::OPT_w); - Args.ClaimAllArgs(options::OPT_static_libgcc); if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. CmdArgs.push_back("-s"); Index: lib/Driver/ToolChains/NaCl.cpp =================================================================== --- lib/Driver/ToolChains/NaCl.cpp +++ lib/Driver/ToolChains/NaCl.cpp @@ -134,7 +134,7 @@ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = - Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; + ToolChain.linksStaticLib(ToolChain::LT_cxxstdlib) && !IsStatic; if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bstatic"); ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); Index: test/Driver/fuchsia.cpp =================================================================== --- test/Driver/fuchsia.cpp +++ test/Driver/fuchsia.cpp @@ -33,6 +33,10 @@ // RUN: | FileCheck %s -check-prefix=CHECK-STDLIB // CHECK-STDLIB: error: invalid library name in argument '-stdlib=libstdc++' +// RUN: %clangxx %s -### --target=x86_64-unknown-fuchsia -static=c++stdlib \ +// RUN: -fuse-ld=lld 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-STATIC + // RUN: %clangxx %s -### --target=x86_64-unknown-fuchsia -static-libstdc++ \ // RUN: -fuse-ld=lld 2>&1 \ // RUN: | FileCheck %s -check-prefix=CHECK-STATIC Index: test/Driver/linux-ld.c =================================================================== --- test/Driver/linux-ld.c +++ test/Driver/linux-ld.c @@ -131,11 +131,17 @@ // CHECK-LD-GCC: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" // CHECK-LD-GCC: "-lc" // CHECK-LD-GCC: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" -// + // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=x86_64-unknown-linux -rtlib=platform \ -// RUN: -static-libgcc \ -// RUN: --gcc-toolchain="" \ +// RUN: -static=rtlib --gcc-toolchain="" \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC-LIBGCC %s + +// -static-libgcc is an alias of -static=rtlib +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: --target=x86_64-unknown-linux -rtlib=platform \ +// RUN: -static-libgcc --gcc-toolchain="" \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ // RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC-LIBGCC %s // CHECK-LD-64-STATIC-LIBGCC-NOT: warning: @@ -243,7 +249,7 @@ // CHECK-CLANG-NO-LIBGCC-DYNAMIC: "-lc" // CHECK-CLANG-NO-LIBGCC-DYNAMIC: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" // -// RUN: %clang -static-libgcc -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: %clang -static=rtlib -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=x86_64-unknown-linux -rtlib=platform \ // RUN: --gcc-toolchain="" \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ @@ -253,7 +259,7 @@ // CHECK-CLANG-STATIC-LIBGCC: "-lc" // CHECK-CLANG-STATIC-LIBGCC: "-lgcc" "-lgcc_eh" // -// RUN: %clang -static-libgcc -dynamic -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: %clang -static=rtlib -dynamic -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=x86_64-unknown-linux -rtlib=platform \ // RUN: --gcc-toolchain="" \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ @@ -329,7 +335,7 @@ // Check that flags can be combined. The -static dominates. // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=x86_64-unknown-linux -rtlib=platform \ -// RUN: -static-libgcc -static \ +// RUN: -static=rtlib -static \ // RUN: --gcc-toolchain="" \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ // RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s Index: test/Driver/linux-musl.cpp =================================================================== --- /dev/null +++ test/Driver/linux-musl.cpp @@ -0,0 +1,13 @@ +// RUN: %clangxx -no-canonical-prefixes %s -### -target x86_64-linux-musl 2>&1 \ +// RUN: -static=c++stdlib -stdlib=libc++ \ +// RUN: -ccc-install-dir %S/Inputs/basic_linux_tree/usr/bin \ +// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree \ +// RUN: | FileCheck --check-prefix=CHECK-STATIC-LIBCXX %s +// CHECK-STATIC-LIBCXX: "-Bstatic" "-lc++" "-Bdynamic" "-lm" "-lgcc_s" "-lgcc" "-lc" "-lgcc_s" "-lgcc" + +// RUN: %clangxx -no-canonical-prefixes %s -### -target x86_64-linux-musl 2>&1 \ +// RUN: -static=c++stdlib,rtlib -stdlib=libc++ \ +// RUN: -ccc-install-dir %S/Inputs/basic_linux_tree/usr/bin \ +// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree \ +// RUN: | FileCheck --check-prefix=CHECK-STATIC-LIBCXX-RTLIB %s +// CHECK-STATIC-LIBCXX-RTLIB: "-Bstatic" "-lc++" "-Bdynamic" "-lm" "-lgcc" "-lgcc_eh" "-lc" "-lgcc" "-lgcc_eh" Index: test/Driver/static.c =================================================================== --- /dev/null +++ test/Driver/static.c @@ -0,0 +1,5 @@ +// RUN: %clang -target %itanium_abi_triple %s -static=c++stdlib,rtlib -### 2>&1 | \ +// RUN: FileCheck /dev/null --implicit-check-not=error: + +// RUN: %clang -target %itanium_abi_triple %s -static=unknown -### 2>&1 | FileCheck --check-prefix=STATIC-UNKNOWN %s +// STATIC-UNKNOWN: error: unsupported argument 'unknown' to option 'static='