import std; import Crafter.Build; namespace fs = std::filesystem; using namespace Crafter; extern "C" Configuration CrafterBuildProject(std::span args) { bool debug = false; for (std::string_view arg : args) { if (arg == "--debug") debug = true; } static auto crafterBuildLib = std::make_unique(); crafterBuildLib->path = "./"; crafterBuildLib->name = "crafter.build-lib"; crafterBuildLib->outputName = "crafter-build"; crafterBuildLib->target = "x86_64-pc-linux-gnu"; crafterBuildLib->type = ConfigurationType::LibraryStatic; crafterBuildLib->debug = debug; { std::array interfaces = { "interfaces/Crafter.Build", "interfaces/Crafter.Build-Shader", "interfaces/Crafter.Build-Platform", "interfaces/Crafter.Build-Interface", "interfaces/Crafter.Build-Implementation", "interfaces/Crafter.Build-External", "interfaces/Crafter.Build-Clang", "interfaces/Crafter.Build-Test", }; std::array implementations = { "implementations/Crafter.Build-Shader", "implementations/Crafter.Build-Platform", "implementations/Crafter.Build-Interface", "implementations/Crafter.Build-Implementation", "implementations/Crafter.Build-External", "implementations/Crafter.Build-Clang", "implementations/Crafter.Build-Test", }; crafterBuildLib->GetInterfacesAndImplementations(interfaces, implementations); } ExternalDependency& glslang = crafterBuildLib->externalDependencies.emplace_back(); glslang.name = "glslang"; glslang.source.url = "https://github.com/KhronosGroup/glslang.git"; glslang.source.branch = "main"; glslang.builder = ExternalBuilder::CMake; glslang.options = { "-DENABLE_OPT=OFF" }; glslang.includeDirs = { "" }; glslang.libs = { "SPIRV", "GenericCodeGen", "glslang", "OSDependent", "MachineIndependent", "glslang-default-resource-limits" }; Configuration cfg; cfg.path = "./"; cfg.name = "crafter.build-exe"; cfg.outputName = "crafter-build"; cfg.target = "x86_64-pc-linux-gnu"; cfg.type = ConfigurationType::Executable; cfg.debug = debug; cfg.dependencies = { crafterBuildLib.get() }; { std::array interfaces = {}; std::array implementations = { "implementations/main" }; cfg.GetInterfacesAndImplementations(interfaces, implementations); } cfg.linkFlags.push_back("-Wl,--export-dynamic"); cfg.linkFlags.push_back("-ldl"); // ----- Single-driver, multi-target tests (each appears once per (target, runner)). ----- // Lifetime holders for per-target lib Configurations referenced by Tests. static std::vector> testLibPool; struct TargetRunner { std::string target; TestRunner runner; std::vector extraLinkFlags; }; std::vector targets = { { "x86_64-pc-linux-gnu", TestRunner::Local(), {} }, { "x86_64-w64-mingw32", TestRunner::SshWin("winvm", "C:/temp/crafter-tests"), {"-lstdc++exp"} }, }; auto addPerTarget = [&](std::string name, auto buildOne) { for (auto& tr : targets) { Test t; t.config.name = name; t.config.target = tr.target; t.config.type = ConfigurationType::Executable; t.config.linkFlags.push_back("-fuse-ld=lld"); for (auto& f : tr.extraLinkFlags) t.config.linkFlags.push_back(f); buildOne(t, tr.target); t.runner = tr.runner; cfg.tests.push_back(std::move(t)); } }; addPerTarget("HelloWorld", [](Test& t, std::string_view) { t.config.path = "tests/fixtures/hello-world/"; t.config.outputName = "hello"; std::array ifaces = {}; std::array impls = { "main" }; t.config.GetInterfacesAndImplementations(ifaces, impls); }); addPerTarget("WithModule", [](Test& t, std::string_view) { t.config.path = "tests/fixtures/with-module/"; t.config.outputName = "hello-mod"; std::array ifaces = { "interfaces/Greeter" }; std::array impls = { "main" }; t.config.GetInterfacesAndImplementations(ifaces, impls); }); addPerTarget("Defines", [](Test& t, std::string_view) { t.config.path = "tests/fixtures/defines/"; t.config.outputName = "defines-app"; std::array ifaces = {}; std::array impls = { "main" }; t.config.GetInterfacesAndImplementations(ifaces, impls); t.config.defines.push_back({"CRAFTER_TEST_FOO", "42"}); }); addPerTarget("CrossProjectModule", [&](Test& t, std::string_view target) { auto fooLib = std::make_unique(); fooLib->path = "tests/fixtures/cross-project/lib/"; fooLib->name = std::format("Foo-cross-project-{}", target); fooLib->outputName = "Foo"; fooLib->target = std::string(target); fooLib->type = ConfigurationType::LibraryStatic; std::array libIfaces = { "Foo" }; std::array libImpls = {}; fooLib->GetInterfacesAndImplementations(libIfaces, libImpls); Configuration* fooLibPtr = fooLib.get(); testLibPool.push_back(std::move(fooLib)); t.config.path = "tests/fixtures/cross-project/"; t.config.outputName = "cross-app"; t.config.dependencies = { fooLibPtr }; std::array mainIfaces = {}; std::array mainImpls = { "main" }; t.config.GetInterfacesAndImplementations(mainIfaces, mainImpls); }); auto makeDiamondLib = [&](std::string_view dir, std::string_view modName, std::string_view target, std::span deps) { auto lib = std::make_unique(); lib->path = std::format("tests/fixtures/diamond/{}/", dir); lib->name = std::format("{}-diamond-{}", modName, target); lib->outputName = std::string(modName); lib->target = std::string(target); lib->type = ConfigurationType::LibraryStatic; lib->dependencies.assign(deps.begin(), deps.end()); std::array ifaces = { fs::path(modName) }; std::array impls = {}; lib->GetInterfacesAndImplementations(ifaces, impls); return lib; }; addPerTarget("Diamond", [&](Test& t, std::string_view target) { auto X = makeDiamondLib("X", "X", target, {}); Configuration* xDeps[] = { X.get() }; auto B = makeDiamondLib("B", "B", target, xDeps); auto C = makeDiamondLib("C", "C", target, xDeps); Configuration* mainDeps[] = { B.get(), C.get() }; t.config.path = "tests/fixtures/diamond/"; t.config.outputName = "diamond-app"; t.config.dependencies.assign(mainDeps, mainDeps + 2); std::array ifaces = {}; std::array impls = { "main" }; t.config.GetInterfacesAndImplementations(ifaces, impls); testLibPool.push_back(std::move(X)); testLibPool.push_back(std::move(B)); testLibPool.push_back(std::move(C)); }); // ----- Outer-driver tests (still need their own driver source for multi-step // logic or meta-runner behavior). ----- auto addOuterDriverTest = [&](std::string name) { Test t; t.config.path = "./"; t.config.name = name; t.config.outputName = name; t.config.target = "x86_64-pc-linux-gnu"; t.config.type = ConfigurationType::Executable; std::array empty = {}; std::array impls = { fs::path("tests") / name }; t.config.GetInterfacesAndImplementations(empty, impls); cfg.tests.push_back(std::move(t)); }; addOuterDriverTest("Incremental"); addOuterDriverTest("BuildError"); addOuterDriverTest("Libraries"); addOuterDriverTest("RunnerClassification"); addOuterDriverTest("QemuUser"); addOuterDriverTest("SshRunner"); addOuterDriverTest("CrossArchAarch64"); addOuterDriverTest("WindowsViaSsh"); return cfg; }