Skip to content

Commit 8b25b25

Browse files
rtfeldmanclaude
andcommitted
Merge origin/main into types-coverage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2 parents b2b915d + 8e7aabc commit 8b25b25

115 files changed

Lines changed: 23639 additions & 2653 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.zig

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,13 +2009,59 @@ const FixArchivePaddingStep = struct {
20092009
defer file.close();
20102010

20112011
const stat = try file.stat();
2012-
const file_size = stat.size;
2012+
var file_size = stat.size;
20132013

20142014
// AR format requires archives to end on an even byte boundary.
20152015
// If file size is odd, append a newline padding byte.
2016+
// This fixes Zig bug https://codeberg.org/ziglang/zig/issues/30572
2017+
// where Zig's archiver doesn't add required padding after odd-sized members.
20162018
if (file_size % 2 == 1) {
20172019
try file.seekTo(file_size);
20182020
try file.writeAll("\n");
2021+
file_size += 1;
2022+
}
2023+
2024+
// Parse the archive to verify member offsets are valid.
2025+
// This catches cases where lld would fail with "truncated or malformed archive".
2026+
try file.seekTo(0);
2027+
var header_buf: [8]u8 = undefined;
2028+
_ = try file.read(&header_buf);
2029+
if (!std.mem.eql(u8, &header_buf, "!<arch>\n")) {
2030+
std.debug.print("Warning: Invalid archive magic in {s}\n", .{self.archive_path});
2031+
return;
2032+
}
2033+
2034+
var offset: u64 = 8; // After magic
2035+
while (offset + 60 <= file_size) {
2036+
try file.seekTo(offset + 48); // Seek to size field (offset 48 within 60-byte header)
2037+
var size_buf: [10]u8 = undefined;
2038+
_ = try file.read(&size_buf);
2039+
2040+
// Parse size (ASCII decimal, space-padded)
2041+
var size: u64 = 0;
2042+
for (size_buf) |c| {
2043+
if (c >= '0' and c <= '9') {
2044+
size = size * 10 + (c - '0');
2045+
} else break;
2046+
}
2047+
2048+
// Move to next member (header + content + padding if odd)
2049+
offset += 60 + size;
2050+
if (size % 2 == 1) {
2051+
offset += 1; // Padding byte expected
2052+
}
2053+
2054+
// If we're exactly at EOF, archive is valid
2055+
if (offset == file_size) break;
2056+
2057+
// If next offset would be past EOF, we have a problem - add missing padding
2058+
if (offset > file_size) {
2059+
const missing = offset - file_size;
2060+
try file.seekTo(file_size);
2061+
const padding = "\n\n"; // At most 1 byte needed, but be safe
2062+
try file.writeAll(padding[0..@min(missing, 2)]);
2063+
break;
2064+
}
20192065
}
20202066
}
20212067
};
@@ -2415,6 +2461,7 @@ pub fn build(b: *std.Build) void {
24152461
roc_modules.repl.addImport("compiled_builtins", compiled_builtins_module);
24162462
roc_modules.compile.addImport("compiled_builtins", compiled_builtins_module);
24172463
roc_modules.eval.addImport("compiled_builtins", compiled_builtins_module);
2464+
roc_modules.lsp.addImport("compiled_builtins", compiled_builtins_module);
24182465

24192466
// Setup test platform host libraries
24202467
setupTestPlatforms(b, target, optimize, roc_modules, test_platforms_step, strip, omit_frame_pointer);
@@ -2727,8 +2774,8 @@ pub fn build(b: *std.Build) void {
27272774
const module_tests_result = roc_modules.createModuleTests(b, target, optimize, zstd, test_filters);
27282775
const tests_summary = TestsSummaryStep.create(b, test_filters, module_tests_result.forced_passes);
27292776
for (module_tests_result.tests) |module_test| {
2730-
// Add compiled builtins to check, repl, eval, and compile module tests
2731-
if (std.mem.eql(u8, module_test.test_step.name, "check") or std.mem.eql(u8, module_test.test_step.name, "repl") or std.mem.eql(u8, module_test.test_step.name, "eval") or std.mem.eql(u8, module_test.test_step.name, "compile")) {
2777+
// Add compiled builtins to check, repl, eval, compile, and lsp module tests
2778+
if (std.mem.eql(u8, module_test.test_step.name, "check") or std.mem.eql(u8, module_test.test_step.name, "repl") or std.mem.eql(u8, module_test.test_step.name, "eval") or std.mem.eql(u8, module_test.test_step.name, "compile") or std.mem.eql(u8, module_test.test_step.name, "lsp")) {
27322779
module_test.test_step.root_module.addImport("compiled_builtins", compiled_builtins_module);
27332780
module_test.test_step.step.dependOn(&write_compiled_builtins.step);
27342781
}
@@ -3089,17 +3136,39 @@ pub fn build(b: *std.Build) void {
30893136
// Copy the fx test platform host library to the source directory
30903137
const copy_test_fx_host = b.addUpdateSourceFiles();
30913138
const test_fx_host_filename = if (target.result.os.tag == .windows) "host.lib" else "libhost.a";
3092-
copy_test_fx_host.addCopyFileToSource(test_platform_fx_host_lib.getEmittedBin(), b.pathJoin(&.{ "test/fx/platform", test_fx_host_filename }));
3093-
b.getInstallStep().dependOn(&copy_test_fx_host.step);
3139+
const fx_host_main_path = b.pathJoin(&.{ "test/fx/platform", test_fx_host_filename });
3140+
copy_test_fx_host.addCopyFileToSource(test_platform_fx_host_lib.getEmittedBin(), fx_host_main_path);
30943141

30953142
// Also copy to the target-specific directory so findHostLibrary finds it
3096-
if (fx_host_target_dir) |target_dir| {
3143+
const fx_host_target_path = if (fx_host_target_dir) |target_dir|
3144+
b.pathJoin(&.{ "test/fx/platform/targets", target_dir, test_fx_host_filename })
3145+
else
3146+
null;
3147+
if (fx_host_target_path) |target_path| {
30973148
copy_test_fx_host.addCopyFileToSource(
30983149
test_platform_fx_host_lib.getEmittedBin(),
3099-
b.pathJoin(&.{ "test/fx/platform/targets", target_dir, test_fx_host_filename }),
3150+
target_path,
31003151
);
31013152
}
31023153

3154+
// Apply archive padding fix for non-Windows targets (Zig bug workaround)
3155+
// The final_fx_host_step is what tests should depend on to ensure the archive is ready
3156+
const final_fx_host_step: *Step = if (target.result.os.tag != .windows) blk: {
3157+
const fix_main = FixArchivePaddingStep.create(b, fx_host_main_path);
3158+
fix_main.step.dependOn(&copy_test_fx_host.step);
3159+
3160+
if (fx_host_target_path) |target_path| {
3161+
const fix_target = FixArchivePaddingStep.create(b, target_path);
3162+
fix_target.step.dependOn(&copy_test_fx_host.step);
3163+
// Make fix_target depend on fix_main so both complete
3164+
fix_target.step.dependOn(&fix_main.step);
3165+
break :blk &fix_target.step;
3166+
}
3167+
break :blk &fix_main.step;
3168+
} else &copy_test_fx_host.step;
3169+
3170+
b.getInstallStep().dependOn(final_fx_host_step);
3171+
31033172
const fx_platform_test = b.addTest(.{
31043173
.name = "fx_platform_test",
31053174
.root_module = b.createModule(.{
@@ -3114,8 +3183,8 @@ pub fn build(b: *std.Build) void {
31143183
if (run_args.len != 0) {
31153184
run_fx_platform_test.addArgs(run_args);
31163185
}
3117-
// Ensure host library is copied before running the test
3118-
run_fx_platform_test.step.dependOn(&copy_test_fx_host.step);
3186+
// Ensure host library is copied AND fixed before running the test
3187+
run_fx_platform_test.step.dependOn(final_fx_host_step);
31193188
// Ensure roc binary is built before running the test (tests invoke roc CLI)
31203189
run_fx_platform_test.step.dependOn(roc_step);
31213190
tests_summary.addRun(&run_fx_platform_test.step);

0 commit comments

Comments
 (0)