test runner, cross-target runners, lib/exe split
- subprocess-isolated test runner (replaces V1 dlopen-RunTest); Pass/Fail/Crash/Timeout/Skipped outcomes via :Test partition - TestRunner abstraction with command templates: Local, Ssh, SshWin (cmd.exe-shell), QemuUser, FromEnv; probe-based skip when runner unreachable - transitive PCM-path propagation in Build(); resolveImport walks deps recursively; depResults cache keyed by PcmDir() so per-target builds don't collide - cfg.sysroot threaded through BuildStdPcm + base compile/link command (enables aarch64 cross via Arch Linux ARM rootfs) - lib + exe split: project.cpp defines crafterBuildLib (LibraryStatic) + crafterBuildExe (Executable depending on it); build.sh produces lib/libcrafter-build.a alongside bin/crafter-build for downstream static-link consumers - Windows DLL+launcher: CRAFTER_API macro, /EXPORT flag for project.dll's CrafterBuildProject; Crafter::Run as the real entry point with main.cpp as a thin wrapper - 18 tests: HelloWorld/WithModule/Defines/CrossProjectModule/ Diamond × (Linux + sshwin:winvm), plus Incremental, BuildError, Libraries, RunnerClassification, QemuUser, SshRunner, WindowsViaSsh, CrossArchAarch64 - single ./bin/crafter-build test runs everything; Windows variants skip gracefully if winvm SSH alias unreachable Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
f13671b2be
commit
cdfdb976c8
60 changed files with 2029 additions and 104 deletions
|
|
@ -59,7 +59,7 @@ std::string Crafter::RunCommand(const std::string_view cmd) {
|
|||
|
||||
CommandResult Crafter::RunCommandChecked(std::string_view cmd) {
|
||||
std::array<char, 128> buffer;
|
||||
CommandResult result{0, ""};
|
||||
CommandResult result{};
|
||||
|
||||
std::string with = "cmd /C \"" + std::string(cmd) + " 2>&1\"";
|
||||
|
||||
|
|
@ -76,6 +76,10 @@ CommandResult Crafter::RunCommandChecked(std::string_view cmd) {
|
|||
return result;
|
||||
}
|
||||
|
||||
CommandResult Crafter::RunCommandWithTimeout(std::string_view, std::chrono::seconds) {
|
||||
throw std::runtime_error("RunCommandWithTimeout not yet implemented on Windows");
|
||||
}
|
||||
|
||||
std::string Crafter::BuildStdPcm(const Configuration& config, fs::path stdPcm) {
|
||||
std::string libcxx = std::getenv("LIBCXX_DIR");
|
||||
std::string stdcppm = std::format("{}\\modules\\c++\\v1\\std.cppm", libcxx);
|
||||
|
|
@ -99,13 +103,14 @@ std::string Crafter::GetBaseCommand(const Configuration& config) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
constexpr std::array<std::string_view, 7> kCrafterBuildModules = {
|
||||
constexpr std::array<std::string_view, 8> kCrafterBuildModules = {
|
||||
"Crafter.Build-Shader",
|
||||
"Crafter.Build-Platform",
|
||||
"Crafter.Build-Interface",
|
||||
"Crafter.Build-Implementation",
|
||||
"Crafter.Build-External",
|
||||
"Crafter.Build-Clang",
|
||||
"Crafter.Build-Test",
|
||||
"Crafter.Build",
|
||||
};
|
||||
|
||||
|
|
@ -121,7 +126,7 @@ namespace {
|
|||
}
|
||||
std::string cmd = std::format(
|
||||
"clang++ --target=x86_64-pc-windows-msvc -march=native -mtune=native "
|
||||
"-std=c++26 -O3 "
|
||||
"-std=c++26 -O3 -D CRAFTER_BUILD_DLL_IMPORT "
|
||||
"-nostdinc++ -nostdlib++ -isystem %LIBCXX_DIR%\\include\\c++\\v1 "
|
||||
"-Wno-reserved-identifier -Wno-reserved-module-identifier "
|
||||
"-fprebuilt-module-path={} "
|
||||
|
|
@ -178,9 +183,11 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
|
||||
std::string compileCmd = std::format(
|
||||
"clang++ --target=x86_64-pc-windows-msvc -march=native -mtune=native "
|
||||
"-std=c++26 -shared -O3 -Wno-return-type-c-linkage "
|
||||
"-std=c++26 -shared -O3 -Wno-return-type-c-linkage -fuse-ld=lld "
|
||||
"-D CRAFTER_BUILD_DLL_IMPORT "
|
||||
"-nostdinc++ -nostdlib++ -isystem %LIBCXX_DIR%\\include\\c++\\v1 "
|
||||
"-fprebuilt-module-path={} "
|
||||
"-Wl,/EXPORT:CrafterBuildProject "
|
||||
"{} {} -o {} -L %LIBCXX_DIR%\\lib -lc++",
|
||||
cacheDir.string(),
|
||||
absProject.string(), crafterBuildLib.string(), dllPath.string());
|
||||
|
|
@ -229,7 +236,7 @@ std::string Crafter::RunCommand(const std::string_view cmd) {
|
|||
|
||||
CommandResult Crafter::RunCommandChecked(std::string_view cmd) {
|
||||
std::array<char, 128> buffer;
|
||||
CommandResult result{0, ""};
|
||||
CommandResult result{};
|
||||
|
||||
std::string with = std::string(cmd) + " 2>&1";
|
||||
FILE* pipe = popen(with.c_str(), "r");
|
||||
|
|
@ -243,7 +250,47 @@ CommandResult Crafter::RunCommandChecked(std::string_view cmd) {
|
|||
if (WIFEXITED(status)) {
|
||||
result.exitCode = WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
result.exitCode = 128 + WTERMSIG(status);
|
||||
result.signal = WTERMSIG(status);
|
||||
result.exitCode = 128 + result.signal;
|
||||
result.crashed = true;
|
||||
} else {
|
||||
result.exitCode = -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CommandResult Crafter::RunCommandWithTimeout(std::string_view cmd, std::chrono::seconds timeout) {
|
||||
std::array<char, 128> buffer;
|
||||
CommandResult result{};
|
||||
|
||||
std::string wrapped = std::format(
|
||||
"timeout --kill-after=2 {} {} 2>&1",
|
||||
timeout.count(), cmd);
|
||||
|
||||
FILE* pipe = popen(wrapped.c_str(), "r");
|
||||
if (!pipe) throw std::runtime_error("popen() failed!");
|
||||
|
||||
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
|
||||
result.output += buffer.data();
|
||||
}
|
||||
|
||||
int status = pclose(pipe);
|
||||
if (WIFEXITED(status)) {
|
||||
int code = WEXITSTATUS(status);
|
||||
if (code == 124) {
|
||||
result.timedOut = true;
|
||||
result.exitCode = 124;
|
||||
} else if (code >= 128) {
|
||||
result.signal = code - 128;
|
||||
result.exitCode = code;
|
||||
result.crashed = true;
|
||||
} else {
|
||||
result.exitCode = code;
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
result.signal = WTERMSIG(status);
|
||||
result.exitCode = 128 + result.signal;
|
||||
result.crashed = true;
|
||||
} else {
|
||||
result.exitCode = -1;
|
||||
}
|
||||
|
|
@ -276,8 +323,14 @@ std::string Crafter::BuildStdPcm(const Configuration& config, fs::path stdPcm) {
|
|||
return "";
|
||||
}
|
||||
} else {
|
||||
if(!fs::exists(stdPcm) || fs::last_write_time(stdPcm) < fs::last_write_time("/usr/share/libc++/v1/std.cppm")) {
|
||||
return RunCommand(std::format("clang++ --target={} -std=c++26 -stdlib=libc++ -march={} -mtune={} -O3 -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile /usr/share/libc++/v1/std.cppm -o {}", config.target, config.march, config.mtune, stdPcm.string()));
|
||||
std::string stdCppm = config.sysroot.empty()
|
||||
? std::string("/usr/share/libc++/v1/std.cppm")
|
||||
: std::format("{}/usr/share/libc++/v1/std.cppm", config.sysroot);
|
||||
std::string sysrootFlag = config.sysroot.empty()
|
||||
? std::string()
|
||||
: std::format(" --sysroot={}", config.sysroot);
|
||||
if(!fs::exists(stdPcm) || fs::last_write_time(stdPcm) < fs::last_write_time(stdCppm)) {
|
||||
return RunCommand(std::format("clang++ --target={} -std=c++26 -stdlib=libc++{} -march={} -mtune={} -O3 -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile {} -o {}", config.target, sysrootFlag, config.march, config.mtune, stdCppm, stdPcm.string()));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
|
@ -307,13 +360,14 @@ std::string Crafter::GetBaseCommand(const Configuration& config) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
constexpr std::array<std::string_view, 7> kCrafterBuildModules = {
|
||||
constexpr std::array<std::string_view, 8> kCrafterBuildModules = {
|
||||
"Crafter.Build-Shader",
|
||||
"Crafter.Build-Platform",
|
||||
"Crafter.Build-Interface",
|
||||
"Crafter.Build-Implementation",
|
||||
"Crafter.Build-External",
|
||||
"Crafter.Build-Clang",
|
||||
"Crafter.Build-Test",
|
||||
"Crafter.Build",
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue