Files
game-engine/deps/enkiTS/build.zig
T
f88f9f8ffa [M1-01] Initialize Monorepo, CMake C++20 Build, and .slnx Workspace (#22)
* [M1-01] Initialize monorepo: CMake C++20 build, .slnx workspace, vendored deps, CI

- Root CMakeLists.txt (C++20 strict, PIC) + cmake/EngineHotFlags
  (-Wall/-Werror, -mavx2 x86-64 only, -fno-exceptions/-fno-rtti hot path)
- CMakePresets.json: linux/macos/windows debug+release, ci-* (WERROR)
- native/: engine_core shared lib (version API), core/ecs hot OBJECT
  libs, renderer/physics/audio/bridge stubs with owners
- native/tests: engine_core_smoke CTest (version handshake)
- deps/: flecs v4.1.6 + enkiTS pinned, README with re-vendor recipe
- Engine.slnx + Directory.Build.props (net10.0, AllowUnsafeBlocks,
  TieredPGO, zero-warn) + Bindings/Runtime/Tests/abi_codegen stubs
- .github/workflows/ci.yml: native (CMake+CTest) + managed
  (dotnet build+run) on ubuntu/macos/windows
- Verified: configure+build+ctest green on linux-debug (Clang),
  AVX2/no-exceptions flags confirmed in compile_commands.json

* fix(ci): AbiCodegen assembly name (CA1707), Windows Ninja+MSVC presets

* fix(ci): fail-fast windows test (5min step timeout, 60s test timeout, verbose)

* fix(ci): isolate windows hang — bootstrap control test + unbuffered smoke output

* fix(ci): copy runtime DLLs next to windows test binaries

* fix(ci): only copy DLLs for linked test target

---------

Co-authored-by: hermes-agent <hermes-agent@local>
Co-authored-by: hermes <[email protected]>
2026-10-28 00:58:04 -04:00

241 lines
6.9 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
pub const Options = struct {
pub const max_task_priorities = 5;
shared: bool,
build_examples: bool,
task_priorities: u32,
const defaults = Options{
.shared = false,
.build_examples = false,
.task_priorities = 0,
};
pub fn getOptions(b: *std.Build) !Options {
const task_priorities = b.option(u32, "task_priorities", "Number of task priorities, 1-5, 0 for defined by defaults in source") orelse defaults.task_priorities;
if (task_priorities > max_task_priorities) {
std.log.err("task_priorities must be in range 0-{d}", .{max_task_priorities});
return error.InvalidTaskPriorities;
}
return .{
.shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared,
.build_examples = b.option(bool, "build_examples", "Build examples") orelse defaults.build_examples,
.task_priorities = task_priorities,
};
}
pub fn applyTaskPriorities(options: Options, b: *std.Build, compile: *std.Build.Step.Compile) !void {
if (options.task_priorities > 0) {
const task_priorities_str = try std.fmt.allocPrint(b.allocator, "{d}", .{options.task_priorities});
// leak task_priorities_str as we dont really care in build scripts and lifetime needs to be longer ...
compile.root_module.addCMacro("ENKITS_TASK_PRIORITIES_NUM", task_priorities_str);
}
}
};
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const options = try Options.getOptions(b);
const lib = try compileEnkiTS(b, target, optimize, options);
b.installArtifact(lib);
if (options.build_examples) {
try buildExamples(b, target, optimize, lib, options);
}
}
fn compileEnkiTS(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
const module = b.addModule("enki_ts", .{
.target = target,
.optimize = optimize,
.link_libcpp = true,
});
const linkage: std.builtin.LinkMode = if (options.shared) .dynamic else .static;
const enki_ts = b.addLibrary(.{
.root_module = module,
.name = "enki_ts",
.linkage = linkage,
});
const cpp_source_files = &[_][]const u8{
"src/LockLessMultiReadPipe.h",
"src/TaskScheduler_c.h",
"src/TaskScheduler_c.cpp",
"src/TaskScheduler.cpp",
"src/TaskScheduler.h",
};
enki_ts.installHeader(b.path("src/TaskScheduler_c.h"), "TaskScheduler_c.h");
enki_ts.installHeader(b.path("src/TaskScheduler.h"), "TaskScheduler.h");
var flags_arr = std.ArrayList([]const u8).empty;
defer flags_arr.deinit(b.allocator);
const target_os = target.query.os_tag orelse builtin.target.os.tag;
if (target_os == .macos) {
try flags_arr.append(b.allocator, "-stdlib=libc++");
} else {
try flags_arr.append(b.allocator, "-std=c++11");
}
if (target_os == .linux) {
try flags_arr.append(b.allocator, "-pthread");
}
if (options.shared) {
try flags_arr.appendSlice(b.allocator, &[_][]const u8{
"-fPIC",
"-DBUILD_LIBTYPE_SHARED",
});
enki_ts.root_module.addCMacro("ENKITS_BUILD_DLL", "1");
enki_ts.root_module.addCMacro("ENKITS_DLL", "1");
}
try options.applyTaskPriorities(b, enki_ts);
enki_ts.root_module.addCSourceFiles(.{
.files = cpp_source_files,
.flags = flags_arr.items,
.language = .cpp,
});
return enki_ts;
}
fn buildExamples(
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
enki_ts: *std.Build.Step.Compile,
options: Options,
) !void {
inline for (&[_][]const u8{
"CompletionAction",
"CustomAllocator",
"Dependencies",
"ExternalTaskThread",
"LambdaTask",
"ParallelSum",
"PinnedTask",
"TaskOverhead",
"TaskThroughput",
"TestAll",
"TestWaitforTask",
"WaitForNewPinnedTasks",
}) |cpp_example_name| {
try buildCppExample(b, target, optimize, enki_ts, options, cpp_example_name);
}
inline for (&[_][]const u8{
"CompletionAction_c",
"CustomAllocator_c",
"Dependencies_c",
"ExternalTaskThread_c",
"ParallelSum_c",
"PinnedTask_c",
"WaitForNewPinnedTasks_c",
}) |c_example_name| {
try buildCExample(b, target, optimize, enki_ts, options, c_example_name);
}
if (options.task_priorities > 0) {
try buildCppExample(b, target, optimize, enki_ts, options, "Priorities");
try buildCExample(b, target, optimize, enki_ts, options, "Priorities_c");
}
}
fn buildCppExample(
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
enki_ts: *std.Build.Step.Compile,
options: Options,
comptime example_name: []const u8,
) !void {
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = example_name,
.root_module = exe_mod,
});
const example_path = "example/" ++ example_name ++ ".cpp";
const source_files = [_][]const u8{example_path};
exe.root_module.addCSourceFiles(.{
.files = &source_files,
.flags = &[_][]const u8{
"-std=c++11",
},
.language = .cpp,
});
try options.applyTaskPriorities(b, exe);
// link with lib
exe.root_module.linkLibrary(enki_ts);
b.installArtifact(exe);
addExampleRunStep(b, exe, example_name);
}
fn buildCExample(
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
enki_ts: *std.Build.Step.Compile,
options: Options,
comptime example_name: []const u8,
) !void {
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = example_name,
.root_module = exe_mod,
});
const example_path = "example/" ++ example_name ++ ".c";
const source_files = [_][]const u8{example_path};
exe.root_module.addCSourceFiles(.{
.files = &source_files,
.flags = &[_][]const u8{},
.language = .c,
});
try options.applyTaskPriorities(b, exe);
// link with lib
exe.root_module.linkLibrary(enki_ts);
b.installArtifact(exe);
addExampleRunStep(b, exe, example_name);
}
fn addExampleRunStep(
b: *std.Build,
exe: *std.Build.Step.Compile,
comptime example_name: []const u8,
) void {
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run" ++ "-" ++ example_name, "Run the " ++ example_name ++ " example");
run_step.dependOn(&run_cmd.step);
}