Index: cfe/trunk/include/clang/Driver/Options.td =================================================================== --- cfe/trunk/include/clang/Driver/Options.td +++ cfe/trunk/include/clang/Driver/Options.td @@ -556,6 +556,8 @@ def no_cuda_noopt_device_debug : Flag<["--"], "no-cuda-noopt-device-debug">; def cuda_path_EQ : Joined<["--"], "cuda-path=">, Group, HelpText<"CUDA installation path">; +def cuda_path_ignore_env : Joined<["--"], "cuda-path-ignore-env">, Group, + HelpText<"Ignore environment variables to detect CUDA installation">; def ptxas_path_EQ : Joined<["--"], "ptxas-path=">, Group, HelpText<"Path to ptxas (used for compiling CUDA code)">; def fcuda_flush_denormals_to_zero : Flag<["-"], "fcuda-flush-denormals-to-zero">, Index: cfe/trunk/lib/Driver/ToolChains/Cuda.cpp =================================================================== --- cfe/trunk/lib/Driver/ToolChains/Cuda.cpp +++ cfe/trunk/lib/Driver/ToolChains/Cuda.cpp @@ -8,18 +8,20 @@ //===----------------------------------------------------------------------===// #include "Cuda.h" -#include "InputInfo.h" #include "CommonArgs.h" +#include "InputInfo.h" #include "clang/Basic/Cuda.h" -#include "clang/Config/config.h" #include "clang/Basic/VirtualFileSystem.h" -#include "clang/Driver/Distro.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/Distro.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include using namespace clang::driver; @@ -61,42 +63,75 @@ const Driver &D, const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args) : D(D) { - SmallVector CudaPathCandidates; + struct Candidate { + std::string Path; + bool StrictChecking; + + Candidate(std::string Path, bool StrictChecking = false) + : Path(Path), StrictChecking(StrictChecking) {} + }; + SmallVector Candidates; // In decreasing order so we prefer newer versions to older versions. std::initializer_list Versions = {"8.0", "7.5", "7.0"}; if (Args.hasArg(clang::driver::options::OPT_cuda_path_EQ)) { - CudaPathCandidates.push_back( - Args.getLastArgValue(clang::driver::options::OPT_cuda_path_EQ)); + Candidates.emplace_back( + Args.getLastArgValue(clang::driver::options::OPT_cuda_path_EQ).str()); } else if (HostTriple.isOSWindows()) { for (const char *Ver : Versions) - CudaPathCandidates.push_back( + Candidates.emplace_back( D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" + Ver); } else { - CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); + if (!Args.hasArg(clang::driver::options::OPT_cuda_path_ignore_env)) { + // Try to find ptxas binary. If the executable is located in a directory + // called 'bin/', its parent directory might be a good guess for a valid + // CUDA installation. + // However, some distributions might installs 'ptxas' to /usr/bin. In that + // case the candidate would be '/usr' which passes the following checks + // because '/usr/include' exists as well. To avoid this case, we always + // check for the directory potentially containing files for libdevice, + // even if the user passes -nocudalib. + if (llvm::ErrorOr ptxas = + llvm::sys::findProgramByName("ptxas")) { + SmallString<256> ptxasAbsolutePath; + llvm::sys::fs::real_path(*ptxas, ptxasAbsolutePath); + + StringRef ptxasDir = llvm::sys::path::parent_path(ptxasAbsolutePath); + if (llvm::sys::path::filename(ptxasDir) == "bin") + Candidates.emplace_back(llvm::sys::path::parent_path(ptxasDir), + /*StrictChecking=*/true); + } + } + + Candidates.emplace_back(D.SysRoot + "/usr/local/cuda"); for (const char *Ver : Versions) - CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver); + Candidates.emplace_back(D.SysRoot + "/usr/local/cuda-" + Ver); if (Distro(D.getVFS()).IsDebian()) // Special case for Debian to have nvidia-cuda-toolkit work // out of the box. More info on http://bugs.debian.org/882505 - CudaPathCandidates.push_back(D.SysRoot + "/usr/lib/cuda"); + Candidates.emplace_back(D.SysRoot + "/usr/lib/cuda"); } - for (const auto &CudaPath : CudaPathCandidates) { - if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) + bool NoCudaLib = Args.hasArg(options::OPT_nocudalib); + + for (const auto &Candidate : Candidates) { + InstallPath = Candidate.Path; + if (InstallPath.empty() || !D.getVFS().exists(InstallPath)) continue; - InstallPath = CudaPath; - BinPath = CudaPath + "/bin"; + BinPath = InstallPath + "/bin"; IncludePath = InstallPath + "/include"; LibDevicePath = InstallPath + "/nvvm/libdevice"; auto &FS = D.getVFS(); if (!(FS.exists(IncludePath) && FS.exists(BinPath))) continue; + bool CheckLibDevice = (!NoCudaLib || Candidate.StrictChecking); + if (CheckLibDevice && !FS.exists(LibDevicePath)) + continue; // On Linux, we have both lib and lib64 directories, and we need to choose // based on our triple. On MacOS, we have only a lib directory. @@ -180,7 +215,7 @@ // Check that we have found at least one libdevice that we can link in if // -nocudalib hasn't been specified. - if (LibDeviceMap.empty() && !Args.hasArg(options::OPT_nocudalib)) + if (LibDeviceMap.empty() && !NoCudaLib) continue; IsValid = true; Index: cfe/trunk/test/Driver/Inputs/CUDA-symlinks/usr/bin/ptxas =================================================================== --- cfe/trunk/test/Driver/Inputs/CUDA-symlinks/usr/bin/ptxas +++ cfe/trunk/test/Driver/Inputs/CUDA-symlinks/usr/bin/ptxas @@ -0,0 +1 @@ +link ../../opt/cuda/bin/ptxas \ No newline at end of file Index: cfe/trunk/test/Driver/cuda-detect-path.cu =================================================================== --- cfe/trunk/test/Driver/cuda-detect-path.cu +++ cfe/trunk/test/Driver/cuda-detect-path.cu @@ -0,0 +1,83 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: nvptx-registered-target +// This tests uses the PATH environment variable. +// REQUIRES: !system-windows + +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-unknown-linux --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-apple-macosx --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-unknown-linux --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-apple-macosx --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s + + +// Check that we follow ptxas binaries that are symlinks. +// RUN: env PATH=%S/Inputs/CUDA-symlinks/usr/bin \ +// RUN: %clang -v --target=i386-unknown-linux --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix SYMLINKS +// RUN: env PATH=%S/Inputs/CUDA-symlinks/usr/bin \ +// RUN: %clang -v --target=i386-apple-macosx --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix SYMLINKS +// RUN: env PATH=%S/Inputs/CUDA-symlinks/usr/bin \ +// RUN: %clang -v --target=x86_64-unknown-linux --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix SYMLINKS +// RUN: env PATH=%S/Inputs/CUDA-symlinks/usr/bin \ +// RUN: %clang -v --target=x86_64-apple-macosx --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix SYMLINKS + + +// We only take a CUDA installation from PATH if it contains libdevice. +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-unknown-linux --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-apple-macosx --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-unknown-linux --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-apple-macosx --sysroot=%S/no-cuda-there \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA + +// We even require libdevice if -nocudalib is passed to avoid false positives +// if the distribution merges CUDA into /usr and ptxas ends up /usr/bin. +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-unknown-linux --sysroot=%S/no-cuda-there -nocudalib \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-apple-macosx --sysroot=%S/no-cuda-there -nocudalib \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-unknown-linux --sysroot=%S/no-cuda-there -nocudalib \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA-nolibdevice/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-apple-macosx --sysroot=%S/no-cuda-there -nocudalib \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA + + +// Check that the CUDA installation in PATH is not taken when passing +// the option --cuda-path-ignore-env. +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-unknown-linux --sysroot=%S/no-cuda-there --cuda-path-ignore-env \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=i386-apple-macosx --sysroot=%S/no-cuda-there --cuda-path-ignore-env \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-unknown-linux --sysroot=%S/no-cuda-there --cuda-path-ignore-env \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA +// RUN: env PATH=%S/Inputs/CUDA/usr/local/cuda/bin \ +// RUN: %clang -v --target=x86_64-apple-macosx --sysroot=%S/no-cuda-there --cuda-path-ignore-env \ +// RUN: 2>&1 | FileCheck %s --check-prefix NOCUDA + +// CHECK: Found CUDA installation: {{.*}}/Inputs/CUDA/usr/local/cuda +// SYMLINKS: Found CUDA installation: {{.*}}/Inputs/CUDA-symlinks/opt/cuda +// NOCUDA-NOT: Found CUDA installation: Index: cfe/trunk/test/Driver/cuda-detect.cu =================================================================== --- cfe/trunk/test/Driver/cuda-detect.cu +++ cfe/trunk/test/Driver/cuda-detect.cu @@ -4,9 +4,14 @@ // // Check that we properly detect CUDA installation. // RUN: %clang -v --target=i386-unknown-linux \ -// RUN: --sysroot=%S/no-cuda-there 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: --sysroot=%S/no-cuda-there --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA // RUN: %clang -v --target=i386-apple-macosx \ -// RUN: --sysroot=%S/no-cuda-there 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: --sysroot=%S/no-cuda-there --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: %clang -v --target=x86_64-unknown-linux \ +// RUN: --sysroot=%S/no-cuda-there --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: %clang -v --target=x86_64-apple-macosx \ +// RUN: --sysroot=%S/no-cuda-there --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA + // RUN: %clang -v --target=i386-unknown-linux \ // RUN: --sysroot=%S/Inputs/CUDA 2>&1 | FileCheck %s @@ -20,15 +25,23 @@ // Check that we don't find a CUDA installation without libdevice ... // RUN: %clang -v --target=i386-unknown-linux \ -// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA // RUN: %clang -v --target=i386-apple-macosx \ -// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: %clang -v --target=x86_64-unknown-linux \ +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA +// RUN: %clang -v --target=x84_64-apple-macosx \ +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NOCUDA // ... unless the user doesn't need libdevice // RUN: %clang -v --target=i386-unknown-linux -nocudalib \ -// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE // RUN: %clang -v --target=i386-apple-macosx -nocudalib \ -// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE +// RUN: %clang -v --target=x86_64-unknown-linux -nocudalib \ +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE +// RUN: %clang -v --target=x86_64-apple-macosx -nocudalib \ +// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice --cuda-path-ignore-env 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE // Make sure we map libdevice bitcode files to proper GPUs. These Index: cfe/trunk/test/Driver/cuda-not-found.cu =================================================================== --- cfe/trunk/test/Driver/cuda-not-found.cu +++ cfe/trunk/test/Driver/cuda-not-found.cu @@ -3,10 +3,10 @@ // Check that we raise an error if we're trying to compile CUDA code but can't // find a CUDA install, unless -nocudainc was passed. -// RUN: %clang -### --sysroot=%s/no-cuda-there %s 2>&1 | FileCheck %s --check-prefix ERR +// RUN: %clang -### --sysroot=%s/no-cuda-there --cuda-path-ignore-env %s 2>&1 | FileCheck %s --check-prefix ERR // RUN: %clang -### --cuda-path=%s/no-cuda-there %s 2>&1 | FileCheck %s --check-prefix ERR // ERR: cannot find CUDA installation -// RUN: %clang -### -nocudainc --sysroot=%s/no-cuda-there %s 2>&1 | FileCheck %s --check-prefix OK +// RUN: %clang -### -nocudainc --sysroot=%s/no-cuda-there --cuda-path-ignore-env %s 2>&1 | FileCheck %s --check-prefix OK // RUN: %clang -### -nocudainc --cuda-path=%s/no-cuda-there %s 2>&1 | FileCheck %s --check-prefix OK // OK-NOT: cannot find CUDA installation Index: cfe/trunk/test/Driver/cuda-version-check.cu =================================================================== --- cfe/trunk/test/Driver/cuda-version-check.cu +++ cfe/trunk/test/Driver/cuda-version-check.cu @@ -2,40 +2,40 @@ // REQUIRES: x86-registered-target // REQUIRES: nvptx-registered-target -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_20 --sysroot=%S/Inputs/CUDA 2>&1 %s | \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_20 --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=OK -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_20 --sysroot=%S/Inputs/CUDA_80 2>&1 %s | \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_20 --cuda-path=%S/Inputs/CUDA_80/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=OK -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --sysroot=%S/Inputs/CUDA_80 2>&1 %s | \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA_80/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=OK // The installation at Inputs/CUDA is CUDA 7.0, which doesn't support sm_60. -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --sysroot=%S/Inputs/CUDA 2>&1 %s | \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=ERR_SM60 // This should only complain about sm_60, not sm_35. // RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-gpu-arch=sm_35 \ -// RUN: --sysroot=%S/Inputs/CUDA 2>&1 %s | \ +// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=ERR_SM60 --check-prefix=OK_SM35 // We should get two errors here, one for sm_60 and one for sm_61. // RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-gpu-arch=sm_61 \ -// RUN: --sysroot=%S/Inputs/CUDA 2>&1 %s | \ +// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=ERR_SM60 --check-prefix=ERR_SM61 // We should still get an error if we pass -nocudainc, because this compilation // would invoke ptxas, and we do a version check on that, too. -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 -nocudainc --sysroot=%S/Inputs/CUDA 2>&1 %s | \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 -nocudainc --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=ERR_SM60 // If with -nocudainc and -E, we don't touch the CUDA install, so we // shouldn't get an error. // RUN: %clang --target=x86_64-linux -v -### -E --cuda-device-only --cuda-gpu-arch=sm_60 -nocudainc \ -// RUN: --sysroot=%S/Inputs/CUDA 2>&1 %s | \ +// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=OK // --no-cuda-version-check should suppress all of these errors. -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --sysroot=%S/Inputs/CUDA 2>&1 \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 \ // RUN: --no-cuda-version-check %s | \ // RUN: FileCheck %s --check-prefix=OK @@ -43,9 +43,9 @@ // therefore we should not get an error in host-only mode. We use the -S here // to avoid the error being produced in case by the assembler tool, which does // the same check. -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-host-only --sysroot=%S/Inputs/CUDA -S 2>&1 %s | \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-host-only --cuda-path=%S/Inputs/CUDA/usr/local/cuda -S 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=OK -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-device-only --sysroot=%S/Inputs/CUDA -S 2>&1 %s | \ +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-device-only --cuda-path=%S/Inputs/CUDA/usr/local/cuda -S 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=ERR_SM60 // OK-NOT: error: GPU arch