Crafter.Asset/project.cpp
2026-05-18 22:31:28 +02:00

92 lines
3.9 KiB
C++

import std;
import Crafter.Build;
namespace fs = std::filesystem;
using namespace Crafter;
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
std::vector<std::string> 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<fs::path> 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<fs::path, 4> ifaces = {
"interfaces/Crafter.Asset",
"interfaces/Crafter.Asset-Compression",
"interfaces/Crafter.Asset-Texture",
"interfaces/Crafter.Asset-Mesh",
};
if (cfg.type == ConfigurationType::Executable) {
std::array<fs::path, 2> impls = {
"implementations/Crafter.Asset-Compression",
"implementations/main",
};
cfg.GetInterfacesAndImplementations(ifaces, impls);
} else {
std::array<fs::path, 1> impls = {
"implementations/Crafter.Asset-Compression",
};
cfg.GetInterfacesAndImplementations(ifaces, impls);
}
return cfg;
}