Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1632,6 +1632,8 @@ def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option]>, HelpText<"Disable builtin #include directories">; def nocudainc : Flag<["-"], "nocudainc">; +def nocudalib : Flag<["-"], "nocudalib">, + HelpText<"Don't link with libraries necessary for running CUDA (-L/path/to/cuda/lib{,64} -lcudart_static -lrt -lpthread -ldl)">; def nocudalibdevice : Flag<["-"], "nocudalibdevice">, HelpText<"Don't link in the CUDA libdevice bitcode (libdevice.compute_xx.yy.bc)">; def nodefaultlibs : Flag<["-"], "nodefaultlibs">; Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -408,6 +408,10 @@ virtual void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; + /// \brief Add LD arguments pointing to CUDA libraries. + virtual void AddCudaLinkerArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &LDArgs) const; + /// \brief Return sanitizers which are available in this toolchain. virtual SanitizerMask getSupportedSanitizers() const; }; Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -665,4 +665,11 @@ } void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const {} + ArgStringList &CC1Args) const { + // Only supported on Linux at the moment. +} + +void ToolChain::AddCudaLinkerArgs(const ArgList &DriverArgs, + ArgStringList &LDArgs) const { + // Only supported on Linux at the moment. +} Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -796,6 +796,8 @@ llvm::opt::ArgStringList &CC1Args) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddCudaLinkerArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; void addProfileRTLibs(const llvm::opt::ArgList &Args, Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -4120,6 +4120,18 @@ } } +void Linux::AddCudaLinkerArgs(const ArgList &DriverArgs, + ArgStringList &LDArgs) const { + if (DriverArgs.hasArg(options::OPT_nocudalib) || !CudaInstallation.isValid()) + return; + + LDArgs.push_back("-L"); + LDArgs.push_back(DriverArgs.MakeArgString(CudaInstallation.getLibPath())); + for (const char *Flag : {"-lcudart_static", "-ldl", "-lrt", "-lpthread"}) { + LDArgs.push_back(DriverArgs.MakeArgString(Flag)); + } +} + bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } SanitizerMask Linux::getSupportedSanitizers() const { Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -224,8 +224,16 @@ } } -static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, - const ArgList &Args, ArgStringList &CmdArgs) { +// Is the given action, or any of its inputs, a CUDA action? +static bool isCudaAction(const Action* A) { + return isa(A) || isa(A) || + std::any_of(A->getInputs().begin(), A->getInputs().end(), + isCudaAction); +} + +static void AddLinkerInputs(const Compilation &C, const ToolChain &TC, + const InputInfoList &Inputs, const ArgList &Args, + ArgStringList &CmdArgs) { const Driver &D = TC.getDriver(); // Add extra linker input arguments which are not treated as inputs @@ -264,6 +272,10 @@ // and only supported on native toolchains. if (!TC.isCrossCompiling()) addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + + // Add -L/path/to/cuda/lib if any of our inputs are .cu files. + if (std::any_of(C.getActions().begin(), C.getActions().end(), isCudaAction)) + TC.AddCudaLinkerArgs(Args, CmdArgs); } /// \brief Determine whether Objective-C automated reference counting is @@ -6409,7 +6421,7 @@ {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_u_Group}); - AddLinkerInputs(HTC, Inputs, Args, CmdArgs); + AddLinkerInputs(C, HTC, Inputs, Args, CmdArgs); //---------------------------------------------------------------------------- // Libraries @@ -6472,7 +6484,7 @@ CmdArgs.push_back("old-gnu"); CmdArgs.push_back("-target"); CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString())); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); C.addCommand(llvm::make_unique(JA, *this, Args.MakeArgString(Linker), @@ -6500,7 +6512,7 @@ ArgStringList CmdArgs; CmdArgs.push_back("-flavor"); CmdArgs.push_back("ld"); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); C.addCommand(llvm::make_unique(JA, *this, Linker, CmdArgs, Inputs)); @@ -6803,7 +6815,7 @@ if (D.isUsingLTO()) AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(C, ToolChain, Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) @@ -7173,7 +7185,7 @@ Args.AddAllArgs(CmdArgs, options::OPT_L); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); // Build the input file for -filelist (list of linker input files) in case we // need it later for (const auto &II : Inputs) { @@ -7391,7 +7403,7 @@ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e, options::OPT_r}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX()) @@ -7564,7 +7576,7 @@ options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { @@ -7683,7 +7695,7 @@ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { @@ -7949,7 +7961,7 @@ AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(C, ToolChain, Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, ToolChain, Args); @@ -8245,7 +8257,7 @@ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); unsigned Major, Minor, Micro; getToolChain().getTriple().getOSVersion(Major, Minor, Micro); @@ -8832,7 +8844,7 @@ CmdArgs.push_back("--no-demangle"); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(C, ToolChain, Inputs, Args, CmdArgs); // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -9026,7 +9038,7 @@ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(C, ToolChain, Inputs, Args, CmdArgs); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -9138,7 +9150,7 @@ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -9259,7 +9271,7 @@ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { CmdArgs.push_back("-L/usr/lib/gcc50"); @@ -9762,7 +9774,7 @@ Args.AddAllArgs(CmdArgs, options::OPT_L); TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(TC, Inputs, Args, CmdArgs); + AddLinkerInputs(C, TC, Inputs, Args, CmdArgs); // TODO: Add ASan stuff here @@ -9886,7 +9898,7 @@ false)) CmdArgs.push_back("-fexceptions"); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); @@ -10040,7 +10052,7 @@ Args.AddAllArgs(CmdArgs, options::OPT_L); TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(TC, Inputs, Args, CmdArgs); + AddLinkerInputs(C, TC, Inputs, Args, CmdArgs); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { @@ -10218,7 +10230,7 @@ TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(C, getToolChain(), Inputs, Args, CmdArgs); if (UseDefaultLibs) { if (C.getDriver().CCCIsCXX()) @@ -10327,7 +10339,7 @@ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(C, ToolChain, Inputs, Args, CmdArgs); if (Args.hasArg(options::OPT_pthread)) { CmdArgs.push_back("-lpthread"); @@ -10423,7 +10435,7 @@ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + AddLinkerInputs(C, ToolChain, Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { // For PS4, we always want to pass libm, libstdc++ and libkernel Index: test/Driver/cuda-default-libs.cu =================================================================== --- /dev/null +++ test/Driver/cuda-default-libs.cu @@ -0,0 +1,42 @@ +// Checks that we add -L /path/to/cuda/lib{,64} and -lcudart_static -ldl -lrt +// -lpthread as appropriate when compiling CUDA code. + +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: nvptx-registered-target + +// RUN: %clang -### -v --target=i386-unknown-linux \ +// RUN: -lfoo --sysroot=%S/Inputs/CUDA %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix CUDA -check-prefix CUDA-x86_32 +// +// RUN: %clang -### -v --target=x86_64-unknown-linux \ +// RUN: -lfoo --sysroot=%S/Inputs/CUDA %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix CUDA -check-prefix CUDA-x86_64 +// +// # Our new flags should come after user-specified flags. +// CUDA: -lfoo +// CUDA-x86_32: "-L" "{{.*}}/Inputs/CUDA/usr/local/cuda/lib" +// CUDA-x86_64: "-L" "{{.*}}/Inputs/CUDA/usr/local/cuda/lib64" +// CUDA-x86_32-NOT: "-L" "{{.*}}/Inputs/CUDA/usr/local/cuda/lib64" +// CUDA-x86_64-NOT: "-L" "{{.*}}/Inputs/CUDA/usr/local/cuda/lib" +// CUDA-DAG: "-lcudart_static" +// CUDA-DAG: "-ldl" +// CUDA-DAG: "-lrt" +// CUDA-DAG: "-lpthread" + +// If we can't find CUDA, don't include it in our library search path, and +// don't include any additional libraries via -l. +// RUN: %clang -### -v --target=i386-unknown-linux \ +// RUN: --sysroot=%S/Inputs/no-cuda-there %s 2>&1 | FileCheck %s -check-prefix NOCUDA +// +// Also don't add anything if we pass -nocudalib. +// RUN: %clang -### -v --target=x86_64-unknown-linux -nocudalib \ +// RUN: --sysroot=%S/Inputs/CUDA %s 2>&1 | FileCheck %s -check-prefix NOCUDA +// +// NOCUDA-NOT: "-L" "{{.*}}/no-cuda-there/{{.*}}" +// NOCUDA-NOT: "-lcudart_static" +// NOCUDA-NOT: "-ldl" +// NOCUDA-NOT: "-lrt" +// NOCUDA-NOT: "-lpthread" +// NOCUDA-NOT: "-L" "{{.*}}/Inputs/CUDA/usr/local/cuda/lib" +// NOCUDA-NOT: "-L" "{{.*}}/Inputs/CUDA/usr/local/cuda/lib64"