master
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.builtin.OutputMode,
8link_mode: std.builtin.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.builtin.WasiExecModel,
57import_memory: bool,
58export_memory: bool,
59shared_memory: bool,
60is_test: bool,
61debug_format: DebugFormat,
62root_optimize_mode: std.builtin.OptimizeMode,
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.builtin.OutputMode,
79 resolved_target: Module.ResolvedTarget,
80 is_test: bool,
81 have_zcu: bool,
82 emit_bin: bool,
83 root_optimize_mode: ?std.builtin.OptimizeMode = null,
84 root_strip: ?bool = null,
85 root_error_tracing: ?bool = null,
86 link_mode: ?std.builtin.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.builtin.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 ObjectFilesCannotSpecifyDynamicLinker,
127 SharedMemoryRequiresAtomicsAndBulkMemory,
128 ThreadsRequireSharedMemory,
129 EmittingLlvmModuleRequiresLlvmBackend,
130 LlvmLacksTargetSupport,
131 ZigLacksTargetSupport,
132 EmittingBinaryRequiresLlvmLibrary,
133 LldIncompatibleObjectFormat,
134 LldCannotIncrementallyLink,
135 LldCannotSpecifyDynamicLinkerForSharedLibraries,
136 LtoRequiresLld,
137 SanitizeThreadRequiresLibCpp,
138 LibCRequiresLibUnwind,
139 LibCppRequiresLibUnwind,
140 OsRequiresLibC,
141 LibCppRequiresLibC,
142 LibUnwindRequiresLibC,
143 TargetCannotDynamicLink,
144 TargetCannotStaticLinkExecutables,
145 LibCRequiresDynamicLinking,
146 SharedLibrariesRequireDynamicLinking,
147 DynamicLinkingWithLldRequiresSharedLibraries,
148 ExportMemoryAndDynamicIncompatible,
149 DynamicLibraryPrecludesPie,
150 TargetRequiresPie,
151 SanitizeThreadRequiresPie,
152 BackendLacksErrorTracing,
153 LlvmLibraryUnavailable,
154 LldUnavailable,
155 ClangUnavailable,
156 DllExportFnsRequiresWindows,
157 NewLinkerIncompatibleWithLld,
158 NewLinkerIncompatibleObjectFormat,
159};
160
161pub fn resolve(options: Options) ResolveError!Config {
162 const target = &options.resolved_target.result;
163
164 // WASI-only. Resolve the optional exec-model option, defaults to command.
165 if (target.os.tag != .wasi and options.wasi_exec_model != null)
166 return error.WasiExecModelRequiresWasi;
167 const wasi_exec_model = options.wasi_exec_model orelse .command;
168
169 const shared_memory = b: {
170 if (!target.cpu.arch.isWasm()) {
171 if (options.shared_memory == true) return error.SharedMemoryIsWasmOnly;
172 break :b false;
173 }
174 if (options.output_mode == .Obj) {
175 if (options.shared_memory == true) return error.ObjectFilesCannotShareMemory;
176 break :b false;
177 }
178 if (!target.cpu.hasAll(.wasm, &.{ .atomics, .bulk_memory })) {
179 if (options.shared_memory == true)
180 return error.SharedMemoryRequiresAtomicsAndBulkMemory;
181 break :b false;
182 }
183 if (options.any_non_single_threaded) {
184 if (options.shared_memory == false)
185 return error.ThreadsRequireSharedMemory;
186 break :b true;
187 }
188 break :b options.shared_memory orelse false;
189 };
190
191 // *If* the LLVM backend were to be selected, should Zig use the LLVM
192 // library to build the LLVM module?
193 const use_lib_llvm = b: {
194 if (!build_options.have_llvm) {
195 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;
196 break :b false;
197 }
198 break :b options.use_lib_llvm orelse true;
199 };
200
201 const root_optimize_mode = options.root_optimize_mode orelse .Debug;
202
203 // Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
204 const c_frontend: CFrontend = b: {
205 if (!build_options.have_llvm) {
206 if (options.use_clang == true) return error.ClangUnavailable;
207 break :b .aro;
208 }
209 if (options.use_clang) |clang| {
210 break :b if (clang) .clang else .aro;
211 }
212 break :b .clang;
213 };
214
215 const link_libcpp = b: {
216 if (options.link_libcpp == true) break :b true;
217 if (options.any_sanitize_thread) {
218 // TSAN is (for now...) implemented in C++ so it requires linking libc++.
219 if (options.link_libcpp == false) return error.SanitizeThreadRequiresLibCpp;
220 break :b true;
221 }
222 if (options.ensure_libcpp_on_non_freestanding and target.os.tag != .freestanding)
223 break :b true;
224
225 break :b false;
226 };
227
228 const link_libc = b: {
229 if (target_util.osRequiresLibC(target)) {
230 if (options.link_libc == false) return error.OsRequiresLibC;
231 break :b true;
232 }
233 if (link_libcpp) {
234 if (options.link_libc == false) return error.LibCppRequiresLibC;
235 break :b true;
236 }
237 if (options.link_libunwind == true) {
238 if (options.link_libc == false) return error.LibUnwindRequiresLibC;
239 break :b true;
240 }
241 if (options.link_libc) |x| break :b x;
242 switch (target.os.tag) {
243 // These targets don't require libc, but we don't yet have a syscall layer for them,
244 // so we default to linking libc for now.
245 .freebsd,
246 .netbsd,
247 => break :b true,
248 else => {},
249 }
250 if (options.ensure_libc_on_non_freestanding and target.os.tag != .freestanding)
251 break :b true;
252
253 break :b false;
254 };
255
256 const link_mode = b: {
257 const explicitly_exe_or_dyn_lib = switch (options.output_mode) {
258 .Obj => false,
259 .Lib => (options.link_mode orelse .static) == .dynamic,
260 .Exe => true,
261 };
262
263 if (target_util.cannotDynamicLink(target)) {
264 if (options.link_mode == .dynamic) return error.TargetCannotDynamicLink;
265 break :b .static;
266 }
267 if (target.os.tag == .fuchsia and options.output_mode == .Exe) {
268 if (options.link_mode == .static) return error.TargetCannotStaticLinkExecutables;
269 break :b .dynamic;
270 }
271 if (explicitly_exe_or_dyn_lib and link_libc and
272 (target_util.osRequiresLibC(target) or
273 // For these libcs, Zig can only provide dynamic libc when cross-compiling.
274 ((target.isGnuLibC() or target.isFreeBSDLibC() or target.isNetBSDLibC()) and
275 !options.resolved_target.is_native_abi)))
276 {
277 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;
278 break :b .dynamic;
279 }
280
281 if (options.link_mode) |link_mode| break :b link_mode;
282
283 if (options.any_dyn_libs) break :b .dynamic;
284
285 if (explicitly_exe_or_dyn_lib and link_libc) {
286 // When using the native glibc/musl ABI, dynamic linking is usually what people want.
287 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {
288 break :b .dynamic;
289 }
290
291 // When targeting systems where the kernel and libc are developed alongside each other,
292 // dynamic linking is the better default; static libc may contain code that requires
293 // the very latest kernel version.
294 if (target.isFreeBSDLibC() or target.isNetBSDLibC()) {
295 break :b .dynamic;
296 }
297 }
298
299 // Static is generally a better default. Fight me.
300 break :b .static;
301 };
302
303 const link_libunwind = b: {
304 if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {
305 if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;
306 break :b true;
307 }
308 if (link_libcpp and target_util.libCxxNeedsLibUnwind(target)) {
309 if (options.link_libunwind == false) return error.LibCppRequiresLibUnwind;
310 break :b true;
311 }
312 break :b options.link_libunwind orelse false;
313 };
314
315 const import_memory = options.import_memory orelse (options.output_mode == .Obj);
316 const export_memory = b: {
317 if (link_mode == .dynamic) {
318 if (options.export_memory == true) return error.ExportMemoryAndDynamicIncompatible;
319 break :b false;
320 }
321 if (options.export_memory) |x| break :b x;
322 break :b !import_memory;
323 };
324
325 const is_dyn_lib = switch (options.output_mode) {
326 .Obj, .Exe => false,
327 .Lib => link_mode == .dynamic,
328 };
329
330 // Make a decision on whether to use LLVM backend for machine code generation.
331 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.
332 // For example, Zig can emit .bc and .ll files directly, and this is still considered
333 // using "the LLVM backend".
334 const use_llvm = b: {
335 // If we have no zig code to compile, no need for LLVM.
336 if (!options.have_zcu) break :b false;
337
338 // If emitting to LLVM bitcode object format, must use LLVM backend.
339 if (options.emit_llvm_ir or options.emit_llvm_bc) {
340 if (options.use_llvm == false)
341 return error.EmittingLlvmModuleRequiresLlvmBackend;
342 if (!target_util.hasLlvmSupport(target, target.ofmt))
343 return error.LlvmLacksTargetSupport;
344
345 break :b true;
346 }
347
348 // If LLVM does not support the target, then we can't use it.
349 if (!target_util.hasLlvmSupport(target, target.ofmt)) {
350 if (options.use_llvm == true) return error.LlvmLacksTargetSupport;
351 break :b false;
352 }
353
354 // If Zig does not support the target, then we can't use it.
355 if (target_util.zigBackend(target, false) == .other) {
356 if (options.use_llvm == false) return error.ZigLacksTargetSupport;
357 break :b true;
358 }
359
360 if (options.use_llvm) |x| break :b x;
361
362 // If we cannot use LLVM libraries, then our own backends will be a
363 // better default since the LLVM backend can only produce bitcode
364 // and not an object file or executable.
365 if (!use_lib_llvm and options.emit_bin) break :b false;
366
367 // Prefer LLVM for release builds.
368 if (root_optimize_mode != .Debug) break :b true;
369
370 // load_dynamic_library standalone test not passing on this combination
371 // https://github.com/ziglang/zig/issues/24080
372 if (target.os.tag.isDarwin() and is_dyn_lib) break :b true;
373
374 // At this point we would prefer to use our own self-hosted backend,
375 // because the compilation speed is better than LLVM. But only do it if
376 // we are confident in the robustness of the backend.
377 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
378 };
379 const backend = target_util.zigBackend(target, use_llvm);
380
381 if (options.emit_bin and options.have_zcu) {
382 if (!use_lib_llvm and use_llvm) {
383 // Explicit request to use LLVM to produce an object file, but without
384 // using LLVM libraries. Impossible.
385 return error.EmittingBinaryRequiresLlvmLibrary;
386 }
387
388 if (backend == .other) {
389 // There is no compiler backend available for this target.
390 return error.ZigLacksTargetSupport;
391 }
392 }
393
394 // Make a decision on whether to use LLD or our own linker.
395 const use_lld = b: {
396 if (!target_util.hasLldSupport(target.ofmt)) {
397 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
398 break :b false;
399 }
400
401 if (!build_options.have_llvm) {
402 if (options.use_lld == true) return error.LldUnavailable;
403 break :b false;
404 }
405
406 if (options.lto != null and options.lto != .none) {
407 if (options.use_lld == false) return error.LtoRequiresLld;
408 break :b true;
409 }
410
411 if (options.use_llvm == false) {
412 if (options.use_lld == true) return error.LldCannotIncrementallyLink;
413 break :b false;
414 }
415
416 if (options.use_lld) |x| break :b x;
417
418 // If we have no zig code to compile, no need for the self-hosted linker.
419 if (!options.have_zcu) break :b true;
420
421 // If we do have zig code, match the decision for whether to use the llvm backend,
422 // so that the llvm backend defaults to lld and the self-hosted backends do not.
423 break :b use_llvm;
424 };
425
426 switch (options.output_mode) {
427 .Exe => if (options.any_dyn_libs) {
428 // When creating a executable that links to system libraries, we
429 // require dynamic linking, but we must not link static libraries
430 // or object files dynamically!
431 if (link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
432 } else if (use_lld and !link_libc and !link_libcpp and !link_libunwind) {
433 // Lld does not support creating dynamic executables when not
434 // linking to any shared libraries.
435 if (link_mode == .dynamic) return error.DynamicLinkingWithLldRequiresSharedLibraries;
436 },
437 .Lib => if (use_lld and options.resolved_target.is_explicit_dynamic_linker) {
438 return error.LldCannotSpecifyDynamicLinkerForSharedLibraries;
439 },
440 .Obj => if (options.resolved_target.is_explicit_dynamic_linker) {
441 return error.ObjectFilesCannotSpecifyDynamicLinker;
442 },
443 }
444
445 const use_new_linker = b: {
446 if (use_lld) {
447 if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;
448 break :b false;
449 }
450
451 if (!target_util.hasNewLinkerSupport(target.ofmt, backend)) {
452 if (options.use_new_linker == true) return error.NewLinkerIncompatibleObjectFormat;
453 break :b false;
454 }
455
456 if (options.use_new_linker) |x| break :b x;
457
458 break :b options.incremental;
459 };
460
461 const pie = b: {
462 switch (options.output_mode) {
463 .Exe => if (target.os.tag == .fuchsia or
464 (target.abi.isAndroid() and link_mode == .dynamic))
465 {
466 if (options.pie == false) return error.TargetRequiresPie;
467 break :b true;
468 },
469 .Lib => if (link_mode == .dynamic) {
470 if (options.pie == true) return error.DynamicLibraryPrecludesPie;
471 break :b false;
472 },
473 .Obj => {},
474 }
475 if (options.any_sanitize_thread) {
476 if (options.pie == false) return error.SanitizeThreadRequiresPie;
477 break :b true;
478 }
479 if (options.pie) |pie| break :b pie;
480 break :b if (options.output_mode == .Exe) switch (target.os.tag) {
481 .fuchsia,
482 .openbsd,
483 => true,
484 else => target.os.tag.isDarwin(),
485 } else false;
486 };
487
488 const lto: std.zig.LtoMode = b: {
489 if (!use_lld) {
490 // zig ld LTO support is tracked by
491 // https://github.com/ziglang/zig/issues/8680
492 if (options.lto != null and options.lto != .none) return error.LtoRequiresLld;
493 break :b .none;
494 }
495
496 if (options.lto) |x| break :b x;
497
498 break :b .none;
499 };
500
501 const root_strip = b: {
502 if (options.root_strip) |x| break :b x;
503 if (root_optimize_mode == .ReleaseSmall) break :b true;
504 if (!target_util.hasDebugInfo(target)) break :b true;
505 break :b false;
506 };
507
508 const debug_format: DebugFormat = b: {
509 if (root_strip and !options.any_non_stripped) break :b .strip;
510 if (options.debug_format) |x| break :b x;
511 break :b switch (target.ofmt) {
512 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
513 .coff => .code_view,
514 .c => switch (target.os.tag) {
515 .windows, .uefi => .code_view,
516 else => .{ .dwarf = .@"32" },
517 },
518 .spirv, .hex, .raw, .plan9 => .strip,
519 };
520 };
521
522 const backend_supports_error_tracing = target_util.backendSupportsFeature(backend, .error_return_trace);
523
524 const root_error_tracing = b: {
525 if (options.root_error_tracing) |x| break :b x;
526 if (root_strip) break :b false;
527 if (!backend_supports_error_tracing) break :b false;
528 break :b switch (root_optimize_mode) {
529 .Debug => true,
530 .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false,
531 };
532 };
533
534 const any_error_tracing = root_error_tracing or options.any_error_tracing;
535 if (any_error_tracing and !backend_supports_error_tracing)
536 return error.BackendLacksErrorTracing;
537
538 const rdynamic = options.rdynamic orelse false;
539
540 const dll_export_fns = b: {
541 if (target.os.tag != .windows) {
542 if (options.dll_export_fns == true)
543 return error.DllExportFnsRequiresWindows;
544 break :b false;
545 }
546 if (options.dll_export_fns) |x| break :b x;
547 if (rdynamic) break :b true;
548 break :b switch (options.output_mode) {
549 .Obj, .Exe => false,
550 .Lib => link_mode == .dynamic,
551 };
552 };
553
554 return .{
555 .output_mode = options.output_mode,
556 .have_zcu = options.have_zcu,
557 .is_test = options.is_test,
558 .link_mode = link_mode,
559 .link_libc = link_libc,
560 .link_libcpp = link_libcpp,
561 .link_libunwind = link_libunwind,
562 .any_unwind_tables = options.any_unwind_tables,
563 .any_c_source_files = options.any_c_source_files,
564 .any_non_single_threaded = options.any_non_single_threaded,
565 .any_error_tracing = any_error_tracing,
566 .any_sanitize_thread = options.any_sanitize_thread,
567 .any_sanitize_c = options.any_sanitize_c,
568 .any_fuzz = options.any_fuzz,
569 .san_cov_trace_pc_guard = options.san_cov_trace_pc_guard,
570 .root_error_tracing = root_error_tracing,
571 .use_new_linker = use_new_linker,
572 .pie = pie,
573 .lto = lto,
574 .incremental = options.incremental,
575 .import_memory = import_memory,
576 .export_memory = export_memory,
577 .shared_memory = shared_memory,
578 .c_frontend = c_frontend,
579 .use_llvm = use_llvm,
580 .use_lib_llvm = use_lib_llvm,
581 .use_lld = use_lld,
582 .wasi_exec_model = wasi_exec_model,
583 .debug_format = debug_format,
584 .root_optimize_mode = root_optimize_mode,
585 .root_strip = root_strip,
586 .dll_export_fns = dll_export_fns,
587 .rdynamic = rdynamic,
588 };
589}
590
591const std = @import("std");
592const Module = @import("../Package.zig").Module;
593const Config = @This();
594const target_util = @import("../target.zig");
595const build_options = @import("build_options");