import std; import Crafter.Build; using namespace Crafter; namespace { int failures = 0; void Check(bool cond, std::string_view msg) { if (!cond) { std::println(std::cerr, "FAIL: {}", msg); ++failures; } } Configuration MakeBase() { Configuration cfg; cfg.path = "/tmp/variant-id-test"; cfg.name = "vt"; cfg.outputName = "vt"; cfg.target = "x86_64-pc-linux-gnu"; cfg.march = "native"; cfg.mtune = "native"; cfg.type = ConfigurationType::Executable; return cfg; } } // VariantId is the cache key for build outputs. Two Configurations that // differ only in something that affects codegen must produce different // VariantId / BuildDir / BinDir, otherwise their .o files collide. int main() { { // Baseline against itself: VariantId is deterministic. Configuration a = MakeBase(); Configuration b = MakeBase(); Check(a.VariantId() == b.VariantId(), "identical configs have identical VariantId"); Check(a.BuildDir() == b.BuildDir(), "identical configs have identical BuildDir"); } { // type differs -> VariantId differs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.type = ConfigurationType::LibraryStatic; Check(a.VariantId() != b.VariantId(), "type change perturbs VariantId"); } { // debug differs -> VariantId differs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.debug = true; Check(a.VariantId() != b.VariantId(), "debug change perturbs VariantId"); } { // sysroot differs -> VariantId differs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.sysroot = "/opt/sysroot"; Check(a.VariantId() != b.VariantId(), "sysroot change perturbs VariantId"); } { // defines differ -> VariantId differs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.defines.push_back({"FOO", "1"}); Check(a.VariantId() != b.VariantId(), "define added perturbs VariantId"); } { // Same define name, different value -> VariantId differs. Configuration a = MakeBase(); a.defines.push_back({"FOO", "1"}); Configuration b = MakeBase(); b.defines.push_back({"FOO", "2"}); Check(a.VariantId() != b.VariantId(), "define value change perturbs VariantId"); } { // compileFlags differ -> VariantId differs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.compileFlags.push_back("-fno-omit-frame-pointer"); Check(a.VariantId() != b.VariantId(), "compile flag added perturbs VariantId"); } { // target differs -> VariantId differs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.target = "aarch64-linux-gnu"; Check(a.VariantId() != b.VariantId(), "target change perturbs VariantId"); } { // march differs -> VariantId differs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.march = "x86-64-v3"; Check(a.VariantId() != b.VariantId(), "march change perturbs VariantId"); } { // PcmDir() differs between Executable (in BuildDir) and Library // (in BinDir) — Library PCMs land in the installable bin dir so // downstream consumers can find them. Configuration exe = MakeBase(); Configuration lib = MakeBase(); lib.type = ConfigurationType::LibraryStatic; Check(exe.PcmDir() == exe.BuildDir(), "Executable PcmDir == BuildDir"); Check(lib.PcmDir() == lib.BinDir(), "Library PcmDir == BinDir"); } { // VariantId is embedded in the path so distinct ids produce distinct dirs. Configuration a = MakeBase(); Configuration b = MakeBase(); b.debug = true; Check(a.BuildDir() != b.BuildDir(), "different VariantId yields different BuildDir"); Check(a.BinDir() != b.BinDir(), "different VariantId yields different BinDir"); } if (failures > 0) { std::println(std::cerr, "{} assertions failed", failures); return 1; } return 0; }