def no_cuda_noopt_device_debug : Flag<["--"], "no-cuda-noopt-device-debug">;
def cuda_path_EQ : Joined<["--"], "cuda-path=">, Group<i_Group>,
HelpText<"CUDA installation path">;
+def cuda_path_ignore_env : Joined<["--"], "cuda-path-ignore-env">, Group<i_Group>,
+ HelpText<"Ignore environment variables to detect CUDA installation">;
def ptxas_path_EQ : Joined<["--"], "ptxas-path=">, Group<i_Group>,
HelpText<"Path to ptxas (used for compiling CUDA code)">;
def fcuda_flush_denormals_to_zero : Flag<["-"], "fcuda-flush-denormals-to-zero">,
//===----------------------------------------------------------------------===//
#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 <system_error>
using namespace clang::driver;
const Driver &D, const llvm::Triple &HostTriple,
const llvm::opt::ArgList &Args)
: D(D) {
- SmallVector<std::string, 4> CudaPathCandidates;
+ struct Candidate {
+ std::string Path;
+ bool StrictChecking;
+
+ Candidate(std::string Path, bool StrictChecking = false)
+ : Path(Path), StrictChecking(StrictChecking) {}
+ };
+ SmallVector<Candidate, 4> Candidates;
// In decreasing order so we prefer newer versions to older versions.
std::initializer_list<const char *> 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<std::string> 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.
// 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;
--- /dev/null
+../../opt/cuda/bin/ptxas
\ No newline at end of file
--- /dev/null
+// 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:
//
// 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
// 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
// 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
// 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
// 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