Some checks failed
CI / build-test-release (push) Has been cancelled
94 lines
3.6 KiB
C++
94 lines
3.6 KiB
C++
/*
|
|
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;
|
|
}
|
|
}
|