1//! User-specified settings that have all the defaults resolved into concrete
2//! values. These values are observable before calling Compilation.create for
3//! the benefit of Module creation API, which needs access to these details in
4//! order to resolve per-Module defaults.
5
6have_zcu: bool,
7output_mode: std.lang.OutputMode,
8link_mode: std.lang.LinkMode,
9link_libc: bool,
10link_libcpp: bool,
11link_libunwind: bool,
12/// True if and only if the c_source_files field will have nonzero length when
13/// calling Compilation.create.
14any_c_source_files: bool,
15/// This is `true` if any `Module` has `unwind_tables` set explicitly to a
16/// value other than `.none`. Until `Compilation.create()` is called, it is
17/// possible for this to be `false` while in fact all `Module` instances have
18/// `unwind_tables != .none` due to the default. After `Compilation.create()` is
19/// called, this will also take into account the default setting, making this
20/// value `true` if and only if any `Module` has `unwind_tables != .none`.
21any_unwind_tables: bool,
22/// This is true if any Module has single_threaded set explicitly to false. Until
23/// Compilation.create is called, it is possible for this to be false while in
24/// fact all Module instances have single_threaded=false due to the default
25/// being non-single-threaded. After Compilation.create is called this will
26/// also take into account the default setting, making this value true if and
27/// only if any Module has single_threaded set to false.
28any_non_single_threaded: bool,
29/// This is true if and only if any Module has error_tracing set to true.
30/// Function types and function calling convention depend on this global value,
31/// however, other kinds of error tracing are omitted depending on the
32/// per-Module setting.
33any_error_tracing: bool,
34any_sanitize_thread: bool,
35any_sanitize_c: std.zig.SanitizeC,
36any_fuzz: bool,
37/// If this is true then linker code is responsible for making an LLVM IR
38/// Module, outputting it to an object file, and then linking that together
39/// with link options and other objects. Otherwise (depending on `use_lld`)
40/// linker code directly outputs and updates the final binary.
41use_llvm: bool,
42/// Whether or not the LLVM library API will be used by the LLVM backend.
43use_lib_llvm: bool,
44/// If this is true then linker code is responsible for outputting an object
45/// file and then using LLD to link it together with the link options and other
46/// objects. Otherwise (depending on `use_llvm`) linker code directly outputs
47/// and updates the final binary.
48use_lld: bool,
49c_frontend: CFrontend,
50use_new_linker: bool,
51pie: bool,
52lto: std.zig.LtoMode,
53incremental: bool,
54/// WASI-only. Type of WASI execution model ("command" or "reactor").
55/// Always set to `command` for non-WASI targets.
56wasi_exec_model: std.lang.WasiExecModel,
57import_memory: bool,
58export_memory: bool,
59shared_memory: bool,
60is_test: bool,
61debug_format: DebugFormat,
62root_optimize_mode: std.lang.Optimize,
63root_strip: bool,
64root_error_tracing: bool,
65dll_export_fns: bool,
66rdynamic: bool,
67san_cov_trace_pc_guard: bool,
68
69pub const CFrontend = enum { clang, aro };
70
71pub const DebugFormat = union(enum) {
72 strip,
73 dwarf: std.dwarf.Format,
74 code_view,
75};
76
77pub const Options = struct {
78 output_mode: std.lang.OutputMode,
79 resolved_target: Module.ResolvedTarget,
80 is_test: bool,
81 have_zcu: bool,
82 emit_bin: bool,
83 root_optimize_mode: ?std.lang.Optimize = null,
84 root_strip: ?bool = null,
85 root_error_tracing: ?bool = null,
86 link_mode: ?std.lang.LinkMode = null,
87 ensure_libc_on_non_freestanding: bool = false,
88 ensure_libcpp_on_non_freestanding: bool = false,
89 any_non_single_threaded: bool = false,
90 any_sanitize_thread: bool = false,
91 any_sanitize_c: std.zig.SanitizeC = .off,
92 any_fuzz: bool = false,
93 any_unwind_tables: bool = false,
94 any_dyn_libs: bool = false,
95 any_c_source_files: bool = false,
96 any_non_stripped: bool = false,
97 any_error_tracing: bool = false,
98 emit_llvm_ir: bool = false,
99 emit_llvm_bc: bool = false,
100 link_libc: ?bool = null,
101 link_libcpp: ?bool = null,
102 link_libunwind: ?bool = null,
103 use_llvm: ?bool = null,
104 use_lib_llvm: ?bool = null,
105 use_lld: ?bool = null,
106 use_clang: ?bool = null,
107 use_new_linker: ?bool = null,
108 pie: ?bool = null,
109 lto: ?std.zig.LtoMode = null,
110 incremental: bool = false,
111 /// WASI-only. Type of WASI execution model ("command" or "reactor").
112 wasi_exec_model: ?std.lang.WasiExecModel = null,
113 import_memory: ?bool = null,
114 export_memory: ?bool = null,
115 shared_memory: ?bool = null,
116 debug_format: ?DebugFormat = null,
117 dll_export_fns: ?bool = null,
118 rdynamic: ?bool = null,
119 san_cov_trace_pc_guard: bool = false,
120};
121
122pub const ResolveError = error{
123 WasiExecModelRequiresWasi,
124 SharedMemoryIsWasmOnly,
125 ObjectFilesCannotShareMemory,
126 SharedMemoryRequiresAtomicsAndBulkMemory,
127 ThreadsRequireSharedMemory,
128 EmittingLlvmModuleRequiresLlvmBackend,
129 LlvmLacksTargetSupport,
130 ZigLacksTargetSupport,
131 EmittingBinaryRequiresLlvmLibrary,
132 LldIncompatibleObjectFormat,
133 LldIncompatibleWithSelfHostedBackend,
134 LtoRequiresLld,
135 SanitizeThreadRequiresLibCpp,
136 LibCRequiresLibUnwind,
137 LibCppRequiresLibUnwind,
138 LibCppRequiresLibC,
139 LibUnwindRequiresLibC,
140 TargetCannotDynamicLink,
141 TargetCannotStaticLinkExecutables,
142 LibCRequiresDynamicLinking,
143 SharedLibrariesRequireDynamicLinking,
144 DynamicLinkingWithLldRequiresSharedLibraries,
145 ExportMemoryAndDynamicIncompatible,
146 DynamicLibraryPrecludesPie,
147 TargetRequiresPie,
148 SanitizeThreadRequiresPie,
149 SanitizeThreadRequiresLlvmBackend,
150 BackendLacksErrorTracing,
151 LlvmLibraryUnavailable,
152 LldUnavailable,
153 ClangUnavailable,
154 DllExportFnsRequiresWindows,
155 NewLinkerIncompatibleWithLld,
156 NewLinkerIncompatibleObjectFormat,
157};
158
159pub fn resolve(options: Options) ResolveError!Config {
160 const target = &options.resolved_target.result;
161
162 // WASI-only. Resolve the optional exec-model option, defaults to command.
163 if (target.os.tag != .wasi and options.wasi_exec_model != null)
164 return error.WasiExecModelRequiresWasi;
165 const wasi_exec_model = options.wasi_exec_model orelse .command;
166
167 const shared_memory = b: {
168 if (!target.cpu.arch.isWasm()) {
169 if (options.shared_memory == true) return error.SharedMemoryIsWasmOnly;
170 break :b false;
171 }
172 if (options.output_mode == .Obj) {
173 if (options.shared_memory == true) return error.ObjectFilesCannotShareMemory;
174 break :b false;
175 }
176 if (!target.cpu.hasAll(.wasm, &.{ .atomics, .bulk_memory })) {
177 if (options.shared_memory == true)
178 return error.SharedMemoryRequiresAtomicsAndBulkMemory;
179 break :b false;
180 }
181 if (options.any_non_single_threaded) {
182 if (options.shared_memory == false)
183 return error.ThreadsRequireSharedMemory;
184 break :b true;
185 }
186 break :b options.shared_memory orelse false;
187 };
188
189 // *If* the LLVM backend were to be selected, should Zig use the LLVM
190 // library to build the LLVM module?
191 const use_lib_llvm = b: {
192 if (!build_options.have_llvm) {
193 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;
194 break :b false;
195 }
196 break :b options.use_lib_llvm orelse true;
197 };
198
199 const root_optimize_mode = options.root_optimize_mode orelse .debug;
200
201 // Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
202 const c_frontend: CFrontend = b: {
203 if (!build_options.have_llvm) {
204 if (options.use_clang == true) return error.ClangUnavailable;
205 break :b .aro;
206 }
207 if (options.use_clang) |clang| {
208 break :b if (clang) .clang else .aro;
209 }
210 break :b .clang;
211 };
212
213 const link_libcpp = b: {
214 if (options.link_libcpp == true) break :b true;
215 if (options.any_sanitize_thread) {
216 // TSAN is (for now...) implemented in C++ so it requires linking libc++.
217 if (options.link_libcpp == false) return error.SanitizeThreadRequiresLibCpp;
218 break :b true;
219 }
220 if (options.ensure_libcpp_on_non_freestanding and target.os.tag != .freestanding)
221 break :b true;
222
223 break :b false;
224 };
225
226 const link_libc = b: {
227 if (link_libcpp) {
228 if (options.link_libc == false) return error.LibCppRequiresLibC;
229 break :b true;
230 }
231 if (options.link_libunwind == true) {
232 if (options.link_libc == false) return error.LibUnwindRequiresLibC;
233 break :b true;
234 }
235 if (options.link_libc) |x| break :b x;
236 if (options.ensure_libc_on_non_freestanding and target.os.tag != .freestanding)
237 break :b true;
238
239 break :b std.os.targetRequiresLibC(target);
240 };
241
242 const link_mode = b: {
243 const explicitly_exe_or_dyn_lib = switch (options.output_mode) {
244 .Obj => false,
245 .Lib => (options.link_mode orelse .static) == .dynamic,
246 .Exe => true,
247 };
248
249 if (!target_util.canDynamicLink(target)) {
250 if (options.link_mode == .dynamic) return error.TargetCannotDynamicLink;
251 break :b .static;
252 }
253 if (!target_util.canStaticLinkExe(target) and options.output_mode == .Exe) {
254 if (options.link_mode == .static) return error.TargetCannotStaticLinkExecutables;
255 break :b .dynamic;
256 }
257 if (explicitly_exe_or_dyn_lib and link_libc and
258 (target.requiresLibC() or
259 // For these libcs, Zig can only provide dynamic libc when cross-compiling.
260 ((target.isGnuLibC() or target.isFreeBSDLibC() or target.isNetBSDLibC() or target.isOpenBSDLibC()) and
261 !options.resolved_target.is_native_abi)))
262 {
263 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;
264 break :b .dynamic;
265 }
266
267 if (options.link_mode) |link_mode| break :b link_mode;
268
269 if (options.any_dyn_libs) break :b .dynamic;
270
271 if (explicitly_exe_or_dyn_lib and link_libc) {
272 // When using the native glibc/musl ABI, dynamic linking is usually what people want.
273 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {
274 break :b .dynamic;
275 }
276
277 // When targeting systems where the kernel and libc are developed alongside each other,
278 // dynamic linking is the better default; static libc may contain code that requires
279 // the very latest kernel version.
280 if (target.isFreeBSDLibC() or target.isNetBSDLibC() or target.isOpenBSDLibC()) {
281 break :b .dynamic;
282 }
283 }
284
285 // Static is generally a better default. Fight me.
286 break :b .static;
287 };
288
289 const link_libunwind = b: {
290 if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {
291 if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;
292 break :b true;
293 }
294 if (link_libcpp and target_util.libCxxNeedsLibUnwind(target)) {
295 if (options.link_libunwind == false) return error.LibCppRequiresLibUnwind;
296 break :b true;
297 }
298 break :b options.link_libunwind orelse false;
299 };
300
301 const import_memory = options.import_memory orelse (options.output_mode == .Obj);
302 const export_memory = b: {
303 if (link_mode == .dynamic) {
304 if (options.export_memory == true) return error.ExportMemoryAndDynamicIncompatible;
305 break :b false;
306 }
307 if (options.export_memory) |x| break :b x;
308 break :b !import_memory;
309 };
310
311 const is_dyn_lib = switch (options.output_mode) {
312 .Obj, .Exe => false,
313 .Lib => link_mode == .dynamic,
314 };
315
316 // Make a decision on whether to use LLVM backend for machine code generation.
317 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.
318 // For example, Zig can emit .bc and .ll files directly, and this is still considered
319 // using "the LLVM backend".
320 const use_llvm = b: {
321 // If we have no zig code to compile, no need for LLVM.
322 if (!options.have_zcu) break :b false;
323
324 // If emitting to LLVM bitcode object format, must use LLVM backend.
325 if (options.emit_llvm_ir or options.emit_llvm_bc) {
326 if (options.use_llvm == false)
327 return error.EmittingLlvmModuleRequiresLlvmBackend;
328 if (!target_util.hasLlvmSupport(target, target.ofmt))
329 return error.LlvmLacksTargetSupport;
330
331 break :b true;
332 }
333
334 // If LLVM does not support the target, then we can't use it.
335 if (!target_util.hasLlvmSupport(target, target.ofmt)) {
336 if (options.use_llvm == true) return error.LlvmLacksTargetSupport;
337 break :b false;
338 }
339
340 // If Zig does not support the target, then we can't use it.
341 if (target_util.zigBackend(target, false) == .other) {
342 if (options.use_llvm == false) return error.ZigLacksTargetSupport;
343 break :b true;
344 }
345
346 if (options.any_sanitize_thread) {
347 // Thread sanitization instrumentation requires the LLVM backend.
348 if (options.use_llvm == false) return error.SanitizeThreadRequiresLlvmBackend;
349 break :b true;
350 }
351
352 if (options.use_llvm) |x| break :b x;
353
354 // If we cannot use LLVM libraries, then our own backends will be a
355 // better default since the LLVM backend can only produce bitcode
356 // and not an object file or executable.
357 if (!use_lib_llvm and options.emit_bin) break :b false;
358
359 // Prefer LLVM for release builds.
360 if (root_optimize_mode != .debug) break :b true;
361
362 // load_dynamic_library standalone test not passing on this combination
363 // https://github.com/ziglang/zig/issues/24080
364 if (target.os.tag.isDarwin() and is_dyn_lib) break :b true;
365
366 // At this point we would prefer to use our own self-hosted backend,
367 // because the compilation speed is better than LLVM. But only do it if
368 // we are confident in the robustness of the backend.
369 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
370 };
371 const backend = target_util.zigBackend(target, use_llvm);
372
373 if (options.emit_bin and options.have_zcu) {
374 if (!use_lib_llvm and use_llvm) {
375 // Explicit request to use LLVM to produce an object file, but without
376 // using LLVM libraries. Impossible.
377 return error.EmittingBinaryRequiresLlvmLibrary;
378 }
379
380 if (backend == .other) {
381 // There is no compiler backend available for this target.
382 return error.ZigLacksTargetSupport;
383 }
384 }
385
386 // Make a decision on whether to use LLD or our own linker.
387 const use_lld = b: {
388 if (!target_util.hasLldSupport(target.ofmt)) {
389 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
390 break :b false;
391 }
392
393 if (!build_options.have_llvm) {
394 if (options.use_lld == true) return error.LldUnavailable;
395 break :b false;
396 }
397
398 if (options.lto != null and options.lto != .none) {
399 if (options.use_lld == false) return error.LtoRequiresLld;
400 break :b true;
401 }
402
403 // If we have Zig code (i.e. a ZCU) and are compiling with a self-hosted backend, then we
404 // also need to use a self-hosted linker.
405 if (options.have_zcu and !use_llvm) {
406 if (options.use_lld == true) return error.LldIncompatibleWithSelfHostedBackend;
407 break :b false;
408 }
409
410 if (options.use_lld) |x| break :b x;
411
412 // If the user didn't specify whether to use LLD but did specify to use the new linker,
413 // assume no LLD.
414 if (options.use_new_linker == true) break :b false;
415
416 // If we have no zig code to compile, no need for the self-hosted linker.
417 if (!options.have_zcu) break :b true;
418
419 // If we do have zig code, match the decision for whether to use the llvm backend,
420 // so that the llvm backend defaults to lld and the self-hosted backends do not.
421 break :b use_llvm;
422 };
423
424 switch (options.output_mode) {
425 .Exe => if (options.any_dyn_libs) {
426 // When creating a executable that links to system libraries, we
427 // require dynamic linking, but we must not link static libraries
428 // or object files dynamically!
429 if (link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
430 } else if (use_lld and !link_libc and !link_libcpp and !link_libunwind) {
431 // Lld does not support creating dynamic executables when not
432 // linking to any shared libraries.
433 if (link_mode == .dynamic) return error.DynamicLinkingWithLldRequiresSharedLibraries;
434 },
435 .Lib, .Obj => {},
436 }
437
438 const use_new_linker = b: {
439 if (use_lld) {
440 if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;
441 break :b false;
442 }
443
444 if (!target_util.hasNewLinker(target.ofmt)) {
445 if (options.use_new_linker == true) return error.NewLinkerIncompatibleObjectFormat;
446 break :b false;
447 }
448
449 if (options.use_new_linker) |x| break :b x;
450
451 break :b options.incremental;
452 };
453
454 const pie = b: {
455 switch (options.output_mode) {
456 .Exe => if (target_util.requiresPie(target, link_mode)) {
457 if (options.pie == false) return error.TargetRequiresPie;
458 break :b true;
459 },
460 .Lib => if (link_mode == .dynamic) {
461 if (options.pie == true) return error.DynamicLibraryPrecludesPie;
462 break :b false;
463 },
464 .Obj => {},
465 }
466 if (options.any_sanitize_thread) {
467 if (options.pie == false) return error.SanitizeThreadRequiresPie;
468 break :b true;
469 }
470 if (options.pie) |pie| break :b pie;
471 break :b if (options.output_mode == .Exe) target_util.defaultPie(target) else false;
472 };
473
474 const lto: std.zig.LtoMode = b: {
475 if (!use_lld) {
476 // zig ld LTO support is tracked by
477 // https://github.com/ziglang/zig/issues/8680
478 if (options.lto != null and options.lto != .none) return error.LtoRequiresLld;
479 break :b .none;
480 }
481
482 if (options.lto) |x| break :b x;
483
484 break :b .none;
485 };
486
487 const root_strip = b: {
488 if (options.root_strip) |x| break :b x;
489 if (root_optimize_mode == .small) break :b true;
490 if (!target_util.hasDebugInfo(target)) break :b true;
491 break :b false;
492 };
493
494 const debug_format: DebugFormat = b: {
495 if (root_strip and !options.any_non_stripped) break :b .strip;
496 if (options.debug_format) |x| break :b x;
497 break :b switch (target.ofmt) {
498 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
499 .coff => .code_view,
500 .c => switch (target.os.tag) {
501 .windows, .uefi => .code_view,
502 else => .{ .dwarf = .@"32" },
503 },
504 .spirv, .hex, .raw, .plan9 => .strip,
505 };
506 };
507
508 const backend_supports_error_tracing = target_util.backendSupportsFeature(backend, .error_return_trace);
509
510 const root_error_tracing = b: {
511 if (options.root_error_tracing) |x| break :b x;
512 if (root_strip) break :b false;
513 if (!backend_supports_error_tracing) break :b false;
514 break :b switch (root_optimize_mode) {
515 .debug => true,
516 .safe, .fast, .small => false,
517 };
518 };
519
520 const any_error_tracing = root_error_tracing or options.any_error_tracing;
521 if (any_error_tracing and !backend_supports_error_tracing)
522 return error.BackendLacksErrorTracing;
523
524 const rdynamic = options.rdynamic orelse false;
525
526 const dll_export_fns = b: {
527 if (target.os.tag != .windows) {
528 if (options.dll_export_fns == true)
529 return error.DllExportFnsRequiresWindows;
530 break :b false;
531 }
532 if (options.dll_export_fns) |x| break :b x;
533 if (rdynamic) break :b true;
534 break :b switch (options.output_mode) {
535 .Obj, .Exe => false,
536 .Lib => link_mode == .dynamic,
537 };
538 };
539
540 return .{
541 .output_mode = options.output_mode,
542 .have_zcu = options.have_zcu,
543 .is_test = options.is_test,
544 .link_mode = link_mode,
545 .link_libc = link_libc,
546 .link_libcpp = link_libcpp,
547 .link_libunwind = link_libunwind,
548 .any_unwind_tables = options.any_unwind_tables,
549 .any_c_source_files = options.any_c_source_files,
550 .any_non_single_threaded = options.any_non_single_threaded,
551 .any_error_tracing = any_error_tracing,
552 .any_sanitize_thread = options.any_sanitize_thread,
553 .any_sanitize_c = options.any_sanitize_c,
554 .any_fuzz = options.any_fuzz,
555 .san_cov_trace_pc_guard = options.san_cov_trace_pc_guard,
556 .root_error_tracing = root_error_tracing,
557 .use_new_linker = use_new_linker,
558 .pie = pie,
559 .lto = lto,
560 .incremental = options.incremental,
561 .import_memory = import_memory,
562 .export_memory = export_memory,
563 .shared_memory = shared_memory,
564 .c_frontend = c_frontend,
565 .use_llvm = use_llvm,
566 .use_lib_llvm = use_lib_llvm,
567 .use_lld = use_lld,
568 .wasi_exec_model = wasi_exec_model,
569 .debug_format = debug_format,
570 .root_optimize_mode = root_optimize_mode,
571 .root_strip = root_strip,
572 .dll_export_fns = dll_export_fns,
573 .rdynamic = rdynamic,
574 };
575}
576
577const std = @import("std");
578const Module = @import("../Module.zig");
579const Config = @This();
580const target_util = @import("../target.zig");
581const build_options = @import("build_options");