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">; 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,17 @@ } } +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,6 +224,13 @@ } } +// 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) { @@ -265,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 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"