1const Compile = @This();
2
3const builtin = @import("builtin");
4
5const std = @import("std");
6const Io = std.Io;
7const mem = std.mem;
8const fs = std.fs;
9const assert = std.debug.assert;
10const panic = std.debug.panic;
11const StringHashMap = std.StringHashMap;
12const Allocator = std.mem.Allocator;
13const Step = std.Build.Step;
14const LazyPath = std.Build.LazyPath;
15const Module = std.Build.Module;
16const InstallDir = std.Build.InstallDir;
17const Path = std.Build.Cache.Path;
18const Configuration = std.Build.Configuration;
19
20pub const base_tag: Step.Tag = .compile;
21
22step: Step,
23root_module: *Module,
24
25name: []const u8,
26linker_script: ?LazyPath = null,
27version_script: ?LazyPath = null,
28/// Deprecated.
29out_filename: []const u8,
30linkage: ?std.builtin.LinkMode = null,
31version: ?std.SemanticVersion,
32kind: Kind,
33formatted_panics: ?bool = null,
34compress_debug_sections: std.zig.CompressDebugSections = .none,
35verbose_link: bool,
36verbose_cc: bool,
37bundle_compiler_rt: ?bool = null,
38bundle_ubsan_rt: ?bool = null,
39rdynamic: bool,
40import_memory: bool = false,
41export_memory: bool = false,
42/// For WebAssembly targets, this will allow for undefined symbols to
43/// be imported from the host environment.
44import_symbols: bool = false,
45/// (WebAssembly) import function table from the host environment
46import_table: bool = false,
47export_table: bool = false,
48growable_table: bool = false,
49initial_memory: ?u64 = null,
50max_memory: ?u64 = null,
51shared_memory: bool = false,
52global_base: ?u64 = null,
53/// Set via options; intended to be read-only after that.
54zig_lib_dir: ?LazyPath,
55filters: []const []const u8,
56test_runner: ?TestRunner,
57wasi_exec_model: ?std.builtin.WasiExecModel = null,
58
59installed_headers: std.ArrayList(HeaderInstallation),
60
61/// This step is used to create an include tree that dependent modules can add to their include
62/// search paths. Installed headers are copied to this step.
63/// This step is created the first time a module links with this artifact and is not
64/// created otherwise.
65installed_headers_include_tree: ?*Step.WriteFile = null,
66
67/// Deprecated. This functionality will be moved to an external package:
68/// https://codeberg.org/ziglang/rc
69///
70/// Behavior of automatic detection of include directories when compiling .rc files.
71/// any: Use MSVC if available, fall back to MinGW.
72/// msvc: Use MSVC include paths (must be present on the system).
73/// gnu: Use MinGW include paths (distributed with Zig).
74/// none: Do not use any autodetected include paths.
75rc_includes: std.zig.RcIncludes = .any,
76
77/// Deprecated. This functionality will be moved to an external package:
78/// https://codeberg.org/ziglang/rc
79///
80/// (Windows) .manifest file to embed in the compilation
81/// Set via options; intended to be read-only after that.
82win32_manifest: ?LazyPath = null,
83
84/// (Windows) .def file to embed in the compilation (dll)
85/// Set via options; intended to be read-only after that.
86win32_module_definition: ?LazyPath = null,
87
88/// Base address for an executable image.
89image_base: ?u64 = null,
90
91libc_file: ?LazyPath = null,
92
93each_lib_rpath: ?bool = null,
94/// On ELF targets, this will emit a link section called ".note.gnu.build-id"
95/// which can be used to coordinate a stripped binary with its debug symbols.
96///
97/// As an example, the bloaty project refuses to work unless its inputs have
98/// build ids, in order to prevent accidental mismatches.
99///
100/// The default is to not include this section because it slows down linking.
101///
102/// This option overrides the CLI argument passed to `zig build`.
103build_id: ?std.zig.BuildId = null,
104
105/// Create a .eh_frame_hdr section and a PT.GNU_EH_FRAME segment in the ELF
106/// file.
107link_eh_frame_hdr: bool = false,
108link_emit_relocs: bool = false,
109
110/// Place every function in its own section so that unused ones may be
111/// safely garbage-collected during the linking phase.
112link_function_sections: bool = false,
113
114/// Place every data in its own section so that unused ones may be
115/// safely garbage-collected during the linking phase.
116link_data_sections: bool = false,
117
118/// Remove functions and data that are unreachable by the entry point or
119/// exported symbols.
120link_gc_sections: ?bool = null,
121
122/// (Windows) Whether or not to enable ASLR. Maps to the /DYNAMICBASE[:NO] linker argument.
123linker_dynamicbase: bool = true,
124
125linker_allow_shlib_undefined: ?bool = null,
126
127/// Allow version scripts to refer to undefined symbols.
128linker_allow_undefined_version: ?bool = null,
129
130// Enable (or disable) the new DT_RUNPATH tag in the dynamic section.
131linker_enable_new_dtags: ?bool = null,
132
133/// Permit read-only relocations in read-only segments. Disallowed by default.
134link_z_notext: bool = false,
135
136/// Force all relocations to be read-only after processing.
137link_z_relro: bool = true,
138
139/// Allow relocations to be lazily processed after load.
140link_z_lazy: bool = false,
141
142/// Common page size
143link_z_common_page_size: ?u64 = null,
144
145/// Maximum page size
146link_z_max_page_size: ?u64 = null,
147
148/// Force a fatal error if any undefined symbols remain.
149link_z_defs: bool = false,
150
151/// (Darwin) Install name for the dylib
152install_name: ?[]const u8 = null,
153
154/// Must be passed in via `Options`.
155entitlements: ?LazyPath = null,
156
157/// (Darwin) Size of the pagezero segment.
158pagezero_size: ?u64 = null,
159
160/// (Darwin) Set size of the padding between the end of load commands
161/// and start of `__TEXT,__text` section.
162headerpad_size: ?u32 = null,
163
164/// (Darwin) Automatically Set size of the padding between the end of load commands
165/// and start of `__TEXT,__text` section to a value fitting all paths expanded to MAXPATHLEN.
166headerpad_max_install_names: bool = false,
167
168/// (Darwin) Remove dylibs that are unreachable by the entry point or exported symbols.
169dead_strip_dylibs: bool = false,
170
171/// (Darwin) Force load all members of static archives that implement an Objective-C class or category
172force_load_objc: bool = false,
173
174/// Whether local symbols should be discarded from the symbol table.
175discard_local_symbols: bool = false,
176
177/// Position Independent Executable
178pie: ?bool = null,
179
180/// Link Time Optimization mode
181lto: ?std.zig.LtoMode = null,
182
183dll_export_fns: ?bool = null,
184
185subsystem: ?std.zig.Subsystem = null,
186
187/// (Windows) When targeting the MinGW ABI, use the unicode entry point (wmain/wWinMain)
188mingw_unicode_entry_point: bool = false,
189
190/// How the linker must handle the entry point of the executable.
191entry: Entry = .default,
192
193/// List of symbols forced as undefined in the symbol table
194/// thus forcing their resolution by the linker.
195/// Corresponds to `-u <symbol>` for ELF/MachO and `/include:<symbol>` for COFF/PE.
196force_undefined_symbols: std.array_hash_map.String(void),
197
198/// Overrides the default stack size
199stack_size: ?u64 = null,
200
201use_llvm: ?bool,
202use_lld: ?bool,
203use_new_linker: ?bool,
204
205/// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI
206/// flags, overriding the global user setting provided to the `zig build`
207/// command.
208///
209/// The compiler defaults this value to off so that users whose system shared
210/// libraries are all ELF files don't have to pay the cost of checking every
211/// file to find out if it is a text file instead.
212allow_so_scripts: ?bool = null,
213
214/// This is an advanced setting that can change the intent of this Compile step.
215/// If this value is non-null, it means that this Compile step exists to
216/// check for compile errors and return *success* if they match, and failure
217/// otherwise.
218expect_errors: ?ExpectedCompileErrors = null,
219
220/// The maximum number of distinct errors within a compilation step Defaults to
221/// `std.math.maxInt(u16)`. Overrides the argument passed to `zig build`.
222error_limit: ?u32 = null,
223
224/// Enables coverage instrumentation that is only useful if you are using third
225/// party fuzzers that depend on it. Otherwise, slows down the instrumented
226/// binary with unnecessary function calls.
227///
228/// This kind of coverage instrumentation is used by AFLplusplus v4.21c,
229/// however, modern fuzzers - including Zig - have switched to using "inline
230/// 8-bit counters" or "inline bool flag" which incurs only a single
231/// instruction for coverage, along with "trace cmp" which instruments
232/// comparisons and reports the operands.
233///
234/// To instead enable fuzz testing instrumentation on a compilation using Zig's
235/// builtin fuzzer, see the `fuzz` flag in `Module`.
236sanitize_coverage_trace_pc_guard: ?bool = null,
237
238/// Enable or disable incremental compilation.
239///
240/// Incremental compilation reduces compile time by mutating an existing build artifact. Non-
241/// incremental compilation is slower but preserves previous build artifacts.
242incremental: ?bool = null,
243
244emit_directory: Configuration.OptionalGeneratedFileIndex = .none,
245generated_docs: Configuration.OptionalGeneratedFileIndex = .none,
246generated_asm: Configuration.OptionalGeneratedFileIndex = .none,
247generated_bin: Configuration.OptionalGeneratedFileIndex = .none,
248generated_pdb: Configuration.OptionalGeneratedFileIndex = .none,
249generated_implib: Configuration.OptionalGeneratedFileIndex = .none,
250generated_llvm_bc: Configuration.OptionalGeneratedFileIndex = .none,
251generated_llvm_ir: Configuration.OptionalGeneratedFileIndex = .none,
252generated_h: Configuration.OptionalGeneratedFileIndex = .none,
253
254pub const ExpectedCompileErrors = union(enum) {
255 contains: []const u8,
256 exact: []const []const u8,
257 starts_with: []const u8,
258 stderr_contains: []const u8,
259};
260
261pub const Entry = union(enum) {
262 /// Let the compiler decide whether to make an entry point and what to name
263 /// it.
264 default,
265 /// The executable will have no entry point.
266 disabled,
267 /// The executable will have an entry point with the default symbol name.
268 enabled,
269 /// The executable will have an entry point with the specified symbol name.
270 symbol_name: []const u8,
271};
272
273pub const Options = struct {
274 name: []const u8,
275 root_module: *Module,
276 kind: Kind,
277 linkage: ?std.builtin.LinkMode = null,
278 version: ?std.SemanticVersion = null,
279 max_rss: u64 = 0,
280 filters: []const []const u8 = &.{},
281 test_runner: ?TestRunner = null,
282 use_llvm: ?bool = null,
283 use_lld: ?bool = null,
284 zig_lib_dir: ?LazyPath = null,
285 /// Deprecated. This functionality will be moved to an external package:
286 /// https://codeberg.org/ziglang/rc
287 ///
288 /// Embed a `.manifest` file in the compilation if the object format supports it.
289 /// https://learn.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference
290 /// Manifest files must have the extension `.manifest`.
291 /// Can be set regardless of target. The `.manifest` file will be ignored
292 /// if the target object format does not support embedded manifests.
293 win32_manifest: ?LazyPath = null,
294 /// Win32 module definition file.
295 win32_module_definition: ?LazyPath = null,
296 /// (Darwin) Path to entitlements file
297 entitlements: ?LazyPath = null,
298};
299
300pub const Kind = Configuration.Step.Compile.Kind;
301
302pub const HeaderInstallation = union(enum) {
303 file: File,
304 directory: Directory,
305
306 pub const File = struct {
307 source: LazyPath,
308 dest_rel_path: []const u8,
309
310 pub fn dupe(file: File, graph: *const std.Build.Graph) File {
311 return .{
312 .source = file.source.dupe(graph),
313 .dest_rel_path = graph.dupePath(file.dest_rel_path),
314 };
315 }
316 };
317
318 pub const Directory = struct {
319 source: LazyPath,
320 dest_rel_path: []const u8,
321 options: Directory.Options,
322
323 pub const Options = struct {
324 /// File paths that end in any of these suffixes will be excluded from installation.
325 exclude_extensions: []const []const u8 = &.{},
326 /// Only file paths that end in any of these suffixes will be included in installation.
327 /// `null` means that all suffixes will be included.
328 /// `exclude_extensions` takes precedence over `include_extensions`.
329 include_extensions: ?[]const []const u8 = &.{".h"},
330
331 pub fn dupe(opts: Directory.Options, graph: *const std.Build.Graph) Directory.Options {
332 return .{
333 .exclude_extensions = graph.dupeStrings(opts.exclude_extensions),
334 .include_extensions = if (opts.include_extensions) |incs| graph.dupeStrings(incs) else null,
335 };
336 }
337 };
338
339 pub fn dupe(dir: Directory, graph: *const std.Build.Graph) Directory {
340 return .{
341 .source = dir.source.dupe(graph),
342 .dest_rel_path = graph.dupePath(dir.dest_rel_path),
343 .options = dir.options.dupe(graph),
344 };
345 }
346 };
347
348 pub fn getSource(installation: HeaderInstallation) LazyPath {
349 return switch (installation) {
350 inline .file, .directory => |x| x.source,
351 };
352 }
353
354 pub fn dupe(installation: HeaderInstallation, graph: *const std.Build.Graph) HeaderInstallation {
355 return switch (installation) {
356 .file => |f| .{ .file = f.dupe(graph) },
357 .directory => |d| .{ .directory = d.dupe(graph) },
358 };
359 }
360};
361
362pub const TestRunner = struct {
363 path: LazyPath,
364 /// Test runners can either be "simple", running tests when spawned and terminating when the
365 /// tests are complete, or they can use `std.zig.Server` over stdio to interact more closely
366 /// with the build system.
367 mode: enum { simple, server },
368};
369
370pub fn create(owner: *std.Build, options: Options) *Compile {
371 const graph = owner.graph;
372 const arena = graph.arena;
373
374 const name = owner.graph.dupeString(options.name);
375 if (mem.find(u8, name, "/") != null or mem.find(u8, name, "\\") != null) {
376 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
377 }
378
379 const resolved_target = options.root_module.resolved_target orelse
380 @panic("the root Module of a Compile step must be created with a known 'target' field");
381 const target = &resolved_target.result;
382
383 const step_name = owner.fmt("compile {s} {s} {s}", .{
384 // Avoid the common case of the step name looking like "compile test test".
385 if (options.kind.isTest() and mem.eql(u8, name, "test"))
386 @tagName(options.kind)
387 else
388 owner.fmt("{t} {s}", .{ options.kind, name }),
389 @tagName(options.root_module.optimize orelse .debug),
390 resolved_target.query.zigTriple(arena) catch @panic("OOM"),
391 });
392
393 const out_filename = std.zig.binNameAlloc(arena, .{
394 .root_name = name,
395 .cpu_arch = target.cpu.arch,
396 .os_tag = target.os.tag,
397 .ofmt = target.ofmt,
398 .abi = target.abi,
399 .output_mode = switch (options.kind) {
400 .lib => .Lib,
401 .obj, .test_obj => .Obj,
402 .exe, .@"test" => .Exe,
403 },
404 .link_mode = options.linkage,
405 .version = options.version,
406 }) catch @panic("OOM");
407
408 const compile = arena.create(Compile) catch @panic("OOM");
409 compile.* = .{
410 .root_module = options.root_module,
411 .verbose_link = false,
412 .verbose_cc = false,
413 .linkage = options.linkage,
414 .kind = options.kind,
415 .name = name,
416 .step = .init(.{
417 .tag = base_tag,
418 .name = step_name,
419 .owner = owner,
420 .max_rss = options.max_rss,
421 }),
422 .version = options.version,
423 .out_filename = out_filename,
424 .installed_headers = .empty,
425 .zig_lib_dir = null,
426 .filters = options.filters,
427 .test_runner = null, // set below
428 .rdynamic = false,
429 .force_undefined_symbols = .empty,
430
431 .use_llvm = options.use_llvm,
432 .use_lld = options.use_lld,
433 .use_new_linker = null,
434 };
435
436 if (options.zig_lib_dir) |lp| {
437 compile.zig_lib_dir = lp.dupe(graph);
438 lp.addStepDependencies(&compile.step);
439 }
440
441 if (options.test_runner) |runner| {
442 compile.test_runner = .{
443 .path = runner.path.dupe(graph),
444 .mode = runner.mode,
445 };
446 runner.path.addStepDependencies(&compile.step);
447 }
448
449 // Only the PE/COFF format has a Resource Table which is where the manifest
450 // gets embedded, so for any other target the manifest file is just ignored.
451 if (target.ofmt == .coff) {
452 if (options.win32_manifest) |lp| {
453 compile.win32_manifest = lp.dupe(graph);
454 lp.addStepDependencies(&compile.step);
455 }
456 if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) {
457 // Building a Win32 DLL, check for win32 .def file.
458 if (options.win32_module_definition) |lp| {
459 compile.win32_module_definition = lp.dupe(graph);
460 lp.addStepDependencies(&compile.step);
461 }
462 }
463 }
464
465 if (options.entitlements) |lp| {
466 compile.entitlements = lp.dupe(graph);
467 lp.addStepDependencies(&compile.step);
468 }
469
470 return compile;
471}
472
473/// Marks the specified header for installation alongside this artifact.
474/// When a module links with this artifact, all headers marked for installation are added to that
475/// module's include search path.
476pub fn installHeader(cs: *Compile, source: LazyPath, dest_rel_path: []const u8) void {
477 const graph = cs.step.owner.graph;
478 const arena = graph.arena;
479 const installation: HeaderInstallation = .{ .file = .{
480 .source = source.dupe(graph),
481 .dest_rel_path = graph.dupePath(dest_rel_path),
482 } };
483 cs.installed_headers.append(arena, installation) catch @panic("OOM");
484 cs.addHeaderInstallationToIncludeTree(installation);
485 installation.getSource().addStepDependencies(&cs.step);
486}
487
488/// Marks headers from the specified directory for installation alongside this artifact.
489/// When a module links with this artifact, all headers marked for installation are added to that
490/// module's include search path.
491pub fn installHeadersDirectory(
492 cs: *Compile,
493 source: LazyPath,
494 dest_rel_path: []const u8,
495 options: HeaderInstallation.Directory.Options,
496) void {
497 const graph = cs.step.owner.graph;
498 const arena = graph.arena;
499 const installation: HeaderInstallation = .{ .directory = .{
500 .source = source.dupe(graph),
501 .dest_rel_path = graph.dupePath(dest_rel_path),
502 .options = options.dupe(graph),
503 } };
504 cs.installed_headers.append(arena, installation) catch @panic("OOM");
505 cs.addHeaderInstallationToIncludeTree(installation);
506 installation.getSource().addStepDependencies(&cs.step);
507}
508
509/// Marks the specified config header for installation alongside this artifact.
510/// When a module links with this artifact, all headers marked for installation are added to that
511/// module's include search path.
512pub fn installConfigHeader(cs: *Compile, config_header: *Step.ConfigHeader) void {
513 cs.installHeader(config_header.getOutputFile(), config_header.include_path);
514}
515
516/// Forwards all headers marked for installation from `lib` to this artifact.
517/// When a module links with this artifact, all headers marked for installation are added to that
518/// module's include search path.
519pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void {
520 assert(lib.kind == .lib);
521 const graph = cs.step.owner.graph;
522 const arena = graph.arena;
523 for (lib.installed_headers.items) |installation| {
524 const installation_copy = installation.dupe(graph);
525 cs.installed_headers.append(arena, installation_copy) catch @panic("OOM");
526 cs.addHeaderInstallationToIncludeTree(installation_copy);
527 installation_copy.getSource().addStepDependencies(&cs.step);
528 }
529}
530
531fn addHeaderInstallationToIncludeTree(cs: *Compile, installation: HeaderInstallation) void {
532 if (cs.installed_headers_include_tree) |wf| switch (installation) {
533 .file => |file| {
534 _ = wf.addCopyFile(file.source, file.dest_rel_path);
535 },
536 .directory => |dir| {
537 _ = wf.addCopyDirectory(dir.source, dir.dest_rel_path, .{
538 .exclude_extensions = dir.options.exclude_extensions,
539 .include_extensions = dir.options.include_extensions,
540 });
541 },
542 };
543}
544
545pub fn getEmittedIncludeTree(cs: *Compile) LazyPath {
546 if (cs.installed_headers_include_tree) |wf| return wf.getDirectory();
547 const b = cs.step.owner;
548 const wf = b.addWriteFiles();
549 cs.installed_headers_include_tree = wf;
550 for (cs.installed_headers.items) |installation| {
551 cs.addHeaderInstallationToIncludeTree(installation);
552 }
553 // The compile step itself does not need to depend on the write files step,
554 // only dependent modules do.
555 return wf.getDirectory();
556}
557
558pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy {
559 const b = cs.step.owner;
560 var copy = options;
561 if (copy.basename == null) {
562 if (options.format) |f| {
563 copy.basename = b.fmt("{s}.{s}", .{ cs.name, @tagName(f) });
564 } else {
565 copy.basename = cs.name;
566 }
567 }
568 return b.addObjCopy(cs.getEmittedBin(), copy);
569}
570
571pub fn setLinkerScript(compile: *Compile, source: LazyPath) void {
572 const graph = compile.step.owner.graph;
573 compile.linker_script = source.dupe(graph);
574 source.addStepDependencies(&compile.step);
575}
576
577pub fn setVersionScript(compile: *Compile, source: LazyPath) void {
578 const graph = compile.step.owner.graph;
579 compile.version_script = source.dupe(graph);
580 source.addStepDependencies(&compile.step);
581}
582
583pub fn forceUndefinedSymbol(compile: *Compile, symbol_name: []const u8) void {
584 const graph = compile.step.owner.graph;
585 const arena = graph.arena;
586 compile.force_undefined_symbols.put(arena, graph.dupeString(symbol_name), {}) catch @panic("OOM");
587}
588
589/// Returns whether the library, executable, or object depends on a particular system library.
590/// Includes transitive dependencies.
591pub fn dependsOnSystemLibrary(compile: *Compile, name: []const u8) bool {
592 var is_linking_libc = false;
593 var is_linking_libcpp = false;
594
595 for (compile.getCompileDependencies(true)) |some_compile| {
596 for (some_compile.root_module.getGraph().modules) |mod| {
597 for (mod.link_objects.items) |lo| {
598 switch (lo) {
599 .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
600 else => {},
601 }
602 }
603 if (mod.link_libc orelse false) is_linking_libc = true;
604 if (mod.link_libcpp orelse false) is_linking_libcpp = true;
605 }
606 }
607
608 const target = compile.rootModuleTarget();
609
610 if (std.zig.target.isLibCLibName(&target, name)) {
611 return is_linking_libc;
612 }
613
614 if (std.zig.target.isLibCxxLibName(&target, name)) {
615 return is_linking_libcpp;
616 }
617
618 return false;
619}
620
621pub fn isDynamicLibrary(compile: *const Compile) bool {
622 return compile.kind == .lib and compile.linkage == .dynamic;
623}
624
625pub fn isStaticLibrary(compile: *const Compile) bool {
626 return compile.kind == .lib and compile.linkage != .dynamic;
627}
628
629pub fn isDll(compile: *Compile) bool {
630 return compile.isDynamicLibrary() and compile.rootModuleTarget().os.tag == .windows;
631}
632
633pub fn producesPdbFile(compile: *Compile) bool {
634 const target = compile.rootModuleTarget();
635 // TODO: Is this right? Isn't PDB for *any* PE/COFF file?
636 // TODO: just share this logic with the compiler, silly!
637 switch (target.os.tag) {
638 .windows, .uefi => {},
639 else => return false,
640 }
641 if (target.ofmt == .c) return false;
642 if (compile.use_llvm == false) return false;
643 if (compile.root_module.strip == true or
644 (compile.root_module.strip == null and compile.root_module.optimize == .small))
645 {
646 return false;
647 }
648 return compile.isDynamicLibrary() or compile.kind == .exe or compile.kind == .@"test";
649}
650
651pub fn producesCompilerRtDynLib(compile: *Compile) bool {
652 if (compile.rootModuleTarget().ofmt != .coff) return false;
653 if (compile.bundle_compiler_rt orelse (compile.kind == .exe or compile.isDynamicLibrary()))
654 return compile.use_llvm == false;
655 return false;
656}
657
658pub fn producesImplib(compile: *Compile) bool {
659 return compile.isDll();
660}
661
662pub fn setVerboseLink(compile: *Compile, value: bool) void {
663 compile.verbose_link = value;
664}
665
666pub fn setVerboseCC(compile: *Compile, value: bool) void {
667 compile.verbose_cc = value;
668}
669
670pub fn setLibCFile(compile: *Compile, libc_file: ?LazyPath) void {
671 const graph = compile.step.owner.graph;
672 if (libc_file) |f| {
673 compile.libc_file = f.dupe(graph);
674 f.addStepDependencies(&compile.step);
675 } else {
676 compile.libc_file = null;
677 }
678}
679
680fn getEmittedFileGeneric(compile: *Compile, output_file: *Configuration.OptionalGeneratedFileIndex) LazyPath {
681 if (output_file.unwrap()) |index| return .{ .generated = .{ .index = index } };
682 const graph = compile.step.owner.graph;
683 const index = graph.addGeneratedFile(&compile.step);
684 output_file.* = .init(index);
685 return .{ .generated = .{ .index = index } };
686}
687
688/// Returns the path to the directory that contains the emitted binary file.
689pub fn getEmittedBinDirectory(compile: *Compile) LazyPath {
690 _ = compile.getEmittedBin();
691 return compile.getEmittedFileGeneric(&compile.emit_directory);
692}
693
694/// Returns the path to the generated executable, library or object file.
695/// To run an executable built with zig build, use `run`, or create an install step and invoke it.
696pub fn getEmittedBin(compile: *Compile) LazyPath {
697 return compile.getEmittedFileGeneric(&compile.generated_bin);
698}
699
700/// Returns the path to the generated import library.
701/// This function can only be called for libraries.
702pub fn getEmittedImplib(compile: *Compile) LazyPath {
703 assert(compile.kind == .lib);
704 return compile.getEmittedFileGeneric(&compile.generated_implib);
705}
706
707/// Returns the path to the generated header file.
708/// This function can only be called for libraries or objects.
709pub fn getEmittedH(compile: *Compile) LazyPath {
710 assert(compile.kind != .exe and compile.kind != .@"test");
711 return compile.getEmittedFileGeneric(&compile.generated_h);
712}
713
714/// Returns the generated PDB file.
715/// If the compilation does not produce a PDB file, this causes a FileNotFound error
716/// at build time.
717pub fn getEmittedPdb(compile: *Compile) LazyPath {
718 _ = compile.getEmittedBin();
719 return compile.getEmittedFileGeneric(&compile.generated_pdb);
720}
721
722/// Returns the path to the generated documentation directory.
723pub fn getEmittedDocs(compile: *Compile) LazyPath {
724 return compile.getEmittedFileGeneric(&compile.generated_docs);
725}
726
727/// Returns the path to the generated assembly code.
728pub fn getEmittedAsm(compile: *Compile) LazyPath {
729 return compile.getEmittedFileGeneric(&compile.generated_asm);
730}
731
732/// Returns the path to the generated LLVM IR.
733pub fn getEmittedLlvmIr(compile: *Compile) LazyPath {
734 return compile.getEmittedFileGeneric(&compile.generated_llvm_ir);
735}
736
737/// Returns the path to the generated LLVM BC.
738pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
739 return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);
740}
741
742pub fn rootModuleTarget(c: *Compile) std.Target {
743 // The root module is always given a target, so we know this to be non-null.
744 return c.root_module.resolved_target.?.result;
745}
746
747/// Return the full set of `Step.Compile` which `start` depends on, recursively. `start` itself is
748/// always returned as the first element. If `chase_dynamic` is `false`, then dynamic libraries are
749/// not included, and their dependencies are not considered; if `chase_dynamic` is `true`, dynamic
750/// libraries are treated the same as other linked `Compile`s.
751pub fn getCompileDependencies(start: *Compile, chase_dynamic: bool) []const *Compile {
752 const arena = start.step.owner.graph.arena;
753
754 var compiles: std.array_hash_map.Auto(*Compile, void) = .empty;
755 var next_idx: usize = 0;
756
757 compiles.putNoClobber(arena, start, {}) catch @panic("OOM");
758
759 while (next_idx < compiles.count()) {
760 const compile = compiles.keys()[next_idx];
761 next_idx += 1;
762
763 for (compile.root_module.getGraph().modules) |mod| {
764 for (mod.link_objects.items) |lo| {
765 switch (lo) {
766 .other_step => |other_compile| {
767 if (!chase_dynamic and other_compile.isDynamicLibrary()) continue;
768 compiles.put(arena, other_compile, {}) catch @panic("OOM");
769 },
770 else => {},
771 }
772 }
773 }
774 }
775
776 return compiles.keys();
777}