Repository navigation
Expand file tree
/
Copy pathbuild.zig
More file actions
145 lines (131 loc) · 5.75 KB
/
Copy pathbuild.zig
File metadata and controls
145 lines (131 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
const std = @import("std");
const builtin = @import("builtin");
/// ere publishes `libere_verifier_c` for aarch64 macOS and for x86_64 and
/// aarch64 glibc Linux. Every other target gets the module with
/// `available = false` and no `c`, so consumers gate on `available`.
///
/// Linux links the archive statically. Rust's unwinder needs `-lunwind`.
///
/// macOS cannot link the archive statically: Zig's Mach-O linker rejects the
/// debug stabs of the `ld -r` merged object and, once those are stripped,
/// mislays its thread-local offsets. Native macOS builds instead turn the
/// archive into a dylib with Apple's ld. Consumers install it beside their
/// binary from the named lazy path `libere_verifier_c.dylib`; the module
/// carries an `@loader_path` rpath for that and an rpath into the cache for
/// test binaries.
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const dylib_option = b.option(
bool,
"dylib",
"On macOS, link through a dylib built with Apple's ld. Defaults to true for native macOS builds.",
);
const t = target.result;
const native = target.query.isNativeOs() and target.query.isNativeCpu();
const darwin_dylib = dylib_option orelse (t.os.tag == .macos and native and builtin.os.tag == .macos);
const package: ?*std.Build.Dependency = switch (t.os.tag) {
.macos => if (t.cpu.arch == .aarch64 and darwin_dylib) b.lazyDependency("darwin_arm64", .{}) else null,
.linux => if (t.abi != .gnu) null else switch (t.cpu.arch) {
.x86_64 => b.lazyDependency("linux_amd64", .{}),
.aarch64 => b.lazyDependency("linux_arm64", .{}),
else => null,
},
else => null,
};
const options = b.addOptions();
options.addOption(bool, "available", package != null);
const module = b.addModule("ere", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
module.addOptions("build_options", options);
if (package) |pkg| {
const translated = b.addTranslateC(.{
.root_source_file = pkg.path("ere_verifier.h"),
.target = target,
.optimize = optimize,
});
module.addImport("c", translated.createModule());
const archive = pkg.path("libere_verifier_c.a");
switch (t.os.tag) {
.linux => {
module.addObjectFile(archive);
module.linkSystemLibrary("m", .{});
module.linkSystemLibrary("pthread", .{});
module.linkSystemLibrary("dl", .{});
module.linkSystemLibrary("unwind", .{});
},
.macos => linkDarwinDylib(b, module, target, optimize, archive),
else => unreachable,
}
}
const tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/test.zig"),
.target = target,
.optimize = optimize,
.imports = &.{.{ .name = "ere", .module = module }},
}),
});
b.step("test", "Run the tests").dependOn(&b.addRunArtifact(tests).step);
const download = b.addExecutable(.{
.name = "download_fixtures",
.root_module = b.createModule(.{
.root_source_file = b.path("scripts/download_fixtures.zig"),
.target = b.graph.host,
.optimize = .Debug,
}),
});
b.step("download-fixtures", "Download ere's verifier fixtures into test/fixtures").dependOn(&b.addRunArtifact(download).step);
}
fn linkDarwinDylib(
b: *std.Build,
module: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
archive: std.Build.LazyPath,
) void {
const min_os = target.result.os.version_range.semver.min;
const sdk_path = std.mem.trim(u8, b.run(&.{ "xcrun", "--show-sdk-path" }), &std.ascii.whitespace);
const sdk_version = std.mem.trim(u8, b.run(&.{ "xcrun", "--show-sdk-version" }), &std.ascii.whitespace);
const strip = b.addSystemCommand(&.{ "strip", "-S", "-o" });
const stripped = strip.addOutputFileArg("libere_verifier_c.a");
strip.addFileArg(archive);
// The archive localizes `_rust_eh_personality` but still references it, so
// the dylib needs a definition. Unwinding reaches it only on a panic inside
// the verifier, which then traps instead of unwinding into a hidden routine.
const stub_source = b.addWriteFiles().add("rust_eh_personality_stub.zig",
\\export fn rust_eh_personality() callconv(.c) noreturn {
\\ @trap();
\\}
\\
);
const stub = b.addObject(.{
.name = "rust_eh_personality_stub",
.root_module = b.createModule(.{
.root_source_file = stub_source,
.target = target,
.optimize = optimize,
}),
});
const ld = b.addSystemCommand(&.{
"ld", "-dylib",
"-arch", "arm64",
"-platform_version", "macos",
b.fmt("{d}.{d}", .{ min_os.major, min_os.minor }), sdk_version,
"-syslibroot", sdk_path,
"-lSystem", "-all_load",
"-install_name", "@rpath/libere_verifier_c.dylib",
});
ld.addFileArg(stripped);
ld.addFileArg(stub.getEmittedBin());
ld.addArg("-o");
const dylib = ld.addOutputFileArg("libere_verifier_c.dylib");
module.addObjectFile(dylib);
module.addRPath(dylib.dirname());
module.addRPathSpecial("@loader_path");
b.addNamedLazyPath("libere_verifier_c.dylib", dylib);
}