| author | |
| committer | |
| log | 7566a8fbd81a71d4b61022fd2b6f5f80a4679fb0 |
| tree | 2981d3abee93cd1c3e599ad9529cc9bf60b5807b |
| parent | 197fd41e27647d846b6e6bf6197bad0ab14634ae |
4 files changed, 215 insertions(+), 9 deletions(-)
test/link.zig+5-6| ... | ... | @@ -4,6 +4,11 @@ pub const Case = struct { |
| 4 | 4 | }; |
| 5 | 5 | |
| 6 | 6 | pub const cases = [_]Case{ |
| 7 | .{ | |
| 8 | .build_root = "test/link", | |
| 9 | .import = @import("link/link.zig"), | |
| 10 | }, | |
| 11 | ||
| 7 | 12 | .{ |
| 8 | 13 | .build_root = "test/link/bss", |
| 9 | 14 | .import = @import("link/bss/build.zig"), |
| ... | ... | @@ -29,12 +34,6 @@ pub const cases = [_]Case{ |
| 29 | 34 | .import = @import("link/glibc_compat/build.zig"), |
| 30 | 35 | }, |
| 31 | 36 | |
| 32 | // Elf Cases | |
| 33 | .{ | |
| 34 | .build_root = "test/link", | |
| 35 | .import = @import("link/elf.zig"), | |
| 36 | }, | |
| 37 | ||
| 38 | 37 | // WASM Cases |
| 39 | 38 | // https://github.com/ziglang/zig/issues/16938 |
| 40 | 39 | //.{ |
test/link/elf.zig+3-3| ... | ... | @@ -2,9 +2,8 @@ |
| 2 | 2 | //! Currently, we support linking x86_64 Linux, but in the future we |
| 3 | 3 | //! will progressively relax those to exercise more combinations. |
| 4 | 4 | |
| 5 | pub fn build(b: *Build) void { | |
| 5 | pub fn testAll(b: *Build) *Step { | |
| 6 | 6 | const elf_step = b.step("test-elf", "Run ELF tests"); |
| 7 | b.default_step = elf_step; | |
| 8 | 7 | |
| 9 | 8 | const default_target = CrossTarget{ |
| 10 | 9 | .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs |
| ... | ... | @@ -123,6 +122,8 @@ pub fn build(b: *Build) void { |
| 123 | 122 | elf_step.dependOn(testZNow(b, .{ .target = glibc_target })); |
| 124 | 123 | elf_step.dependOn(testZStackSize(b, .{ .target = glibc_target })); |
| 125 | 124 | elf_step.dependOn(testZText(b, .{ .target = glibc_target })); |
| 125 | ||
| 126 | return elf_step; | |
| 126 | 127 | } |
| 127 | 128 | |
| 128 | 129 | fn testAbsSymbols(b: *Build, opts: Options) *Step { |
| ... | ... | @@ -3582,7 +3583,6 @@ const std = @import("std"); |
| 3582 | 3583 | const Build = std.Build; |
| 3583 | 3584 | const Compile = Step.Compile; |
| 3584 | 3585 | const CrossTarget = std.zig.CrossTarget; |
| 3585 | const LazyPath = Build.LazyPath; | |
| 3586 | 3586 | const Run = Step.Run; |
| 3587 | 3587 | const Step = Build.Step; |
| 3588 | 3588 | const WriteFile = Step.WriteFile; |
test/link/link.zig created+114| ... | ... | @@ -0,0 +1,114 @@ |
| 1 | pub fn build(b: *Build) void { | |
| 2 | const test_step = b.step("test-link", "Run link tests"); | |
| 3 | b.default_step = test_step; | |
| 4 | ||
| 5 | test_step.dependOn(@import("elf.zig").testAll(b)); | |
| 6 | test_step.dependOn(@import("macho.zig").testAll(b)); | |
| 7 | } | |
| 8 | ||
| 9 | pub const Options = struct { | |
| 10 | target: CrossTarget, | |
| 11 | optimize: std.builtin.OptimizeMode = .Debug, | |
| 12 | use_llvm: bool = true, | |
| 13 | use_lld: bool = false, | |
| 14 | }; | |
| 15 | ||
| 16 | pub fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step { | |
| 17 | const target = opts.target.zigTriple(b.allocator) catch @panic("OOM"); | |
| 18 | const optimize = @tagName(opts.optimize); | |
| 19 | const use_llvm = if (opts.use_llvm) "llvm" else "no-llvm"; | |
| 20 | const name = std.fmt.allocPrint(b.allocator, "test-" ++ prefix ++ "-{s}-{s}-{s}", .{ | |
| 21 | target, | |
| 22 | optimize, | |
| 23 | use_llvm, | |
| 24 | }) catch @panic("OOM"); | |
| 25 | return b.step(name, ""); | |
| 26 | } | |
| 27 | ||
| 28 | pub fn addExecutable(b: *Build, name: []const u8, opts: Options) *Compile { | |
| 29 | return b.addExecutable(.{ | |
| 30 | .name = name, | |
| 31 | .target = opts.target, | |
| 32 | .optimize = opts.optimize, | |
| 33 | .use_llvm = opts.use_llvm, | |
| 34 | .use_lld = opts.use_lld, | |
| 35 | }); | |
| 36 | } | |
| 37 | ||
| 38 | pub fn addObject(b: *Build, name: []const u8, opts: Options) *Compile { | |
| 39 | return b.addObject(.{ | |
| 40 | .name = name, | |
| 41 | .target = opts.target, | |
| 42 | .optimize = opts.optimize, | |
| 43 | .use_llvm = opts.use_llvm, | |
| 44 | .use_lld = opts.use_lld, | |
| 45 | }); | |
| 46 | } | |
| 47 | ||
| 48 | pub fn addStaticLibrary(b: *Build, name: []const u8, opts: Options) *Compile { | |
| 49 | return b.addStaticLibrary(.{ | |
| 50 | .name = name, | |
| 51 | .target = opts.target, | |
| 52 | .optimize = opts.optimize, | |
| 53 | .use_llvm = opts.use_llvm, | |
| 54 | .use_lld = opts.use_lld, | |
| 55 | }); | |
| 56 | } | |
| 57 | ||
| 58 | pub fn addSharedLibrary(b: *Build, name: []const u8, opts: Options) *Compile { | |
| 59 | return b.addSharedLibrary(.{ | |
| 60 | .name = name, | |
| 61 | .target = opts.target, | |
| 62 | .optimize = opts.optimize, | |
| 63 | .use_llvm = opts.use_llvm, | |
| 64 | .use_lld = opts.use_lld, | |
| 65 | }); | |
| 66 | } | |
| 67 | ||
| 68 | pub fn addRunArtifact(comp: *Compile) *Run { | |
| 69 | const b = comp.step.owner; | |
| 70 | const run = b.addRunArtifact(comp); | |
| 71 | run.skip_foreign_checks = true; | |
| 72 | return run; | |
| 73 | } | |
| 74 | ||
| 75 | pub fn addZigSourceBytes(comp: *Compile, bytes: []const u8) void { | |
| 76 | const b = comp.step.owner; | |
| 77 | const file = WriteFile.create(b).add("a.zig", bytes); | |
| 78 | file.addStepDependencies(&comp.step); | |
| 79 | comp.root_src = file; | |
| 80 | } | |
| 81 | ||
| 82 | pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void { | |
| 83 | const b = comp.step.owner; | |
| 84 | const file = WriteFile.create(b).add("a.c", bytes); | |
| 85 | comp.addCSourceFile(.{ .file = file, .flags = flags }); | |
| 86 | } | |
| 87 | ||
| 88 | pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void { | |
| 89 | const b = comp.step.owner; | |
| 90 | const file = WriteFile.create(b).add("a.cpp", bytes); | |
| 91 | comp.addCSourceFile(.{ .file = file, .flags = flags }); | |
| 92 | } | |
| 93 | ||
| 94 | pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void { | |
| 95 | const b = comp.step.owner; | |
| 96 | const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM"); | |
| 97 | const file = WriteFile.create(b).add("a.s", actual_bytes); | |
| 98 | comp.addAssemblyFile(file); | |
| 99 | } | |
| 100 | ||
| 101 | pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void { | |
| 102 | comp.expect_errors = expected_errors; | |
| 103 | const bin_file = comp.getEmittedBin(); | |
| 104 | bin_file.addStepDependencies(test_step); | |
| 105 | } | |
| 106 | ||
| 107 | const std = @import("std"); | |
| 108 | ||
| 109 | const Build = std.Build; | |
| 110 | const Compile = Step.Compile; | |
| 111 | const CrossTarget = std.zig.CrossTarget; | |
| 112 | const Run = Step.Run; | |
| 113 | const Step = Build.Step; | |
| 114 | const WriteFile = Step.WriteFile; |
test/link/macho.zig created+93| ... | ... | @@ -0,0 +1,93 @@ |
| 1 | //! Here we test our MachO linker for correctness and functionality. | |
| 2 | //! TODO migrate standalone tests from test/link/macho/* to here. | |
| 3 | ||
| 4 | pub fn testAll(b: *Build) *Step { | |
| 5 | const macho_step = b.step("test-macho", "Run MachO tests"); | |
| 6 | ||
| 7 | const default_target = CrossTarget{ .os_tag = .macos }; | |
| 8 | ||
| 9 | macho_step.dependOn(testResolvingBoundarySymbols(b, .{ .target = default_target })); | |
| 10 | ||
| 11 | return macho_step; | |
| 12 | } | |
| 13 | ||
| 14 | fn testResolvingBoundarySymbols(b: *Build, opts: Options) *Step { | |
| 15 | const test_step = addTestStep(b, "macho-resolving-boundary-symbols", opts); | |
| 16 | ||
| 17 | const obj1 = addObject(b, "obj1", opts); | |
| 18 | addCppSourceBytes(obj1, | |
| 19 | \\constexpr const char* MESSAGE __attribute__((used, section("__DATA_CONST,__message_ptr"))) = "codebase"; | |
| 20 | , &.{}); | |
| 21 | ||
| 22 | const main_o = addObject(b, "main", opts); | |
| 23 | addZigSourceBytes(main_o, | |
| 24 | \\const std = @import("std"); | |
| 25 | \\extern fn interop() [*:0]const u8; | |
| 26 | \\pub fn main() !void { | |
| 27 | \\ std.debug.print("All your {s} are belong to us.\n", .{ | |
| 28 | \\ std.mem.span(interop()), | |
| 29 | \\ }); | |
| 30 | \\} | |
| 31 | ); | |
| 32 | ||
| 33 | { | |
| 34 | const obj2 = addObject(b, "obj2", opts); | |
| 35 | addCppSourceBytes(obj2, | |
| 36 | \\extern const char* message_pointer __asm("section$start$__DATA_CONST$__message_ptr"); | |
| 37 | \\extern "C" const char* interop() { | |
| 38 | \\ return message_pointer; | |
| 39 | \\} | |
| 40 | , &.{}); | |
| 41 | ||
| 42 | const exe = addExecutable(b, "test", opts); | |
| 43 | exe.addObject(obj1); | |
| 44 | exe.addObject(obj2); | |
| 45 | exe.addObject(main_o); | |
| 46 | ||
| 47 | const run = addRunArtifact(exe); | |
| 48 | run.expectStdErrEqual("All your codebase are belong to us.\n"); | |
| 49 | test_step.dependOn(&run.step); | |
| 50 | ||
| 51 | const check = exe.checkObject(); | |
| 52 | check.checkInSymtab(); | |
| 53 | check.checkNotPresent("section$start$__DATA_CONST$__message_ptr"); | |
| 54 | test_step.dependOn(&check.step); | |
| 55 | } | |
| 56 | ||
| 57 | { | |
| 58 | const obj3 = addObject(b, "obj3", opts); | |
| 59 | addCppSourceBytes(obj3, | |
| 60 | \\extern const char* message_pointer __asm("section$start$__DATA$__message_ptr"); | |
| 61 | \\extern "C" const char* interop() { | |
| 62 | \\ return message_pointer; | |
| 63 | \\} | |
| 64 | , &.{}); | |
| 65 | ||
| 66 | const exe = addExecutable(b, "test", opts); | |
| 67 | exe.addObject(obj1); | |
| 68 | exe.addObject(obj3); | |
| 69 | exe.addObject(main_o); | |
| 70 | ||
| 71 | expectLinkErrors(exe, test_step, .{ .exact = &.{ | |
| 72 | "section not found: __DATA,__message_ptr", | |
| 73 | "note: while resolving section$start$__DATA$__message_ptr", | |
| 74 | } }); | |
| 75 | } | |
| 76 | ||
| 77 | return test_step; | |
| 78 | } | |
| 79 | ||
| 80 | const addCppSourceBytes = link.addCppSourceBytes; | |
| 81 | const addExecutable = link.addExecutable; | |
| 82 | const addObject = link.addObject; | |
| 83 | const addRunArtifact = link.addRunArtifact; | |
| 84 | const addTestStep = link.addTestStep; | |
| 85 | const addZigSourceBytes = link.addZigSourceBytes; | |
| 86 | const expectLinkErrors = link.expectLinkErrors; | |
| 87 | const link = @import("link.zig"); | |
| 88 | const std = @import("std"); | |
| 89 | ||
| 90 | const Build = std.Build; | |
| 91 | const CrossTarget = std.zig.CrossTarget; | |
| 92 | const Options = link.Options; | |
| 93 | const Step = Build.Step; |