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");