Files
zig/lib/compiler/configure_runner.zig
T
2026-04-19 10:56:46 -07:00

777 lines
36 KiB
Zig

const builtin = @import("builtin");
const std = @import("std");
const Allocator = std.mem.Allocator;
const Color = std.zig.Color;
const Configuration = std.Build.Configuration;
const File = std.Io.File;
const Io = std.Io;
const Step = std.Build.Step;
const Writer = std.Io.Writer;
const assert = std.debug.assert;
const fatal = std.process.fatal;
const fmt = std.fmt;
const log = std.log;
const mem = std.mem;
const process = std.process;
pub const root = @import("@build");
pub const dependencies = @import("@dependencies");
pub const std_options: std.Options = .{
.side_channels_mitigations = .none,
.http_disable_tls = true,
};
pub fn main(init: process.Init.Minimal) !void {
// The build runner is often short-lived, but thanks to `--watch` and `--webui`, that's not
// always the case. So, we do need a true gpa for some things.
var debug_gpa_state: std.heap.DebugAllocator(.{
// We'd rather have `zig build` run faster than catch harmless leaks in
// the user's build.zig script.
.stack_trace_frames = 0,
}) = .init;
defer _ = debug_gpa_state.deinit();
const gpa = debug_gpa_state.allocator();
var threaded: std.Io.Threaded = .init(gpa, .{
.environ = init.environ,
.argv0 = .init(init.args),
});
defer threaded.deinit();
const io = threaded.io();
// ...but we'll back our arena by `std.heap.page_allocator` for efficiency.
var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const args = try init.args.toSlice(arena);
// skip my own exe name
var arg_idx: usize = 1;
const zig_exe = expectArgOrFatal(args, &arg_idx, "--zig");
const zig_lib_dir = expectArgOrFatal(args, &arg_idx, "--zig-lib-dir");
const build_root = expectArgOrFatal(args, &arg_idx, "--build-root");
const local_cache_root = expectArgOrFatal(args, &arg_idx, "--local-cache");
const global_cache_root = expectArgOrFatal(args, &arg_idx, "--global-cache");
const cwd: Io.Dir = .cwd();
const zig_lib_directory: std.Build.Cache.Directory = .{
.path = zig_lib_dir,
.handle = try cwd.openDir(io, zig_lib_dir, .{}),
};
const build_root_directory: std.Build.Cache.Directory = .{
.path = build_root,
.handle = try cwd.openDir(io, build_root, .{}),
};
const local_cache_directory: std.Build.Cache.Directory = .{
.path = local_cache_root,
.handle = try cwd.createDirPathOpen(io, local_cache_root, .{}),
};
const global_cache_directory: std.Build.Cache.Directory = .{
.path = global_cache_root,
.handle = try cwd.createDirPathOpen(io, global_cache_root, .{}),
};
var graph: std.Build.Graph = .{
.io = io,
.arena = arena,
.cache = .{
.io = io,
.gpa = gpa,
.manifest_dir = try local_cache_directory.handle.createDirPathOpen(io, "h", .{}),
.cwd = try process.currentPathAlloc(io, arena),
},
.zig_exe = zig_exe,
.environ_map = try init.environ.createMap(arena),
.global_cache_root = global_cache_directory,
.zig_lib_directory = zig_lib_directory,
.host = .{
.query = .{},
.result = try std.zig.system.resolveTargetQuery(io, .{}),
},
};
graph.cache.addPrefix(.{ .path = null, .handle = cwd });
graph.cache.addPrefix(build_root_directory);
graph.cache.addPrefix(local_cache_directory);
graph.cache.addPrefix(global_cache_directory);
graph.cache.hash.addBytes(builtin.zig_version_string);
const builder = try std.Build.create(
&graph,
build_root_directory,
local_cache_directory,
dependencies.root_deps,
);
var error_style: ErrorStyle = .verbose;
var multiline_errors: MultilineErrors = .indent;
var color: Color = .auto;
if (std.zig.EnvVar.ZIG_BUILD_ERROR_STYLE.get(&graph.environ_map)) |str| {
if (std.meta.stringToEnum(ErrorStyle, str)) |style| {
error_style = style;
}
}
if (std.zig.EnvVar.ZIG_BUILD_MULTILINE_ERRORS.get(&graph.environ_map)) |str| {
if (std.meta.stringToEnum(MultilineErrors, str)) |style| {
multiline_errors = style;
}
}
while (nextArg(args, &arg_idx)) |arg| {
if (mem.cutPrefix(u8, arg, "-D")) |option_contents| {
if (option_contents.len == 0)
fatalWithHint("expected option name after '-D'", .{});
if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
const option_name = option_contents[0..name_end];
const option_value = option_contents[name_end + 1 ..];
if (try builder.addUserInputOption(option_name, option_value))
fatal(" access the help menu with 'zig build -h'", .{});
} else {
if (try builder.addUserInputFlag(option_contents))
fatal(" access the help menu with 'zig build -h'", .{});
}
} else if (mem.cutPrefix(u8, arg, "-fsys=")) |name| {
try graph.system_integration_options.put(arena, name, .user_enabled);
} else if (mem.cutPrefix(u8, arg, "-fno-sys=")) |name| {
try graph.system_integration_options.put(arena, name, .user_disabled);
} else if (mem.eql(u8, arg, "--release")) {
graph.release_mode = .any;
} else if (mem.cutPrefix(u8, arg, "--release=")) |text| {
graph.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
fatalWithHint("expected [off|any|fast|safe|small] in {q}, found {q}", .{
arg, text,
});
};
} else if (mem.eql(u8, arg, "--color")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected [auto|on|off] after {q}", .{arg});
color = std.meta.stringToEnum(Color, next_arg) orelse {
fatalWithHint("expected [auto|on|off] after {q}, found {q}", .{
arg, next_arg,
});
};
} else if (mem.eql(u8, arg, "--error-style")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected style after {q}", .{arg});
error_style = std.meta.stringToEnum(ErrorStyle, next_arg) orelse {
fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg });
};
} else if (mem.eql(u8, arg, "--multiline-errors")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected style after {q}", .{arg});
multiline_errors = std.meta.stringToEnum(MultilineErrors, next_arg) orelse {
fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg });
};
} else if (mem.eql(u8, arg, "--system")) {
// The usage text shows another argument after this parameter
// but it is handled by the parent process. The build runner
// only sees this flag.
graph.system_package_mode = true;
} else if (mem.eql(u8, arg, "--have-run-args")) {
graph.have_run_args = true;
} else {
fatalWithHint("unrecognized argument: {q}", .{arg});
}
}
const NO_COLOR = std.zig.EnvVar.NO_COLOR.isSet(&graph.environ_map);
const CLICOLOR_FORCE = std.zig.EnvVar.CLICOLOR_FORCE.isSet(&graph.environ_map);
graph.stderr_mode = switch (color) {
.auto => try .detect(io, .stderr(), NO_COLOR, CLICOLOR_FORCE),
.on => .escape_codes,
.off => .no_color,
};
try builder.runBuild(root);
if (builder.validateUserInputDidItFail()) {
fatal(" access the help menu with 'zig build -h'", .{});
}
var wc: Configuration.Wip = .init(gpa);
defer wc.deinit();
assert(try wc.addString("") == .empty);
try serializeSystemIntegrationOptions(&graph, &wc);
var stdout_buffer: [1024]u8 = undefined;
var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
serialize(builder, &wc, &file_writer.interface) catch |err| switch (err) {
error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}),
error.OutOfMemory => |e| return e,
};
// This executable is short-lived and run in Debug mode, so we'd rather
// have `zig build` run faster than catch resource leaks in the user's
// build.zig script (or, frankly, this configure runner), therefore we call
// exit directly here rather than cleanExit.
process.exit(0);
}
const Serialize = struct {
arena: Allocator,
wc: *Configuration.Wip,
module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty,
package_map: std.AutoArrayHashMapUnmanaged(*std.Build, Configuration.Package.Index) = .empty,
fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index {
if (b.pkg_hash.len == 0) return .root;
const arena = s.arena;
const wc = s.wc;
const gop = try s.package_map.getOrPut(arena, b);
if (!gop.found_existing) {
gop.value_ptr.* = @enumFromInt(try wc.addExtra(@as(Configuration.Package, .{
.hash = try wc.addString(b.pkg_hash),
.dep_prefix = try wc.addString(b.dep_prefix),
})));
}
return gop.value_ptr.*;
}
fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.OptionalLazyPath {
const wc = s.wc;
return @enumFromInt(switch (lp orelse return .none) {
.src_path => |src_path| i: {
const sub_path = try wc.addString(src_path.sub_path);
break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{
.flags = .{},
.owner = try s.builderToPackage(src_path.owner),
.sub_path = sub_path,
}));
},
.generated => |generated| i: {
const sub_path = try wc.addString(generated.sub_path);
break :i try wc.addExtra(@as(Configuration.LazyPath.Generated, .{
.flags = .{ .up = @intCast(generated.up) },
.sub_path = sub_path,
}));
},
.cwd_relative => |cwd_relative_sub_path| i: {
const sub_path = try wc.addString(cwd_relative_sub_path);
break :i try wc.addExtra(@as(Configuration.LazyPath.Relative, .{
.flags = .{ .base = .cwd },
.sub_path = sub_path,
}));
},
.dependency => |dependency| i: {
const sub_path = try wc.addString(dependency.sub_path);
break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{
.flags = .{},
.owner = try s.builderToPackage(dependency.dependency.builder),
.sub_path = sub_path,
}));
},
});
}
fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath {
return (try addOptionalLazyPathEnum(s, lp)).unwrap();
}
fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String {
return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null;
}
fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String {
return if (opt_slice) |slice| try s.wc.addString(slice) else null;
}
};
fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
const graph = b.graph;
const arena = graph.arena;
const gpa = wc.gpa;
var s: Serialize = .{ .wc = wc, .arena = arena };
// Starting from all top-level steps in `b`, traverse the entire step graph
// and add all step dependencies implied by module graphs.
const top_level_steps = b.top_level_steps.values();
// Index corresponds to `Configuration.steps` index.
var step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty;
try step_map.ensureUnusedCapacity(arena, top_level_steps.len);
for (top_level_steps) |tls| {
step_map.putAssumeCapacityNoClobber(&tls.step, {});
}
{
while (wc.steps.items.len < step_map.count()) {
const step = step_map.keys()[wc.steps.items.len];
// Set up any implied dependencies for this step. It's important that we do this first, so
// that the loop below discovers steps implied by the module graph.
try createModuleDependenciesForStep(step);
try step_map.ensureUnusedCapacity(arena, step.dependencies.items.len);
for (step.dependencies.items) |other_step| {
step_map.putAssumeCapacity(other_step, {});
}
// Add and then de-duplicate dependencies.
const deps = d: {
const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len);
for (try wc.prepareDeps(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step|
dep.* = @intCast(step_map.getIndex(dep_step).?);
break :d try wc.dedupeDeps(deps);
};
try wc.steps.ensureTotalCapacity(gpa, step_map.entries.capacity);
wc.steps.appendAssumeCapacity(.{
.name = try wc.addString(step.name),
.owner = try s.builderToPackage(step.owner),
.deps = deps,
.max_rss = .fromBytes(step.max_rss),
.extended = switch (step.tag) {
.top_level => e: {
const top_level: *Step.TopLevel = @fieldParentPtr("step", step);
break :e @enumFromInt(try wc.addExtra(@as(Configuration.Step.TopLevel, .{
.description = try wc.addString(top_level.description),
})));
},
.compile => e: {
const c: *Step.Compile = @fieldParentPtr("step", step);
const extra_index = try wc.addExtra(@as(Configuration.Step.Compile, .{
.flags = .{
.filters_len = c.filters.len != 0,
.exec_cmd_args_len = if (c.exec_cmd_args) |a| a.len != 0 else false,
.installed_headers_len = c.installed_headers.items.len != 0,
.force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0,
.verbose_link = c.verbose_link,
.verbose_cc = c.verbose_cc,
.rdynamic = c.rdynamic,
.import_memory = c.import_memory,
.export_memory = c.export_memory,
.import_symbols = c.import_symbols,
.import_table = c.import_table,
.export_table = c.export_table,
.shared_memory = c.shared_memory,
.link_eh_frame_hdr = c.link_eh_frame_hdr,
.link_emit_relocs = c.link_emit_relocs,
.link_function_sections = c.link_function_sections,
.link_data_sections = c.link_data_sections,
.linker_dynamicbase = c.linker_dynamicbase,
.link_z_notext = c.link_z_notext,
.link_z_relro = c.link_z_relro,
.link_z_lazy = c.link_z_lazy,
.link_z_defs = c.link_z_defs,
.headerpad_max_install_names = c.headerpad_max_install_names,
.dead_strip_dylibs = c.dead_strip_dylibs,
.force_load_objc = c.force_load_objc,
.discard_local_symbols = c.discard_local_symbols,
.mingw_unicode_entry_point = c.mingw_unicode_entry_point,
},
.flags2 = .{
.pie = .init(c.pie),
.formatted_panics = .init(c.formatted_panics),
.bundle_compiler_rt = .init(c.bundle_compiler_rt),
.bundle_ubsan_rt = .init(c.bundle_ubsan_rt),
.each_lib_rpath = .init(c.each_lib_rpath),
.link_gc_sections = .init(c.link_gc_sections),
.linker_allow_shlib_undefined = .init(c.linker_allow_shlib_undefined),
.linker_allow_undefined_version = .init(c.linker_allow_undefined_version),
.linker_enable_new_dtags = .init(c.linker_enable_new_dtags),
.dll_export_fns = .init(c.dll_export_fns),
.use_llvm = .init(c.use_llvm),
.use_lld = .init(c.use_lld),
.use_new_linker = .init(c.use_new_linker),
.allow_so_scripts = .init(c.allow_so_scripts),
.sanitize_coverage_trace_pc_guard = .init(c.sanitize_coverage_trace_pc_guard),
.linkage = .init(c.linkage),
},
.flags3 = .{
.is_linking_libc = c.is_linking_libc,
.is_linking_libcpp = c.is_linking_libcpp,
.version = c.version != null,
.compress_debug_sections = c.compress_debug_sections,
.initial_memory = c.initial_memory != null,
.max_memory = c.max_memory != null,
.kind = c.kind,
.global_base = c.global_base != null,
.test_runner_mode = if (c.test_runner) |tr| switch (tr.mode) {
.simple => .simple,
.server => .server,
} else .default,
.wasi_exec_model = .init(c.wasi_exec_model),
.win32_manifest = c.win32_manifest != null,
.win32_module_definition = c.win32_module_definition != null,
.zig_lib_dir = c.zig_lib_dir != null,
.rc_includes = c.rc_includes,
.image_base = c.image_base != null,
.build_id = .init(c.build_id),
.entry = switch (c.entry) {
.default => .default,
.disabled => .disabled,
.enabled => .enabled,
.symbol_name => .symbol_name,
},
.lto = .init(c.lto),
.subsystem = .init(c.subsystem),
},
.flags4 = .{
.libc_file = c.libc_file != null,
.link_z_common_page_size = c.link_z_common_page_size != null,
.link_z_max_page_size = c.link_z_max_page_size != null,
.pagezero_size = c.pagezero_size != null,
.stack_size = c.stack_size != null,
.headerpad_size = c.headerpad_size != null,
.error_limit = c.error_limit != null,
.install_name = c.install_name != null,
.entitlements = c.entitlements != null,
.expect_errors = if (c.expect_errors) |x| switch (x) {
.contains => .contains,
.exact => .exact,
.starts_with => .starts_with,
.stderr_contains => .stderr_contains,
} else .none,
.linker_script = c.linker_script != null,
.version_script = c.version_script != null,
},
.root_module = try addModule(&s, c.root_module),
.root_name = try wc.addString(c.name),
.linker_script = .{ .value = try s.addOptionalLazyPath(c.linker_script) },
.version_script = .{ .value = try s.addOptionalLazyPath(c.version_script) },
.zig_lib_dir = .{ .value = try s.addOptionalLazyPath(c.zig_lib_dir) },
.libc_file = .{ .value = try s.addOptionalLazyPath(c.libc_file) },
.win32_manifest = .{ .value = try s.addOptionalLazyPath(c.win32_manifest) },
.win32_module_definition = .{ .value = try s.addOptionalLazyPath(c.win32_module_definition) },
.entitlements = .{ .value = try s.addOptionalLazyPath(c.entitlements) },
.version = .{ .value = try s.addOptionalSemVer(c.version) },
.install_name = .{ .value = try s.addOptionalString(c.install_name) },
.initial_memory = .{ .value = c.initial_memory },
.max_memory = .{ .value = c.max_memory },
.global_base = .{ .value = c.global_base },
.image_base = .{ .value = c.image_base },
.link_z_common_page_size = .{ .value = c.link_z_common_page_size },
.link_z_max_page_size = .{ .value = c.link_z_max_page_size },
.pagezero_size = .{ .value = c.pagezero_size },
.stack_size = .{ .value = c.stack_size },
.headerpad_size = .{ .value = c.headerpad_size },
.error_limit = .{ .value = c.error_limit },
}));
log.err("TODO serialize the trailing Compile step data", .{});
break :e @enumFromInt(extra_index);
},
.install_artifact => e: {
const ia: *Step.InstallArtifact = @fieldParentPtr("step", step);
break :e @enumFromInt(try wc.addExtra(@as(Configuration.Step.InstallArtifact, .{
.flags = .{
.dylib_symlinks = ia.dylib_symlinks != null,
},
.dest_dir = try addInstallDir(wc, ia.dest_dir),
.dest_sub_path = try wc.addString(ia.dest_sub_path),
.emitted_bin = try s.addOptionalLazyPathEnum(ia.emitted_bin),
.implib_dir = try addInstallDir(wc, ia.implib_dir),
.emitted_implib = try s.addOptionalLazyPathEnum(ia.emitted_implib),
.pdb_dir = try addInstallDir(wc, ia.pdb_dir),
.emitted_pdb = try s.addOptionalLazyPathEnum(ia.emitted_pdb),
.h_dir = try addInstallDir(wc, ia.h_dir),
.emitted_h = try s.addOptionalLazyPathEnum(ia.emitted_h),
.artifact = stepIndex(&step_map, &ia.artifact.step),
})));
},
.install_file => @panic("TODO"),
.install_dir => @panic("TODO"),
.remove_dir => @panic("TODO"),
.fail => @panic("TODO"),
.fmt => @panic("TODO"),
.translate_c => @panic("TODO"),
.write_file => @panic("TODO"),
.update_source_files => @panic("TODO"),
.run => e: {
const run: *Step.Run = @fieldParentPtr("step", step);
const captured_stdout: Configuration.OptionalString = if (run.captured_stdout) |cs|
.init(try wc.addString(cs.output.basename))
else
.none;
const captured_stderr: Configuration.OptionalString = if (run.captured_stderr) |cs|
.init(try wc.addString(cs.output.basename))
else
.none;
const extra_index = try wc.addExtra(@as(Configuration.Step.Run, .{
.flags = .{
.disable_zig_progress = run.disable_zig_progress,
.skip_foreign_checks = run.skip_foreign_checks,
.failing_to_execute_foreign_is_an_error = run.failing_to_execute_foreign_is_an_error,
.has_side_effects = run.has_side_effects,
.test_runner_mode = run.test_runner_mode,
.color = run.color,
.stdio = switch (run.stdio) {
.infer_from_args => .infer_from_args,
.inherit => .inherit,
.check => .check,
.zig_test => .zig_test,
},
.stdin = switch (run.stdin) {
.none => .none,
.bytes => .bytes,
.lazy_path => .lazy_path,
},
.stdout_trim_whitespace = if (run.captured_stdout) |cs| cs.trim_whitespace else .none,
.stderr_trim_whitespace = if (run.captured_stderr) |cs| cs.trim_whitespace else .none,
.stdio_limit = run.stdio_limit != .unlimited,
.producer = run.producer != null,
},
.file_inputs_len = @intCast(run.file_inputs.items.len),
.args_len = @intCast(run.argv.items.len),
.cwd = try s.addOptionalLazyPathEnum(run.cwd),
.captured_stdout = captured_stdout,
.captured_stderr = captured_stderr,
}));
log.err("TODO serialize the trailing Run step data", .{});
break :e @enumFromInt(extra_index);
},
.check_file => @panic("TODO"),
.check_object => @panic("TODO"),
.config_header => @panic("TODO"),
.objcopy => @panic("TODO"),
.options => @panic("TODO"),
},
});
}
}
try wc.unlazy_deps.ensureUnusedCapacity(gpa, graph.needed_lazy_dependencies.keys().len);
for (graph.needed_lazy_dependencies.keys()) |k| {
wc.unlazy_deps.appendAssumeCapacity(try wc.addString(k));
}
try wc.write(writer, .{
.default_step = stepIndex(&step_map, b.default_step),
});
}
fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index {
if (s.module_map.get(m)) |index| return index;
const wc = s.wc;
const arena = s.arena;
const gpa = wc.gpa;
const import_table: Configuration.ImportTable = @enumFromInt(wc.extra.items.len);
const import_table_extra_len = 1 + 2 * m.import_table.entries.len;
try wc.extra.ensureUnusedCapacity(gpa, import_table_extra_len);
wc.extra.items.len += import_table_extra_len;
wc.extra.appendAssumeCapacity(@intCast(m.import_table.entries.len));
wc.extra.items[@intFromEnum(import_table)] = @intCast(m.import_table.entries.len);
for (
m.import_table.keys(),
@intFromEnum(import_table) + 1..,
) |mod_name, extra_index| {
wc.extra.items[extra_index] = @intFromEnum(try wc.addString(mod_name));
}
for (
m.import_table.values(),
@intFromEnum(import_table) + 1 + m.import_table.entries.len..,
) |dep, extra_index| {
log.err("TODO module dependencies can be cyclic", .{});
wc.extra.items[extra_index] = @intFromEnum(try addModule(s, dep));
}
const module_index: Configuration.Module.Index = @enumFromInt(try wc.addExtra(@as(Configuration.Module, .{
.flags = .{
.optimize = .init(m.optimize),
.strip = .init(m.strip),
.unwind_tables = .init(m.unwind_tables),
.dwarf_format = .init(m.dwarf_format),
.single_threaded = .init(m.strip),
.stack_protector = .init(m.strip),
.stack_check = .init(m.strip),
.sanitize_c = .init(m.sanitize_c),
.sanitize_thread = .init(m.strip),
.fuzz = .init(m.strip),
.code_model = m.code_model,
.c_macros = m.c_macros.items.len != 0,
.include_dirs = m.include_dirs.items.len != 0,
.lib_paths = m.lib_paths.items.len != 0,
.rpaths = m.rpaths.items.len != 0,
.frameworks = m.frameworks.entries.len != 0,
.link_objects = m.link_objects.items.len != 0,
.export_symbol_names = m.export_symbol_names.len != 0,
.valgrind = .init(m.strip),
.pic = .init(m.strip),
.red_zone = .init(m.strip),
.omit_frame_pointer = .init(m.strip),
.error_tracing = .init(m.strip),
.link_libc = .init(m.strip),
.link_libcpp = .init(m.strip),
.no_builtin = .init(m.strip),
},
.owner = try s.builderToPackage(m.owner),
.root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file),
.import_table = import_table,
.resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target),
})));
log.err("TODO serialize the trailing Module data", .{});
try s.module_map.putNoClobber(arena, m, module_index);
return module_index;
}
fn addOptionalResolvedTarget(
wc: *Configuration.Wip,
optional_resolved_target: ?std.Build.ResolvedTarget,
) !Configuration.ResolvedTarget.OptionalIndex {
const resolved_target = optional_resolved_target orelse return .none;
log.debug("TODO deduplicate resolved targets", .{});
return @enumFromInt(try wc.addExtra(@as(Configuration.ResolvedTarget, .{
.query = try wc.addTargetQuery(resolved_target.query),
.result = try wc.addTarget(resolved_target.result),
})));
}
fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Configuration.InstallDestDir {
switch (install_dir orelse return .none) {
.prefix => return .prefix,
.lib => return .lib,
.bin => return .bin,
.header => return .header,
.custom => |sub_path| return .initCustom(try wc.addString(sub_path)),
}
}
fn stepIndex(step_map: *const std.AutoArrayHashMapUnmanaged(*Step, void), step: *Step) Configuration.Step.Index {
return @enumFromInt(step_map.getIndex(step).?);
}
/// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which
/// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`.
fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
const root_module = if (step.cast(Step.Compile)) |cs| root: {
break :root cs.root_module;
} else return; // not a compile step so no module dependencies
// Starting from `root_module`, discover all modules in this graph.
const modules = root_module.getGraph().modules;
// For each of those modules, set up the implied step dependencies.
for (modules) |mod| {
if (mod.root_source_file) |lp| lp.addStepDependencies(step);
for (mod.include_dirs.items) |include_dir| switch (include_dir) {
.path,
.path_system,
.path_after,
.framework_path,
.framework_path_system,
.embed_path,
=> |lp| lp.addStepDependencies(step),
.other_step => |other| {
other.getEmittedIncludeTree().addStepDependencies(step);
step.dependOn(&other.step);
},
.config_header_step => |other| step.dependOn(&other.step),
};
for (mod.lib_paths.items) |lp| lp.addStepDependencies(step);
for (mod.rpaths.items) |rpath| switch (rpath) {
.lazy_path => |lp| lp.addStepDependencies(step),
.special => {},
};
for (mod.link_objects.items) |link_object| switch (link_object) {
.static_path,
.assembly_file,
=> |lp| lp.addStepDependencies(step),
.other_step => |other| step.dependOn(&other.step),
.system_lib => {},
.c_source_file => |source| source.file.addStepDependencies(step),
.c_source_files => |source_files| source_files.root.addStepDependencies(step),
.win32_resource_file => |rc_source| {
rc_source.file.addStepDependencies(step);
for (rc_source.include_paths) |lp| lp.addStepDependencies(step);
},
};
}
}
fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 {
if (idx.* >= args.len) return null;
defer idx.* += 1;
return args[idx.*];
}
fn nextArgOrFatal(args: []const [:0]const u8, idx: *usize) [:0]const u8 {
return nextArg(args, idx) orelse {
fatalWithHint("expected argument after: {s}", .{args[idx.* - 1]});
};
}
fn expectArgOrFatal(args: []const [:0]const u8, index_ptr: *usize, first: []const u8) []const u8 {
const next_arg = nextArg(args, index_ptr) orelse fatal("missing {q} argument", .{first});
if (!mem.eql(u8, first, next_arg)) fatal("expected {q} instead of {q}", .{ first, next_arg });
const arg = nextArg(args, index_ptr) orelse fatal("expected argument after {q}", .{first});
return arg;
}
const ErrorStyle = enum {
verbose,
minimal,
verbose_clear,
minimal_clear,
fn verboseContext(s: ErrorStyle) bool {
return switch (s) {
.verbose, .verbose_clear => true,
.minimal, .minimal_clear => false,
};
}
fn clearOnUpdate(s: ErrorStyle) bool {
return switch (s) {
.verbose, .minimal => false,
.verbose_clear, .minimal_clear => true,
};
}
};
const MultilineErrors = enum { indent, newline, none };
const Summary = enum { all, new, failures, line, none };
fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
log.info("to access the help menu: zig build -h", .{});
fatal(f, args);
}
fn serializeSystemIntegrationOptions(graph: *std.Build.Graph, wc: *Configuration.Wip) Allocator.Error!void {
const gpa = wc.gpa;
var bad = false;
try wc.system_integrations.ensureTotalCapacityPrecise(gpa, graph.system_integration_options.entries.len);
for (graph.system_integration_options.keys(), graph.system_integration_options.values()) |k, v| {
wc.system_integrations.appendAssumeCapacity(.{
.name = try wc.addString(k),
.status = switch (v) {
.user_disabled, .user_enabled => x: {
// The user tried to enable or disable a system library integration, but
// the configure script did not recognize that option.
log.err("system integration name not recognized by configure script: {s}", .{k});
bad = true;
break :x .disabled;
},
.declared_disabled => .disabled,
.declared_enabled => .enabled,
},
});
}
if (bad) {
log.info("help menu contains available options: zig build -h", .{});
process.exit(1);
}
}