This commit is contained in:
parent
c0e4067639
commit
19b059a88c
11 changed files with 286 additions and 1 deletions
94
tests/Cuda/Cuda.cpp
Normal file
94
tests/Cuda/Cuda.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Crafter® Build
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
Catcrafts.net
|
||||
|
||||
LGPL-3.0-only.
|
||||
|
||||
End-to-end CUDA build through the V2 pipeline:
|
||||
the inner project.cpp registers a .cu translation unit via cfg.cuda, and
|
||||
crafter.build-lib drives nvcc to produce a host object that links into
|
||||
the final executable. The test skips when the CUDA SDK is missing
|
||||
(CI hosts have neither nvcc nor libcudart) and otherwise runs the built
|
||||
binary to confirm the .cu's host-callable entry returns through the link.
|
||||
|
||||
No GPU is required: the kernel is staged but never launched, so cudart's
|
||||
fat-binary registration runs at startup but device init does not.
|
||||
*/
|
||||
|
||||
import std;
|
||||
import Crafter.Build;
|
||||
#include "../_shared/TestUtil.h"
|
||||
namespace fs = std::filesystem;
|
||||
using namespace TestUtil;
|
||||
using namespace Crafter;
|
||||
|
||||
namespace {
|
||||
bool ToolPresent(std::string_view name) {
|
||||
return std::system(std::format("which {} > /dev/null 2>&1", name).c_str()) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
if (!ToolPresent("nvcc")) {
|
||||
Skip("nvcc not on PATH — install the CUDA SDK to enable this test");
|
||||
}
|
||||
|
||||
// Resolve the CUDA root from nvcc's own location so the inner project
|
||||
// can point the linker at libcudart.so without a hardcoded path.
|
||||
// Standard SDK layout puts nvcc at <root>/bin/nvcc and cudart at
|
||||
// <root>/lib64; if either assumption is broken we skip rather than
|
||||
// fail, since that means the install is non-standard.
|
||||
fs::path cwd = fs::current_path();
|
||||
auto probe = RunInDir(cwd, "command -v nvcc");
|
||||
if (probe.exitCode != 0 || probe.output.empty()) {
|
||||
Skip("nvcc not on PATH");
|
||||
}
|
||||
std::string nvccPath = probe.output;
|
||||
while (!nvccPath.empty() && (nvccPath.back() == '\n' || nvccPath.back() == '\r')) {
|
||||
nvccPath.pop_back();
|
||||
}
|
||||
fs::path real = fs::canonical(nvccPath);
|
||||
fs::path cudaLibDir = real.parent_path().parent_path() / "lib64";
|
||||
if (!fs::exists(cudaLibDir / "libcudart.so")) {
|
||||
Skip(std::format("libcudart.so not found at {} — incomplete CUDA SDK install",
|
||||
cudaLibDir.string()));
|
||||
}
|
||||
::setenv("CRAFTER_CUDA_LIBDIR", cudaLibDir.string().c_str(), 1);
|
||||
|
||||
fs::path src = cwd / "tests" / "Cuda" / "inner";
|
||||
Configuration cfg = LoadFixture("Cuda", src);
|
||||
fs::path work = fs::current_path();
|
||||
|
||||
auto br = BuildOnce(cfg);
|
||||
if (!br.result.empty()) {
|
||||
std::println(std::cerr, "build failed:\n{}", br.result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fs::path artifact = work / "bin" / "cuda-test-x86_64-pc-linux-gnu-native" / "cuda-test";
|
||||
if (!fs::exists(artifact)) {
|
||||
std::println(std::cerr, "expected artifact missing at {}", artifact.string());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// libcudart.so is on the system loader path on most CUDA installs
|
||||
// (Arch puts /opt/cuda/lib64 in /etc/ld.so.conf.d), but other distros
|
||||
// don't, so set LD_LIBRARY_PATH explicitly for the run.
|
||||
auto run = RunInDir(work, std::format(
|
||||
"LD_LIBRARY_PATH='{}' '{}'", cudaLibDir.string(), artifact.string()));
|
||||
if (run.exitCode != 0) {
|
||||
std::println(std::cerr, "artifact exited nonzero (rc={}):\n{}", run.exitCode, run.output);
|
||||
return 1;
|
||||
}
|
||||
if (run.output != "answer=42\n") {
|
||||
std::println(std::cerr, "output mismatch:\n expected: \"answer=42\\n\"\n got: {:?}", run.output);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} catch (const std::exception& e) {
|
||||
std::println(std::cerr, "test exception: {}", e.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue