@@ -9,44 +9,57 @@ const ResolvedTarget = std.Build.ResolvedTarget;
9
9
const Step = std .Build .Step ;
10
10
11
11
pub fn build (b : * std.Build ) void {
12
- const target = b .standardTargetOptions (.{ .default_target = .{
13
- .abi = if (builtin .target .os .tag == .linux ) .musl else null ,
14
- } });
15
- const optimize = b .standardOptimizeOption (.{});
16
- const strip = b .option (bool , "strip" , "Omit debug information" );
17
-
12
+ // build steps
18
13
const run_step = b .step ("run" , "Build and run the roc cli" );
14
+ const roc_step = b .step ("roc" , "Build the roc compiler without running it" );
19
15
const test_step = b .step ("test" , "Run all tests included in src/tests.zig" );
20
16
const fmt_step = b .step ("fmt" , "Format all zig code" );
21
17
const check_fmt_step = b .step ("check-fmt" , "Check formatting of all zig code" );
22
18
const snapshot_step = b .step ("snapshot" , "Run the snapshot tool to update snapshot files" );
23
19
24
- // llvm configuration
20
+ // general configuration
21
+ const target = b .standardTargetOptions (.{ .default_target = .{
22
+ .abi = if (builtin .target .os .tag == .linux ) .musl else null ,
23
+ } });
24
+ const optimize = b .standardOptimizeOption (.{});
25
+ const strip = b .option (bool , "strip" , "Omit debug information" );
25
26
const no_bin = b .option (bool , "no-bin" , "Skip emitting binaries (important for fast incremental compilation)" ) orelse false ;
27
+
28
+ // llvm configuration
26
29
const use_system_llvm = b .option (bool , "system-llvm" , "Attempt to automatically detect and use system installed llvm" ) orelse false ;
27
30
const enable_llvm = b .option (bool , "llvm" , "Build roc with the llvm backend" ) orelse use_system_llvm ;
28
31
const user_llvm_path = b .option ([]const u8 , "llvm-path" , "Path to llvm. This path must contain the bin, lib, and include directory." );
29
- const use_system_afl = b .option (bool , "system-afl" , "Attempt to automatically detect and use system installed afl++" ) orelse false ;
32
+ // Since zig afl is broken currently, default to system afl.
33
+ const use_system_afl = b .option (bool , "system-afl" , "Attempt to automatically detect and use system installed afl++" ) orelse true ;
30
34
31
35
if (user_llvm_path ) | path | {
32
36
// Even if the llvm backend is not enabled, still add the llvm path.
33
37
// AFL++ may use it for building fuzzing executables.
34
38
b .addSearchPrefix (b .pathJoin (&.{ path , "bin" }));
35
39
}
36
40
37
- const roc_exe = addMainExe (b , target , optimize , strip , enable_llvm , use_system_llvm , user_llvm_path ) orelse return ;
38
-
39
- if (no_bin ) {
40
- b .getInstallStep ().dependOn (& roc_exe .step );
41
- } else {
42
- b .installArtifact (roc_exe );
43
- const run_cmd = b .addRunArtifact (roc_exe );
44
- run_cmd .step .dependOn (b .getInstallStep ());
45
- if (b .args ) | args | {
46
- run_cmd .addArgs (args );
47
- }
48
- run_step .dependOn (& run_cmd .step );
41
+ // tracy profiler configuration
42
+ const tracy = b .option ([]const u8 , "tracy" , "Enable Tracy integration. Supply path to Tracy source" );
43
+ const tracy_callstack = b .option (bool , "tracy-callstack" , "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided" ) orelse (tracy != null );
44
+ const tracy_allocation = b .option (bool , "tracy-allocation" , "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided" ) orelse (tracy != null );
45
+ const tracy_callstack_depth : u32 = b .option (u32 , "tracy-callstack-depth" , "Declare callstack depth for Tracy data. Does nothing if -Dtracy_callstack is not provided" ) orelse 10 ;
46
+ if (tracy != null and target .result .os .tag == .macos ) {
47
+ std .log .warn ("Tracy has significantly more overhead on MacOS. Be cautious when generating timing and analyzing results." , .{});
49
48
}
49
+ if (tracy_callstack ) {
50
+ std .log .warn ("Tracy callstack is enable. This can significantly skew timings, but is important for understanding source location. Be cautious when generating timing and analyzing results." , .{});
51
+ }
52
+
53
+ // Create compile time build options
54
+ const build_options = b .addOptions ();
55
+ build_options .addOption (bool , "enable_tracy" , tracy != null );
56
+ build_options .addOption (bool , "enable_tracy_callstack" , tracy_callstack );
57
+ build_options .addOption (bool , "enable_tracy_allocation" , tracy_allocation );
58
+ build_options .addOption (u32 , "tracy_callstack_depth" , tracy_callstack_depth );
59
+
60
+ // add main roc exe
61
+ const roc_exe = addMainExe (b , build_options , target , optimize , strip , enable_llvm , use_system_llvm , user_llvm_path , tracy ) orelse return ;
62
+ install_and_run (b , no_bin , roc_exe , roc_step , run_step );
50
63
51
64
// Add snapshot tool
52
65
const snapshot_exe = b .addExecutable (.{
@@ -56,26 +69,16 @@ pub fn build(b: *std.Build) void {
56
69
.optimize = optimize ,
57
70
.link_libc = true ,
58
71
});
59
- if (no_bin ) {
60
- b .getInstallStep ().dependOn (& snapshot_exe .step );
61
- } else {
62
- b .installArtifact (snapshot_exe );
63
- const run_snapshot = b .addRunArtifact (snapshot_exe );
64
-
65
- // Add a step to run the snapshot tool
66
- run_snapshot .step .dependOn (b .getInstallStep ());
67
- if (b .args ) | args | {
68
- run_snapshot .addArgs (args );
69
- }
70
- snapshot_step .dependOn (& run_snapshot .step );
71
- }
72
+ add_tracy (b , build_options , snapshot_exe , target , false , tracy );
73
+ install_and_run (b , no_bin , snapshot_exe , snapshot_step , snapshot_step );
72
74
73
75
const all_tests = b .addTest (.{
74
76
.root_source_file = b .path ("src/test.zig" ),
75
77
.target = target ,
76
78
.optimize = optimize ,
77
79
.link_libc = true ,
78
80
});
81
+ all_tests .root_module .addOptions ("build_options" , build_options );
79
82
80
83
if (! no_bin ) {
81
84
const run_tests = b .addRunArtifact (all_tests );
@@ -126,6 +129,8 @@ pub fn build(b: *std.Build) void {
126
129
no_bin ,
127
130
target ,
128
131
optimize ,
132
+ build_options ,
133
+ tracy ,
129
134
name ,
130
135
);
131
136
}
@@ -139,6 +144,8 @@ fn add_fuzz_target(
139
144
no_bin : bool ,
140
145
target : ResolvedTarget ,
141
146
optimize : OptimizeMode ,
147
+ build_options : * Step.Options ,
148
+ tracy : ? []const u8 ,
142
149
name : []const u8 ,
143
150
) void {
144
151
// We always include the repro scripts (no dependencies).
@@ -151,10 +158,11 @@ fn add_fuzz_target(
151
158
// Work around instrumentation bugs on mac without giving up perf on linux.
152
159
.optimize = if (target .result .os .tag == .macos ) .Debug else .ReleaseSafe ,
153
160
});
161
+ add_tracy (b , build_options , fuzz_obj , target , false , tracy );
154
162
155
163
const name_exe = b .fmt ("fuzz-{s}" , .{name });
156
164
const name_repro = b .fmt ("repro-{s}" , .{name });
157
- const run_repro_step = b .step (name_repro , b .fmt ("run fuzz reproduction for {s}" , .{name }));
165
+ const repro_step = b .step (name_repro , b .fmt ("run fuzz reproduction for {s}" , .{name }));
158
166
const repro_exe = b .addExecutable (.{
159
167
.name = name_repro ,
160
168
.root_source_file = b .path ("src/fuzz-repro.zig" ),
@@ -163,37 +171,30 @@ fn add_fuzz_target(
163
171
.link_libc = true ,
164
172
});
165
173
repro_exe .root_module .addImport ("fuzz_test" , fuzz_obj .root_module );
166
- if (no_bin ) {
167
- b .getInstallStep ().dependOn (& repro_exe .step );
168
- } else {
169
- b .installArtifact (repro_exe );
170
-
171
- const run_cmd = b .addRunArtifact (repro_exe );
172
- run_cmd .step .dependOn (b .getInstallStep ());
173
- if (b .args ) | args | {
174
- run_cmd .addArgs (args );
175
- }
176
- run_repro_step .dependOn (& run_cmd .step );
177
- }
174
+ install_and_run (b , no_bin , repro_exe , repro_step , repro_step );
178
175
179
176
if (fuzz and build_afl and ! no_bin ) {
180
177
const fuzz_step = b .step (name_exe , b .fmt ("Generate fuzz executable for {s}" , .{name }));
181
178
b .default_step .dependOn (fuzz_step );
182
179
183
180
const afl = b .lazyImport (@This (), "afl_kit" ) orelse return ;
184
181
const fuzz_exe = afl .addInstrumentedExe (b , target , .ReleaseSafe , &.{}, use_system_afl , fuzz_obj ) orelse return ;
185
- fuzz_step .dependOn (& b .addInstallBinFile (fuzz_exe , name_exe ).step );
182
+ const install_fuzz = b .addInstallBinFile (fuzz_exe , name_exe );
183
+ fuzz_step .dependOn (& install_fuzz .step );
184
+ b .getInstallStep ().dependOn (& install_fuzz .step );
186
185
}
187
186
}
188
187
189
188
fn addMainExe (
190
189
b : * std.Build ,
190
+ build_options : * Step.Options ,
191
191
target : ResolvedTarget ,
192
192
optimize : OptimizeMode ,
193
193
strip : ? bool ,
194
194
enable_llvm : bool ,
195
195
use_system_llvm : bool ,
196
196
user_llvm_path : ? []const u8 ,
197
+ tracy : ? []const u8 ,
197
198
) ? * Step.Compile {
198
199
const exe = b .addExecutable (.{
199
200
.name = "roc" ,
@@ -216,9 +217,72 @@ fn addMainExe(
216
217
try addStaticLlvmOptionsToModule (exe .root_module );
217
218
}
218
219
220
+ add_tracy (b , build_options , exe , target , enable_llvm , tracy );
219
221
return exe ;
220
222
}
221
223
224
+ fn install_and_run (
225
+ b : * std.Build ,
226
+ no_bin : bool ,
227
+ exe : * Step.Compile ,
228
+ build_step : * Step ,
229
+ run_step : * Step ,
230
+ ) void {
231
+ if (run_step != build_step ) {
232
+ run_step .dependOn (build_step );
233
+ }
234
+ if (no_bin ) {
235
+ // No build, just build, don't actually install or run.
236
+ build_step .dependOn (& exe .step );
237
+ b .getInstallStep ().dependOn (& exe .step );
238
+ } else {
239
+ const install = b .addInstallArtifact (exe , .{});
240
+ build_step .dependOn (& install .step );
241
+ b .getInstallStep ().dependOn (& install .step );
242
+
243
+ const run = b .addRunArtifact (exe );
244
+ run .step .dependOn (& install .step );
245
+ if (b .args ) | args | {
246
+ run .addArgs (args );
247
+ }
248
+ run_step .dependOn (& run .step );
249
+ }
250
+ }
251
+
252
+ fn add_tracy (
253
+ b : * std.Build ,
254
+ build_options : * Step.Options ,
255
+ base : * Step.Compile ,
256
+ target : ResolvedTarget ,
257
+ links_llvm : bool ,
258
+ tracy : ? []const u8 ,
259
+ ) void {
260
+ base .root_module .addOptions ("build_options" , build_options );
261
+ if (tracy ) | tracy_path | {
262
+ const client_cpp = b .pathJoin (
263
+ &[_ ][]const u8 { tracy_path , "public" , "TracyClient.cpp" },
264
+ );
265
+
266
+ // On mingw, we need to opt into windows 7+ to get some features required by tracy.
267
+ const tracy_c_flags : []const []const u8 = if (target .result .os .tag == .windows and target .result .abi == .gnu )
268
+ &[_ ][]const u8 { "-DTRACY_ENABLE=1" , "-fno-sanitize=undefined" , "-D_WIN32_WINNT=0x601" }
269
+ else
270
+ &[_ ][]const u8 { "-DTRACY_ENABLE=1" , "-fno-sanitize=undefined" };
271
+
272
+ base .root_module .addIncludePath (.{ .cwd_relative = tracy_path });
273
+ base .root_module .addCSourceFile (.{ .file = .{ .cwd_relative = client_cpp }, .flags = tracy_c_flags });
274
+ if (! links_llvm ) {
275
+ base .root_module .linkSystemLibrary ("c++" , .{ .use_pkg_config = .no });
276
+ }
277
+ base .root_module .link_libc = true ;
278
+
279
+ if (target .result .os .tag == .windows ) {
280
+ base .root_module .linkSystemLibrary ("dbghelp" , .{});
281
+ base .root_module .linkSystemLibrary ("ws2_32" , .{});
282
+ }
283
+ }
284
+ }
285
+
222
286
const LlvmPaths = struct {
223
287
include : []const u8 ,
224
288
lib : []const u8 ,
@@ -305,16 +369,20 @@ fn addStaticLlvmOptionsToModule(mod: *std.Build.Module) !void {
305
369
.flags = & cpp_cflags ,
306
370
});
307
371
372
+ const link_static = std.Build.Module.LinkSystemLibraryOptions {
373
+ .preferred_link_mode = .static ,
374
+ .search_strategy = .mode_first ,
375
+ };
308
376
for (lld_libs ) | lib_name | {
309
- mod .linkSystemLibrary (lib_name , .{} );
377
+ mod .linkSystemLibrary (lib_name , link_static );
310
378
}
311
379
312
380
for (llvm_libs ) | lib_name | {
313
- mod .linkSystemLibrary (lib_name , .{} );
381
+ mod .linkSystemLibrary (lib_name , link_static );
314
382
}
315
383
316
- mod .linkSystemLibrary ("z" , .{} );
317
- mod .linkSystemLibrary ("zstd" , .{} );
384
+ mod .linkSystemLibrary ("z" , link_static );
385
+ mod .linkSystemLibrary ("zstd" , link_static );
318
386
319
387
if (mod .resolved_target .? .result .os .tag != .windows or mod .resolved_target .? .result .abi != .msvc ) {
320
388
// TODO: Can this just be `mod.link_libcpp = true`? Does that make a difference?
0 commit comments