| ... | ... | @@ -0,0 +1,89 @@ |
| 1 | //! Here we test our ELF linker for correctness and functionality. |
| 2 | //! Currently, we support linking x86_64 Linux, but in the future we |
| 3 | //! will progressively relax those to exercise more combinations. |
| 4 | |
| 5 | pub fn build(b: *Build) void { |
| 6 | const elf_step = b.step("test-elf", "Run ELF tests"); |
| 7 | b.default_step = elf_step; |
| 8 | |
| 9 | const target: CrossTarget = .{ |
| 10 | .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs |
| 11 | .os_tag = .linux, |
| 12 | }; |
| 13 | |
| 14 | elf_step.dependOn(testHelloStatic(b, .{ .target = target, .use_llvm = true })); |
| 15 | elf_step.dependOn(testHelloStatic(b, .{ .target = target, .use_llvm = false })); |
| 16 | } |
| 17 | |
| 18 | fn testHelloStatic(b: *Build, opts: Options) *Step { |
| 19 | const test_step = addTestStep(b, "hello-static", opts); |
| 20 | |
| 21 | const exe = addExecutable(b, opts); |
| 22 | addZigSourceBytes(exe, |
| 23 | \\pub fn main() void { |
| 24 | \\ @import("std").debug.print("Hello World!\n", .{}); |
| 25 | \\} |
| 26 | ); |
| 27 | exe.linkage = .static; |
| 28 | |
| 29 | const run = b.addRunArtifact(exe); |
| 30 | run.expectStdErrEqual("Hello World!\n"); |
| 31 | test_step.dependOn(&run.step); |
| 32 | |
| 33 | const check = exe.checkObject(); |
| 34 | check.checkStart(); |
| 35 | check.checkExact("header"); |
| 36 | check.checkExact("type EXEC"); |
| 37 | check.checkStart(); |
| 38 | check.checkExact("section headers"); |
| 39 | check.checkNotPresent("name .dynamic"); |
| 40 | test_step.dependOn(&check.step); |
| 41 | |
| 42 | return test_step; |
| 43 | } |
| 44 | |
| 45 | const Options = struct { |
| 46 | target: CrossTarget = .{ .os_tag = .linux }, |
| 47 | optimize: std.builtin.OptimizeMode = .Debug, |
| 48 | use_llvm: bool = true, |
| 49 | }; |
| 50 | |
| 51 | fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step { |
| 52 | const target = opts.target.zigTriple(b.allocator) catch @panic("OOM"); |
| 53 | const optimize = @tagName(opts.optimize); |
| 54 | const use_llvm = if (opts.use_llvm) "llvm" else "no-llvm"; |
| 55 | const name = std.fmt.allocPrint(b.allocator, "test-elf-" ++ prefix ++ "-{s}-{s}-{s}", .{ |
| 56 | target, |
| 57 | optimize, |
| 58 | use_llvm, |
| 59 | }) catch @panic("OOM"); |
| 60 | return b.step(name, ""); |
| 61 | } |
| 62 | |
| 63 | fn addExecutable(b: *Build, opts: Options) *Compile { |
| 64 | return b.addExecutable(.{ |
| 65 | .name = "test", |
| 66 | .target = opts.target, |
| 67 | .optimize = opts.optimize, |
| 68 | .single_threaded = true, // TODO temp until we teach linker how to handle TLS |
| 69 | .use_llvm = opts.use_llvm, |
| 70 | .use_lld = false, |
| 71 | }); |
| 72 | } |
| 73 | |
| 74 | fn addZigSourceBytes(comp: *Compile, bytes: []const u8) void { |
| 75 | const b = comp.step.owner; |
| 76 | const file = WriteFile.create(b).add("a.zig", bytes); |
| 77 | file.addStepDependencies(&comp.step); |
| 78 | comp.root_src = file; |
| 79 | } |
| 80 | |
| 81 | const std = @import("std"); |
| 82 | |
| 83 | const Build = std.Build; |
| 84 | const Compile = Step.Compile; |
| 85 | const CrossTarget = std.zig.CrossTarget; |
| 86 | const LazyPath = Build.LazyPath; |
| 87 | const Run = Step.Run; |
| 88 | const Step = Build.Step; |
| 89 | const WriteFile = Step.WriteFile; |