2026-05-01 19:16:13 +02:00
|
|
|
/*
|
|
|
|
|
Crafter® Build
|
|
|
|
|
Copyright (C) 2026 Catcrafts®
|
|
|
|
|
Catcrafts.net
|
|
|
|
|
|
|
|
|
|
LGPL-3.0-only.
|
|
|
|
|
|
2026-05-02 21:08:51 +02:00
|
|
|
Verifies that when an executable consumes a library that registers shaders
|
|
|
|
|
or asset files, those runtime artifacts ship in the executable's bin dir
|
|
|
|
|
alongside the binary — not just in the lib's own bin dir, where the runtime
|
|
|
|
|
exe wouldn't find them. Covers a .spv (cfg.shaders), a flat asset
|
|
|
|
|
(cfg.files file), and a directory tree (cfg.files dir).
|
|
|
|
|
|
|
|
|
|
Also verifies cfg.buildFiles' include-path semantic: the consumer's own
|
|
|
|
|
shader compile resolves `#include "ui-shared.glsl"` against the lib's
|
|
|
|
|
buildFiles in-place from the dep's source tree (no copy), and the file is
|
|
|
|
|
NOT mirrored into any build/bin dir.
|
2026-05-01 19:16:13 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import std;
|
|
|
|
|
import Crafter.Build;
|
|
|
|
|
#include "../_shared/TestUtil.h"
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
using namespace TestUtil;
|
|
|
|
|
using namespace Crafter;
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
try {
|
|
|
|
|
fs::path src = fs::current_path() / "tests" / "ShaderDep" / "inner";
|
|
|
|
|
Configuration cfg = LoadFixture("ShaderDep", src);
|
|
|
|
|
|
|
|
|
|
auto br = BuildOnce(cfg);
|
|
|
|
|
if (!br.result.empty()) {
|
|
|
|
|
std::println(std::cerr, "build failed:\n{}", br.result);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs::path libSpv = cfg.dependencies[0]->BinDir() / "triangle.spv";
|
|
|
|
|
fs::path appSpv = cfg.BinDir() / "triangle.spv";
|
|
|
|
|
|
|
|
|
|
if (!fs::exists(libSpv)) {
|
|
|
|
|
std::println(std::cerr, "lib .spv missing at {}", libSpv.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (!fs::exists(appSpv)) {
|
|
|
|
|
std::println(std::cerr, "exe .spv missing at {}", appSpv.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ifstream f(appSpv, std::ios::binary);
|
|
|
|
|
unsigned char magic[4] = {};
|
|
|
|
|
f.read(reinterpret_cast<char*>(magic), 4);
|
|
|
|
|
if (magic[0] != 0x03 || magic[1] != 0x02 || magic[2] != 0x23 || magic[3] != 0x07) {
|
|
|
|
|
std::println(std::cerr,
|
|
|
|
|
"SPIR-V magic mismatch in exe-side copy: got {:#04x} {:#04x} {:#04x} {:#04x}",
|
|
|
|
|
magic[0], magic[1], magic[2], magic[3]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 21:08:51 +02:00
|
|
|
fs::path appAsset = cfg.BinDir() / "asset.txt";
|
|
|
|
|
if (!fs::exists(appAsset)) {
|
|
|
|
|
std::println(std::cerr, "exe-side asset.txt missing at {}", appAsset.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (ReadFile(appAsset) != "crafter-build asset\n") {
|
|
|
|
|
std::println(std::cerr, "asset.txt content mismatch at {}", appAsset.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs::path appNested = cfg.BinDir() / "data" / "nested.txt";
|
|
|
|
|
if (!fs::exists(appNested)) {
|
|
|
|
|
std::println(std::cerr, "exe-side data/nested.txt missing at {}", appNested.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (ReadFile(appNested) != "nested asset\n") {
|
|
|
|
|
std::println(std::cerr, "data/nested.txt content mismatch at {}", appNested.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The consumer shader includes a header from the lib's buildFiles.
|
|
|
|
|
// Successful build (above) means glslang resolved the include
|
|
|
|
|
// in-place from the dep's source tree — verify the resulting .spv
|
|
|
|
|
// and the SPIR-V magic, same as for the lib's shader.
|
|
|
|
|
fs::path consumerSpv = cfg.BinDir() / "consumer.spv";
|
|
|
|
|
if (!fs::exists(consumerSpv)) {
|
|
|
|
|
std::println(std::cerr, "consumer .spv missing at {}", consumerSpv.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
std::ifstream cf(consumerSpv, std::ios::binary);
|
|
|
|
|
unsigned char cmagic[4] = {};
|
|
|
|
|
cf.read(reinterpret_cast<char*>(cmagic), 4);
|
|
|
|
|
if (cmagic[0] != 0x03 || cmagic[1] != 0x02 || cmagic[2] != 0x23 || cmagic[3] != 0x07) {
|
|
|
|
|
std::println(std::cerr,
|
|
|
|
|
"SPIR-V magic mismatch in consumer.spv: got {:#04x} {:#04x} {:#04x} {:#04x}",
|
|
|
|
|
cmagic[0], cmagic[1], cmagic[2], cmagic[3]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// buildFiles must NOT be copied anywhere — they're read in place.
|
|
|
|
|
for (fs::path probe : {
|
|
|
|
|
cfg.BinDir() / "ui-shared.glsl",
|
|
|
|
|
cfg.BuildDir() / "ui-shared.glsl",
|
|
|
|
|
cfg.dependencies[0]->BinDir() / "ui-shared.glsl",
|
|
|
|
|
cfg.dependencies[0]->BuildDir() / "ui-shared.glsl",
|
|
|
|
|
}) {
|
|
|
|
|
if (fs::exists(probe)) {
|
|
|
|
|
std::println(std::cerr, "ui-shared.glsl unexpectedly copied to {}", probe.string());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-01 19:16:13 +02:00
|
|
|
return 0;
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
std::println(std::cerr, "test exception: {}", e.what());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|