diff --git a/test/link.zig b/test/link.zig index 93ccb3c640..49d06b80c9 100644 --- a/test/link.zig +++ b/test/link.zig @@ -131,10 +131,6 @@ pub const cases = [_]Case{ .build_root = "test/link/macho/entry_in_archive", .import = @import("link/macho/entry_in_archive/build.zig"), }, - .{ - .build_root = "test/link/macho/entry_in_dylib", - .import = @import("link/macho/entry_in_dylib/build.zig"), - }, .{ .build_root = "test/link/macho/headerpad", .import = @import("link/macho/headerpad/build.zig"), diff --git a/test/link/macho.zig b/test/link/macho.zig index fc40ebec33..d52ffc98d1 100644 --- a/test/link/macho.zig +++ b/test/link/macho.zig @@ -4,13 +4,70 @@ pub fn testAll(b: *std.Build) *Step { const macho_step = b.step("test-macho", "Run MachO tests"); - macho_step.dependOn(testSectionBoundarySymbols(b, .{ - .target = b.resolveTargetQuery(.{ .os_tag = .macos }), - })); + const default_target = b.resolveTargetQuery(.{ + .os_tag = .macos, + }); + + macho_step.dependOn(testEntryPointDylib(b, .{ .target = default_target })); + macho_step.dependOn(testSectionBoundarySymbols(b, .{ .target = default_target })); return macho_step; } +fn testEntryPointDylib(b: *std.Build, opts: Options) *Step { + const test_step = addTestStep(b, "macho-entry-point-dylib", opts); + + const dylib = addSharedLibrary(b, opts, .{ .name = "liba.dylib" }); + addCSourceBytes(dylib, + \\extern int my_main(); + \\int bootstrap() { + \\ return my_main(); + \\} + , &.{}); + dylib.linker_allow_shlib_undefined = true; + + const exe = addExecutable(b, opts, .{ .name = "main" }); + addCSourceBytes(dylib, + \\#include + \\int my_main() { + \\ fprintf(stdout, "Hello!\n"); + \\ return 0; + \\} + , &.{}); + exe.linkLibrary(dylib); + exe.entry = .{ .symbol_name = "_bootstrap" }; + exe.forceUndefinedSymbol("_my_main"); + + const check = exe.checkObject(); + check.checkInHeaders(); + check.checkExact("segname __TEXT"); + check.checkExtract("vmaddr {text_vmaddr}"); + check.checkInHeaders(); + check.checkExact("sectname __stubs"); + check.checkExtract("addr {stubs_vmaddr}"); + check.checkInHeaders(); + check.checkExact("sectname __stubs"); + check.checkExtract("size {stubs_vmsize}"); + check.checkInHeaders(); + check.checkExact("cmd MAIN"); + check.checkExtract("entryoff {entryoff}"); + check.checkComputeCompare("text_vmaddr entryoff +", .{ + .op = .gte, + .value = .{ .variable = "stubs_vmaddr" }, // The entrypoint should be a synthetic stub + }); + check.checkComputeCompare("text_vmaddr entryoff + stubs_vmaddr -", .{ + .op = .lt, + .value = .{ .variable = "stubs_vmsize" }, // The entrypoint should be a synthetic stub + }); + test_step.dependOn(&check.step); + + const run = addRunArtifact(exe); + run.expectStdOutEqual("Hello!\n"); + test_step.dependOn(&run.step); + + return test_step; +} + fn testSectionBoundarySymbols(b: *std.Build, opts: Options) *Step { const test_step = addTestStep(b, "macho-section-boundary-symbols", opts); @@ -95,8 +152,11 @@ fn addTestStep(b: *std.Build, comptime prefix: []const u8, opts: Options) *Step return link.addTestStep(b, "macho-" ++ prefix, opts); } +const addCSourceBytes = link.addCSourceBytes; +const addRunArtifact = link.addRunArtifact; const addObject = link.addObject; const addExecutable = link.addExecutable; +const addSharedLibrary = link.addSharedLibrary; const expectLinkErrors = link.expectLinkErrors; const link = @import("link.zig"); const std = @import("std"); diff --git a/test/link/macho/entry_in_dylib/bootstrap.c b/test/link/macho/entry_in_dylib/bootstrap.c deleted file mode 100644 index 6e9a2b830c..0000000000 --- a/test/link/macho/entry_in_dylib/bootstrap.c +++ /dev/null @@ -1,5 +0,0 @@ -extern int my_main(); - -int bootstrap() { - return my_main(); -} diff --git a/test/link/macho/entry_in_dylib/build.zig b/test/link/macho/entry_in_dylib/build.zig deleted file mode 100644 index 7827552bcf..0000000000 --- a/test/link/macho/entry_in_dylib/build.zig +++ /dev/null @@ -1,59 +0,0 @@ -const std = @import("std"); - -pub const requires_symlinks = true; - -pub fn build(b: *std.Build) void { - const test_step = b.step("test", "Test it"); - b.default_step = test_step; - - add(b, test_step, .Debug); - add(b, test_step, .ReleaseFast); - add(b, test_step, .ReleaseSmall); - add(b, test_step, .ReleaseSafe); -} - -fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void { - const lib = b.addSharedLibrary(.{ - .name = "bootstrap", - .optimize = optimize, - .target = b.resolveTargetQuery(.{ .os_tag = .macos }), - }); - lib.addCSourceFile(.{ .file = .{ .path = "bootstrap.c" }, .flags = &.{} }); - lib.linkLibC(); - lib.linker_allow_shlib_undefined = true; - - const exe = b.addExecutable(.{ - .name = "main", - .optimize = optimize, - .target = b.resolveTargetQuery(.{ .os_tag = .macos }), - }); - exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); - exe.linkLibrary(lib); - exe.linkLibC(); - exe.entry = .{ .symbol_name = "_bootstrap" }; - exe.forceUndefinedSymbol("_my_main"); - - const check_exe = exe.checkObject(); - check_exe.checkInHeaders(); - check_exe.checkExact("segname __TEXT"); - check_exe.checkExtract("vmaddr {text_vmaddr}"); - - check_exe.checkInHeaders(); - check_exe.checkExact("sectname __stubs"); - check_exe.checkExtract("addr {stubs_vmaddr}"); - - check_exe.checkInHeaders(); - check_exe.checkExact("cmd MAIN"); - check_exe.checkExtract("entryoff {entryoff}"); - - check_exe.checkComputeCompare("text_vmaddr entryoff +", .{ - .op = .eq, - .value = .{ .variable = "stubs_vmaddr" }, // The entrypoint should be a synthetic stub - }); - test_step.dependOn(&check_exe.step); - - const run = b.addRunArtifact(exe); - run.skip_foreign_checks = true; - run.expectStdOutEqual("Hello!\n"); - test_step.dependOn(&run.step); -} diff --git a/test/link/macho/entry_in_dylib/main.c b/test/link/macho/entry_in_dylib/main.c deleted file mode 100644 index 26173b80ba..0000000000 --- a/test/link/macho/entry_in_dylib/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int my_main() { - fprintf(stdout, "Hello!\n"); - return 0; -}