| ... | ... | @@ -1,4 +1,14 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); |
| 3 | |
| 4 | // To run executables linked against a specific glibc version, the |
| 5 | // run-time glibc version needs to be new enough. Check the host's glibc |
| 6 | // version. Note that this does not allow for translation/vm/emulation |
| 7 | // services to run these tests. |
| 8 | const running_glibc_ver: ?std.SemanticVersion = switch (builtin.os.tag) { |
| 9 | .linux => builtin.os.version_range.linux.glibc, |
| 10 | else => null, |
| 11 | }; |
| 2 | 12 | |
| 3 | 13 | pub fn build(b: *std.Build) void { |
| 4 | 14 | const test_step = b.step("test", "Test"); |
| ... | ... | @@ -17,4 +27,89 @@ pub fn build(b: *std.Build) void { |
| 17 | 27 | _ = exe.getEmittedBin(); |
| 18 | 28 | test_step.dependOn(&exe.step); |
| 19 | 29 | } |
| 30 | |
| 31 | // Build & run against a sampling of supported glibc versions |
| 32 | for ([_][]const u8{ |
| 33 | "native-linux-gnu.2.17", // Currently oldest supported, see #17769 |
| 34 | "native-linux-gnu.2.23", |
| 35 | "native-linux-gnu.2.28", |
| 36 | "native-linux-gnu.2.33", |
| 37 | "native-linux-gnu.2.38", |
| 38 | "native-linux-gnu", |
| 39 | }) |t| { |
| 40 | const target = b.resolveTargetQuery(std.Target.Query.parse( |
| 41 | .{ .arch_os_abi = t }, |
| 42 | ) catch unreachable); |
| 43 | |
| 44 | const glibc_ver = target.result.os.version_range.linux.glibc; |
| 45 | |
| 46 | const exe = b.addExecutable(.{ |
| 47 | .name = t, |
| 48 | .root_source_file = .{ .path = "glibc_runtime_check.zig" }, |
| 49 | .target = target, |
| 50 | }); |
| 51 | exe.linkLibC(); |
| 52 | |
| 53 | // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig |
| 54 | // test runner would be able to check this, but see https://github.com/ziglang/zig/pull/17702#issuecomment-1831310453 |
| 55 | if (running_glibc_ver) |running_ver| { |
| 56 | if (glibc_ver.order(running_ver) == .lt) { |
| 57 | const run_cmd = b.addRunArtifact(exe); |
| 58 | run_cmd.skip_foreign_checks = true; |
| 59 | run_cmd.expectExitCode(0); |
| 60 | |
| 61 | test_step.dependOn(&run_cmd.step); |
| 62 | } |
| 63 | } |
| 64 | const check = exe.checkObject(); |
| 65 | |
| 66 | // __errno_location is always a dynamically linked symbol |
| 67 | check.checkInDynamicSymtab(); |
| 68 | check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __errno_location"); |
| 69 | |
| 70 | // before v2.32 fstatat redirects through __fxstatat, afterwards its a |
| 71 | // normal dynamic symbol |
| 72 | if (glibc_ver.order(.{ .major = 2, .minor = 32, .patch = 0 }) == .lt) { |
| 73 | check.checkInDynamicSymtab(); |
| 74 | check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __fxstatat"); |
| 75 | |
| 76 | check.checkInSymtab(); |
| 77 | check.checkContains("FUNC LOCAL HIDDEN fstatat"); |
| 78 | } else { |
| 79 | check.checkInDynamicSymtab(); |
| 80 | check.checkExact("0 0 UND FUNC GLOBAL DEFAULT fstatat"); |
| 81 | |
| 82 | check.checkInSymtab(); |
| 83 | check.checkNotPresent("FUNC LOCAL HIDDEN fstatat"); |
| 84 | } |
| 85 | |
| 86 | // before v2.26 reallocarray is not supported |
| 87 | if (glibc_ver.order(.{ .major = 2, .minor = 26, .patch = 0 }) == .lt) { |
| 88 | check.checkInDynamicSymtab(); |
| 89 | check.checkNotPresent("reallocarray"); |
| 90 | } else { |
| 91 | check.checkInDynamicSymtab(); |
| 92 | check.checkExact("0 0 UND FUNC GLOBAL DEFAULT reallocarray"); |
| 93 | } else { |
| 94 | check.checkInDynamicSymtab(); |
| 95 | check.checkNotPresent("reallocarray"); |
| 96 | } |
| 97 | |
| 98 | // v2.16 introduced getauxval(), so always present |
| 99 | check.checkInDynamicSymtab(); |
| 100 | check.checkExact("0 0 UND FUNC GLOBAL DEFAULT getauxval"); |
| 101 | |
| 102 | // Always have a dynamic "exit" reference |
| 103 | check.checkInDynamicSymtab(); |
| 104 | check.checkExact("0 0 UND FUNC GLOBAL DEFAULT exit"); |
| 105 | |
| 106 | // An atexit local symbol is defined, and depends on undefined dynamic |
| 107 | // __cxa_atexit. |
| 108 | check.checkInSymtab(); |
| 109 | check.checkContains("FUNC LOCAL HIDDEN atexit"); |
| 110 | check.checkInDynamicSymtab(); |
| 111 | check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __cxa_atexit"); |
| 112 | |
| 113 | test_step.dependOn(&check.step); |
| 114 | } |
| 20 | 115 | } |