import std; import Crafter.Build; namespace fs = std::filesystem; using namespace Crafter; extern "C" Configuration CrafterBuildProject(std::span args) { std::vector depArgs(args.begin(), args.end()); bool useLocal = false; for (std::string_view a : args) { if (a == "--local") { useLocal = true; break; } } Configuration* math = useLocal ? LocalProject({ .projectFile = "../Crafter.Math/project.cpp", .args = depArgs, }) : GitProject({ .source = { .url = "https://forgejo.catcrafts.net/Catcrafts/Crafter.Math.git" }, .args = depArgs, }); Configuration cfg; cfg.path = "./"; cfg.name = "Crafter.Asset"; // Default to library so consumers (Crafter.Graphics, examples) link against // libCrafter.Asset.a — the Compression module's non-template entry points // need to be in a real archive, not just PCM-inline. `--exe` (via the // example's main.cpp) flips us to Executable to produce crafter-asset. cfg.type = ConfigurationType::LibraryStatic; ApplyStandardArgs(cfg, args); bool wantExe = false; for (std::string_view a : args) { if (a == "--exe") { wantExe = true; break; } } if (wantExe) cfg.type = ConfigurationType::Executable; cfg.outputName = (cfg.type == ConfigurationType::Executable) ? "crafter-asset" : "Crafter.Asset"; cfg.dependencies = { math }; // Vendored GDeflate (Apache-2.0, Microsoft DirectStorage reference) + // libdeflate (MIT, NVIDIA fork). The C++ wrappers live inline in the // Compression module impl; libdeflate's .c sources are compiled here. // Absolute path: when Crafter.Asset is consumed as a dep, the build runs // clang from the consumer's cwd, and a relative -I would silently fall // through to /usr/include and pick up a system libdeflate of a different // ABI (1.25 dropped LIBDEFLATEEXPORT) instead of the vendored 1.8 fork. cfg.compileFlags.push_back(std::format("-I{}", fs::absolute("lib/gdeflate/libdeflate").string())); // libdeflate's lib/x86/ subdir is x86-specific CPU-feature detection // (CPUID + AVX checks); compiling it for wasm32 fails on the inline // assembly and missing intrinsics. wasm32 builds skip it; libdeflate's // dispatcher falls through to the generic C path. const bool isWasm = cfg.target.find("wasm") != std::string::npos; std::vector libdeflateSources = { "lib/gdeflate/libdeflate/lib/adler32", "lib/gdeflate/libdeflate/lib/crc32", "lib/gdeflate/libdeflate/lib/deflate_compress", "lib/gdeflate/libdeflate/lib/deflate_decompress", "lib/gdeflate/libdeflate/lib/gdeflate_compress", "lib/gdeflate/libdeflate/lib/gdeflate_decompress", "lib/gdeflate/libdeflate/lib/gzip_compress", "lib/gdeflate/libdeflate/lib/gzip_decompress", "lib/gdeflate/libdeflate/lib/utils", "lib/gdeflate/libdeflate/lib/zlib_compress", "lib/gdeflate/libdeflate/lib/zlib_decompress", }; if (!isWasm) { libdeflateSources.emplace_back("lib/gdeflate/libdeflate/lib/x86/cpu_features"); } for (const fs::path& p : libdeflateSources) cfg.cFiles.push_back(p); std::array ifaces = { "interfaces/Crafter.Asset", "interfaces/Crafter.Asset-Compression", "interfaces/Crafter.Asset-Texture", "interfaces/Crafter.Asset-Mesh", }; if (cfg.type == ConfigurationType::Executable) { std::array impls = { "implementations/Crafter.Asset-Compression", "implementations/main", }; cfg.GetInterfacesAndImplementations(ifaces, impls); } else { std::array impls = { "implementations/Crafter.Asset-Compression", }; cfg.GetInterfacesAndImplementations(ifaces, impls); } return cfg; }