fix: AOT build cache disabled for programs with top-level #run

The JIT path already guards its object cache with hasTopLevelRun (the
#run interp executes during codegen; a cache hit skips codegen and
loses its effects). The build path had no such guard, so a second
'sx build --cache' of any app with a '#run configure_build()' block
linked WITHOUT the build.sx config — no link flags (m3te: undefined
SDL3 symbols), and on a binary-level hit the output path and bundling
would have been wrong too. Both cache levels and both save sites now
share the guard; #run-free programs keep full cache behavior
(verified: second build hits the binary cache in <1ms; m3te's
build/--cache/build sequence now links and bundles both times).
This commit is contained in:
agra
2026-06-12 19:11:18 +03:00
parent 9fb7290861
commit f6b0029249

View File

@@ -577,14 +577,19 @@ fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []cons
const obj_path = try std.fmt.allocPrintSentinel(allocator, "{s}/main.o", .{tmp_dir}, 0);
// Cache: compute key and check for cached binary/.o
// Cache: compute key and check for cached binary/.o.
// Disabled for programs with top-level #run (same guard as the JIT
// path): the #run interp runs during codegen, and skipping codegen
// loses its effects — build config (link flags, frameworks, output
// path, bundling) and print side effects alike.
const use_cache = enable_cache and !hasTopLevelRun(root);
const key = computeCacheKey(source, &comp.import_sources, target_config);
const cache_obj = try cachePath(allocator, key, "o");
const cache_bin = try cachePath(allocator, key, "bin");
// Level 1: Try cached binary (skip everything — no codegen, no link).
// Skipped under --emit-obj, which needs the freshly-emitted object kept.
if (enable_cache and !target_config.emit_obj) bin_cache: {
if (use_cache and !target_config.emit_obj) bin_cache: {
std.Io.Dir.copyFile(.cwd(), cache_bin, .cwd(), output_path, io, .{}) catch break :bin_cache;
timer.record("cache");
return;
@@ -592,7 +597,7 @@ fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []cons
// Level 2: Try cached .o (skip codegen+emit, still need link)
const used_obj_cache = blk: {
if (!enable_cache) break :blk false;
if (!use_cache) break :blk false;
std.Io.Dir.copyFile(.cwd(), cache_obj, .cwd(), obj_path, io, .{}) catch break :blk false;
break :blk true;
};
@@ -614,7 +619,7 @@ fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []cons
timer.record("emit");
// Save .o to cache
if (enable_cache) {
if (use_cache) {
std.Io.Dir.copyFile(.cwd(), obj_path, .cwd(), cache_obj, io, .{ .make_path = true }) catch {};
}
}
@@ -783,7 +788,7 @@ fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []cons
}
// Save linked binary to cache
if (enable_cache) {
if (use_cache) {
std.Io.Dir.copyFile(.cwd(), output_path, .cwd(), cache_bin, io, .{ .make_path = true }) catch {};
}