diff --git a/BRANCH_TODO b/BRANCH_TODO new file mode 100644 index 0000000000..90eec2c8c8 --- /dev/null +++ b/BRANCH_TODO @@ -0,0 +1,12 @@ +* rename std.zig.Configuration to std.Build.Configuration +* replace union(@This().Tag) +* replace b.dupe() with string internment +* don't forget to add -listen arg back +* get zig init template working +* finish migrating the rest of the build steps +* make zig-pkg path root configurable in maker (make sure --system still works) +* eliminate calls to getPath, getPath2, getPath3 +* solve the TODOs added in this branch +* get zig tests passing +* test a bunch of third party projects / help people migrate +* refactor with DefaultingEnum diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 8a0e3ba249..9e6c59ea01 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -33,6 +33,7 @@ graph: *Graph, install_paths: InstallPaths, scanned_config: *const ScannedConfig, steps: []Step, +generated_files: []Path, available_rss: usize, max_rss_is_default: bool, @@ -115,7 +116,13 @@ pub fn main(init: process.Init.Minimal) !void { .zig_exe = zig_exe, .environ_map = try init.environ.createMap(arena), .global_cache_root = global_cache_directory, + .local_cache_root = local_cache_directory, .zig_lib_directory = zig_lib_directory, + .build_root_directory = build_root_directory, + .pkg_root = .{ + .root_dir = build_root_directory, + .sub_path = "zig-pkg", + }, }; graph.cache.addPrefix(.{ .path = null, .handle = cwd }); @@ -525,6 +532,7 @@ pub fn main(init: process.Init.Minimal) !void { .include = install_include_path, }, .steps = try arena.alloc(Step, scanned_config.configuration.steps.len), + .generated_files = try arena.alloc(Path, scanned_config.configuration.generated_files_len), .available_rss = max_rss, .max_rss_is_default = false, @@ -1679,3 +1687,99 @@ fn initStdoutWriter(io: Io) *Writer { stdout_writer_allocation = Io.File.stdout().writerStreaming(io, &stdio_buffer_allocation); return &stdout_writer_allocation.interface; } + +/// `asking_step` is only used for debugging purposes; it's the step being run +/// that is asking for the path. +pub fn resolveLazyPath( + maker: *const Maker, + arena: Allocator, + lazy_path: Configuration.LazyPath, + asking_step_index: Configuration.Step.Index, +) Allocator.Error!Path { + _ = asking_step_index; // TODO use this to enhance debugability when this function fails + const c = &maker.scanned_config.configuration; + const graph = maker.graph; + return switch (lazy_path) { + .source_path => |sp| try packagePath(maker, arena, sp.owner, sp.sub_path.slice(c)), + .relative => |relative| switch (relative.flags.base) { + .cwd => .{ + .root_dir = .cwd(), + .sub_path = relative.sub_path.slice(c), + }, + .local_cache => .{ + .root_dir = graph.local_cache_root, + }, + .global_cache => .{ + .root_dir = graph.global_cache_root, + }, + .build_root => .{ + .root_dir = graph.build_root_directory, + }, + }, + .generated => |gen| { + const base = maker.generated_files[@intFromEnum(gen.index)]; + var file_path = base; + for (0..gen.flags.up) |_| { + file_path.sub_path = Io.Dir.path.dirname(file_path.sub_path) orelse + fatal("invalid LazyPath traversal: up {d} times from {f}", .{ gen.flags.up, base }); + } + return file_path.join(arena, gen.sub_path.slice(c)); + }, + }; +} + +pub fn resolveLazyPathIndex( + maker: *const Maker, + arena: Allocator, + lazy_path_index: Configuration.LazyPath.Index, + asking_step_index: Configuration.Step.Index, +) Allocator.Error!Path { + const c = &maker.scanned_config.configuration; + return resolveLazyPath(maker, arena, lazy_path_index.get(c), asking_step_index); +} + +/// `resolveLazyPath` is preferred, but this can be necessary when passing Path +/// objects to child processes. +pub fn resolveLazyPathAbs( + maker: *const Maker, + arena: Allocator, + lazy_path: Configuration.LazyPath, + asking_step_index: Configuration.Step.Index, +) Allocator.Error![]const u8 { + const p = try resolveLazyPath(maker, arena, lazy_path, asking_step_index); + const root_dir_path = p.root_dir.path orelse return p.subPathOrDot(); + if (p.sub_path.len == 0) return root_dir_path; + return Io.Dir.path.join(arena, &.{ root_dir_path, p.sub_path }); +} + +/// `resolveLazyPath` is preferred, but this can be necessary when passing Path +/// objects to child processes. +pub fn resolveLazyPathIndexAbs( + maker: *const Maker, + arena: Allocator, + lazy_path_index: Configuration.LazyPath.Index, + asking_step_index: Configuration.Step.Index, +) Allocator.Error![]const u8 { + const c = &maker.scanned_config.configuration; + return resolveLazyPathAbs(maker, arena, lazy_path_index.get(c), asking_step_index); +} + +fn packagePath( + maker: *const Maker, + arena: Allocator, + package_index: Configuration.Package.Index, + sub_path: []const u8, +) Allocator.Error!Path { + const c = &maker.scanned_config.configuration; + const graph = maker.graph; + const package = package_index.get(c) orelse return .{ + .root_dir = graph.build_root_directory, + .sub_path = sub_path, + }; + const hash = package.hash.slice(c); + const pkg_root = graph.pkg_root; + return .{ + .root_dir = pkg_root.root_dir, + .sub_path = try Io.Dir.path.join(arena, &.{ pkg_root.sub_path, hash, sub_path }), + }; +} diff --git a/lib/compiler/Maker/Graph.zig b/lib/compiler/Maker/Graph.zig index e1b9ef5875..c2ed939b54 100644 --- a/lib/compiler/Maker/Graph.zig +++ b/lib/compiler/Maker/Graph.zig @@ -13,7 +13,10 @@ cache: std.Build.Cache, zig_exe: []const u8, environ_map: std.process.Environ.Map, global_cache_root: std.Build.Cache.Directory, +local_cache_root: std.Build.Cache.Directory, zig_lib_directory: std.Build.Cache.Directory, +build_root_directory: std.Build.Cache.Directory, +pkg_root: std.Build.Cache.Path, debug_compiler_runtime_libs: ?std.builtin.OptimizeMode = null, incremental: ?bool = null, diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig index b50d3c0f60..963640e1db 100644 --- a/lib/compiler/Maker/Step/Compile.zig +++ b/lib/compiler/Maker/Step/Compile.zig @@ -129,6 +129,7 @@ fn lowerZigArgs( const conf = &maker.scanned_config.configuration; const conf_step = compile_index.ptr(conf); const conf_comp = conf_step.extended.get(conf.extra).compile; + const root_module_target = conf_comp.rootModuleTarget(conf); try zig_args.append(gpa, graph.zig_exe); @@ -232,17 +233,17 @@ fn lowerZigArgs( } } - if (true) @panic("TODO"); - // Inherit dependencies on system libraries and static libraries. for (0..mod.link_objects.len) |lo_i| switch (mod.link_objects.get(conf.extra, lo_i)) { .static_path => |static_path| { if (my_responsibility) { - try zig_args.append(gpa, static_path.getPath2(step)); + try zig_args.append(gpa, try maker.resolveLazyPathIndexAbs(arena, static_path, compile_index)); total_linker_objects += 1; } }, - .system_lib => |system_lib| { + .system_lib => |system_lib_index| { + const system_lib = system_lib_index.get(conf); + const system_lib_name = system_lib.name.slice(conf); const system_lib_gop = try seen_system_libs.getOrPut(arena, system_lib.name); if (system_lib_gop.found_existing) { try zig_args.appendSlice(gpa, system_lib_gop.value_ptr.*); @@ -254,37 +255,39 @@ fn lowerZigArgs( if (already_linked) continue; - if ((system_lib.search_strategy != prev_search_strategy or - system_lib.preferred_link_mode != prev_preferred_link_mode) and - compile.linkage != .static) + if ((system_lib.flags.search_strategy != prev_search_strategy or + system_lib.flags.preferred_link_mode != prev_preferred_link_mode) and + conf_comp.flags2.linkage != .static) { - switch (system_lib.search_strategy) { - .no_fallback => switch (system_lib.preferred_link_mode) { + switch (system_lib.flags.search_strategy) { + .no_fallback => switch (system_lib.flags.preferred_link_mode) { .dynamic => try zig_args.append(gpa, "-search_dylibs_only"), .static => try zig_args.append(gpa, "-search_static_only"), }, - .paths_first => switch (system_lib.preferred_link_mode) { + .paths_first => switch (system_lib.flags.preferred_link_mode) { .dynamic => try zig_args.append(gpa, "-search_paths_first"), .static => try zig_args.append(gpa, "-search_paths_first_static"), }, - .mode_first => switch (system_lib.preferred_link_mode) { + .mode_first => switch (system_lib.flags.preferred_link_mode) { .dynamic => try zig_args.append(gpa, "-search_dylibs_first"), .static => try zig_args.append(gpa, "-search_static_first"), }, } - prev_search_strategy = system_lib.search_strategy; - prev_preferred_link_mode = system_lib.preferred_link_mode; + prev_search_strategy = system_lib.flags.search_strategy; + prev_preferred_link_mode = system_lib.flags.preferred_link_mode; } const prefix: []const u8 = prefix: { - if (system_lib.needed) break :prefix "-needed-l"; - if (system_lib.weak) break :prefix "-weak-l"; + if (system_lib.flags.needed) break :prefix "-needed-l"; + if (system_lib.flags.weak) break :prefix "-weak-l"; break :prefix "-l"; }; - switch (system_lib.use_pkg_config) { - .no => try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ prefix, system_lib.name })), + switch (system_lib.flags.use_pkg_config) { + .no => try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ + prefix, system_lib_name, + })), .yes, .force => { - if (compile.runPkgConfig(maker, system_lib.name)) |result| { + if (compile.runPkgConfig(maker, system_lib_name)) |result| { try zig_args.appendSlice(gpa, result.cflags); try zig_args.appendSlice(gpa, result.libs); try seen_system_libs.put(arena, system_lib.name, result.cflags); @@ -294,17 +297,18 @@ fn lowerZigArgs( error.PkgConfigFailed, error.PkgConfigNotInstalled, error.PackageNotFound, - => switch (system_lib.use_pkg_config) { + => switch (system_lib.flags.use_pkg_config) { .yes => { // pkg-config failed, so fall back to linking the library // by name directly. try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ - prefix, - system_lib.name, + prefix, system_lib_name, })); }, .force => { - return step.fail(maker, "pkg-config failed for library {s}", .{system_lib.name}); + return step.fail(maker, "pkg-config failed for library {s}", .{ + system_lib_name, + }); }, .no => unreachable, }, @@ -314,23 +318,31 @@ fn lowerZigArgs( }, } }, - .other_step => |other| { - switch (other.kind) { + .other_step => |other_step_index| { + const other = other_step_index.ptr(conf); + const other_compile = other.extended.get(conf.extra).compile; + switch (other_compile.flags3.kind) { .exe => return step.fail(maker, "cannot link with an executable build artifact", .{}), .@"test" => return step.fail(maker, "cannot link with a test", .{}), .obj, .test_obj => { - const included_in_lib_or_obj = !my_responsibility and - (dep_compile.kind == .lib or dep_compile.kind == .obj or dep_compile.kind == .test_obj); + const included_in_lib_or_obj = switch (dep_compile.flags3.kind) { + .lib, .obj, .test_obj => !my_responsibility, + else => false, + }; if (!already_linked and !included_in_lib_or_obj) { - try zig_args.append(gpa, other.getEmittedBin().getPath2(step)); + try zig_args.append(gpa, try maker.resolveLazyPathAbs( + arena, + .{ .generated = .{ .index = other_compile.generated_bin.value.? } }, + compile_index, + )); total_linker_objects += 1; } }, .lib => l: { - const other_produces_implib = other.producesImplib(); - const other_is_static = other_produces_implib or other.isStaticLibrary(); + const other_produces_implib = other_compile.producesImplib(conf); + const other_is_static = other_produces_implib or other_compile.isStaticLibrary(); - if (compile.isStaticLibrary() and other_is_static) { + if (conf_comp.isStaticLibrary() and other_is_static) { // Avoid putting a static library inside a static library. break :l; } @@ -338,20 +350,25 @@ fn lowerZigArgs( // For DLLs, we must link against the implib. // For everything else, we directly link // against the library file. - const full_path_lib = if (other_produces_implib) - try other.getGeneratedFilePath("generated_implib", &compile.step) - else - try other.getGeneratedFilePath("generated_bin", &compile.step); + const full_path_lib = try maker.resolveLazyPathAbs( + arena, + .{ .generated = .{ + .index = if (other_produces_implib) + other_compile.generated_implib.value.? + else + other_compile.generated_bin.value.?, + } }, + compile_index, + ); try zig_args.append(gpa, full_path_lib); total_linker_objects += 1; - if (other.linkage == .dynamic and - compile.rootModuleTarget().os.tag != .windows) + if (other_compile.flags2.linkage == .dynamic and + root_module_target.flags.os_tag != .windows) { if (Dir.path.dirname(full_path_lib)) |dirname| { - try zig_args.append(gpa, "-rpath"); - try zig_args.append(gpa, dirname); + try zig_args.appendSlice(gpa, &.{ "-rpath", dirname }); } } }, @@ -361,92 +378,96 @@ fn lowerZigArgs( if (!my_responsibility) break :l; if (prev_has_cflags) { - try zig_args.append(gpa, "-cflags"); - try zig_args.append(gpa, "--"); + try zig_args.appendSlice(gpa, &.{ "-cflags", "--" }); prev_has_cflags = false; } - try zig_args.append(gpa, asm_file.getPath2(mod.owner, step)); + try zig_args.append(gpa, try maker.resolveLazyPathIndexAbs(arena, asm_file, compile_index)); total_linker_objects += 1; }, - .c_source_file => |c_source_file| l: { + .c_source_file => |c_source_file_index| l: { if (!my_responsibility) break :l; - if (prev_has_cflags or c_source_file.flags.len != 0) { - try zig_args.append(gpa, "-cflags"); - for (c_source_file.flags) |arg| { - try zig_args.append(gpa, arg); + const c_source_file = c_source_file_index.get(conf); + + if (prev_has_cflags or c_source_file.args.slice.len != 0) { + try zig_args.ensureUnusedCapacity(gpa, 2 + c_source_file.args.slice.len); + zig_args.appendAssumeCapacity("-cflags"); + for (c_source_file.args.slice) |arg| { + zig_args.appendAssumeCapacity(arg.slice(conf)); } - try zig_args.append(gpa, "--"); + zig_args.appendAssumeCapacity("--"); } - prev_has_cflags = (c_source_file.flags.len != 0); + prev_has_cflags = (c_source_file.args.slice.len != 0); - if (c_source_file.language) |lang| { - try zig_args.append(gpa, "-x"); - try zig_args.append(gpa, lang.internalIdentifier()); - } + if (c_source_file.flags.lang.get()) |lang| + (try zig_args.addManyAsArray(gpa, 2)).* = .{ "-x", lang.clangIdentifier() }; - try zig_args.append(gpa, c_source_file.file.getPath2(mod.owner, step)); + try zig_args.append(gpa, try maker.resolveLazyPathIndexAbs(arena, c_source_file.file, compile_index)); + + if (c_source_file.flags.lang != .default) + (try zig_args.addManyAsArray(gpa, 2)).* = .{ "-x", "none" }; - if (c_source_file.language != null) { - try zig_args.append(gpa, "-x"); - try zig_args.append(gpa, "none"); - } total_linker_objects += 1; }, - .c_source_files => |c_source_files| l: { + .c_source_files => |c_source_files_index| l: { if (!my_responsibility) break :l; - if (prev_has_cflags or c_source_files.flags.len != 0) { - try zig_args.append(gpa, "-cflags"); - for (c_source_files.flags) |arg| { - try zig_args.append(gpa, arg); + const c_source_files = c_source_files_index.get(conf); + + if (prev_has_cflags or c_source_files.args.slice.len != 0) { + try zig_args.ensureUnusedCapacity(gpa, 2 + c_source_files.args.slice.len); + zig_args.appendAssumeCapacity("-cflags"); + for (c_source_files.args.slice) |arg| { + zig_args.appendAssumeCapacity(arg.slice(conf)); } - try zig_args.append(gpa, "--"); + zig_args.appendAssumeCapacity("--"); } - prev_has_cflags = (c_source_files.flags.len != 0); + prev_has_cflags = (c_source_files.args.slice.len != 0); - if (c_source_files.language) |lang| { - try zig_args.append(gpa, "-x"); - try zig_args.append(gpa, lang.internalIdentifier()); + if (c_source_files.flags.lang.get()) |lang| + (try zig_args.addManyAsArray(gpa, 2)).* = .{ "-x", lang.clangIdentifier() }; + + const root_path = try maker.resolveLazyPathIndexAbs(arena, c_source_files.root, compile_index); + try zig_args.ensureUnusedCapacity(gpa, c_source_files.sub_paths.slice.len); + for (c_source_files.sub_paths.slice) |sub_path| { + zig_args.appendAssumeCapacity(try Dir.path.join(arena, &.{ + root_path, sub_path.slice(conf), + })); } - const root_path = c_source_files.root.getPath2(mod.owner, step); - for (c_source_files.files) |file| { - try zig_args.append(gpa, try Dir.path.join(arena, &.{ root_path, file })); - } + if (c_source_files.flags.lang != .default) + (try zig_args.addManyAsArray(gpa, 2)).* = .{ "-x", "none" }; - if (c_source_files.language != null) { - try zig_args.append(gpa, "-x"); - try zig_args.append(gpa, "none"); - } - - total_linker_objects += c_source_files.files.len; + total_linker_objects += c_source_files.sub_paths.slice.len; }, - .win32_resource_file => |rc_source_file| l: { + .win32_resource_file => |rc_source_file_index| l: { if (!my_responsibility) break :l; - if (rc_source_file.flags.len == 0 and rc_source_file.include_paths.len == 0) { + const rc_source_file = rc_source_file_index.get(conf); + + if (rc_source_file.args.slice.len == 0 and rc_source_file.include_paths.slice.len == 0) { if (prev_has_rcflags) { - try zig_args.append(gpa, "-rcflags"); - try zig_args.append(gpa, "--"); + (try zig_args.addManyAsArray(gpa, 2)).* = .{ "-rcflags", "--" }; prev_has_rcflags = false; } } else { - try zig_args.append(gpa, "-rcflags"); - for (rc_source_file.flags) |arg| { - try zig_args.append(gpa, arg); + try zig_args.ensureUnusedCapacity(gpa, 1 + rc_source_file.args.slice.len); + zig_args.appendAssumeCapacity("-rcflags"); + for (rc_source_file.args.slice) |arg| { + zig_args.appendAssumeCapacity(arg.slice(conf)); } - for (rc_source_file.include_paths) |include_path| { - try zig_args.append(gpa, "/I"); - try zig_args.append(gpa, include_path.getPath2(mod.owner, step)); + try zig_args.ensureUnusedCapacity(gpa, 1 + 2 * rc_source_file.include_paths.slice.len); + for (rc_source_file.include_paths.slice) |include_path| { + zig_args.appendAssumeCapacity("/I"); + zig_args.appendAssumeCapacity(try maker.resolveLazyPathIndexAbs(arena, include_path, compile_index)); } - try zig_args.append(gpa, "--"); + zig_args.appendAssumeCapacity("--"); prev_has_rcflags = true; } - try zig_args.append(gpa, rc_source_file.file.getPath2(mod.owner, step)); + try zig_args.append(gpa, try maker.resolveLazyPathIndexAbs(arena, rc_source_file.file, compile_index)); total_linker_objects += 1; }, }; @@ -455,9 +476,10 @@ fn lowerZigArgs( // have the correct parent module, but only if the module is part of // this compilation. if (!my_responsibility) continue; - if (cli_named_modules.modules.getIndex(mod)) |module_cli_index| { + if (cli_named_modules.modules.getIndex(mod_index)) |module_cli_index| { const module_cli_name = cli_named_modules.names.keys()[module_cli_index]; - try mod.appendZigProcessFlags(zig_args, step); + if (true) @panic("TODO"); + try appendModuleFlags(zig_args, step); // --dep arguments try zig_args.ensureUnusedCapacity(mod.import_table.count() * 2); @@ -510,12 +532,12 @@ fn lowerZigArgs( if (is_linking_libc) zig_args.appendAssumeCapacity("-lc"); } - if (true) @panic("TODO"); - - if (conf_comp.win32_manifest) |manifest_file| { - try zig_args.append(gpa, manifest_file.getPath2(step)); + if (conf_comp.win32_manifest.value) |manifest_file| { + try zig_args.append(gpa, try maker.resolveLazyPathIndexAbs(arena, manifest_file, compile_index)); } + if (true) @panic("TODO"); + if (conf_comp.win32_module_definition) |module_file| { try zig_args.append(gpa, module_file.getPath2(step)); } @@ -623,27 +645,26 @@ fn lowerZigArgs( "--version", try allocPrint(arena, "{f}", .{version}), }); - if (compile.rootModuleTarget().os.tag.isDarwin()) { + if (root_module_target.flags.os_tag.isDarwin()) { const install_name = compile.install_name orelse try allocPrint(arena, "@rpath/{s}{s}{s}", .{ - compile.rootModuleTarget().libPrefix(), + root_module_target.libPrefix(), compile.name, - compile.rootModuleTarget().dynamicLibSuffix(), + root_module_target.dynamicLibSuffix(), }); - try zig_args.append(gpa, "-install_name"); - try zig_args.append(gpa, install_name); + try zig_args.appendSlice(gpa, &.{ "-install_name", install_name }); } } if (compile.entitlements) |entitlements| { - try zig_args.appendSlice(gpa, &[_][]const u8{ "--entitlements", entitlements }); + try zig_args.appendSlice(gpa, &.{ "--entitlements", entitlements }); } if (compile.pagezero_size) |pagezero_size| { const size = try allocPrint(arena, "{x}", .{pagezero_size}); - try zig_args.appendSlice(gpa, &[_][]const u8{ "-pagezero_size", size }); + try zig_args.appendSlice(gpa, &.{ "-pagezero_size", size }); } if (compile.headerpad_size) |headerpad_size| { const size = try allocPrint(arena, "{x}", .{headerpad_size}); - try zig_args.appendSlice(gpa, &[_][]const u8{ "-headerpad", size }); + try zig_args.appendSlice(gpa, &.{ "-headerpad", size }); } if (compile.headerpad_max_install_names) { try zig_args.append(gpa, "-headerpad_max_install_names"); @@ -1019,7 +1040,8 @@ const PkgConfigResult = struct { /// Run pkg-config for the given library name and parse the output, returning the arguments /// that should be passed to zig to link the given library. -fn runPkgConfig(compile: *Compile, maker: *Maker, lib_name: []const u8) !PkgConfigResult { +fn runPkgConfig(compile: *const Compile, maker: *const Maker, lib_name: []const u8) !PkgConfigResult { + if (true) @panic("TODO"); const graph = maker.graph; const wl_rpath_prefix = "-Wl,-rpath,"; @@ -1361,3 +1383,131 @@ fn getModuleList( return modules; } + +fn appendModuleFlags( + m: *Module, + zig_args: *std.array_list.Managed([]const u8), + asking_step: ?*Step, +) !void { + const b = m.owner; + + try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip"); + try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded"); + try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check"); + try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector"); + try addFlag(zig_args, m.omit_frame_pointer, "-fomit-frame-pointer", "-fno-omit-frame-pointer"); + try addFlag(zig_args, m.error_tracing, "-ferror-tracing", "-fno-error-tracing"); + try addFlag(zig_args, m.sanitize_thread, "-fsanitize-thread", "-fno-sanitize-thread"); + try addFlag(zig_args, m.fuzz, "-ffuzz", "-fno-fuzz"); + try addFlag(zig_args, m.valgrind, "-fvalgrind", "-fno-valgrind"); + try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC"); + try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone"); + try addFlag(zig_args, m.no_builtin, "-fno-builtin", "-fbuiltin"); + + if (m.sanitize_c) |sc| switch (sc) { + .off => try zig_args.append("-fno-sanitize-c"), + .trap => try zig_args.append("-fsanitize-c=trap"), + .full => try zig_args.append("-fsanitize-c=full"), + }; + + if (m.dwarf_format) |dwarf_format| { + try zig_args.append(switch (dwarf_format) { + .@"32" => "-gdwarf32", + .@"64" => "-gdwarf64", + }); + } + + if (m.unwind_tables) |unwind_tables| { + try zig_args.append(switch (unwind_tables) { + .none => "-fno-unwind-tables", + .sync => "-funwind-tables", + .async => "-fasync-unwind-tables", + }); + } + + try zig_args.ensureUnusedCapacity(1); + if (m.optimize) |optimize| switch (optimize) { + .Debug => zig_args.appendAssumeCapacity("-ODebug"), + .ReleaseSmall => zig_args.appendAssumeCapacity("-OReleaseSmall"), + .ReleaseFast => zig_args.appendAssumeCapacity("-OReleaseFast"), + .ReleaseSafe => zig_args.appendAssumeCapacity("-OReleaseSafe"), + }; + + if (m.code_model != .default) { + try zig_args.append("-mcmodel"); + try zig_args.append(@tagName(m.code_model)); + } + + if (m.resolved_target) |*target| { + // Communicate the query via CLI since it's more compact. + if (!target.query.isNative()) { + try zig_args.appendSlice(&.{ + "-target", try target.query.zigTriple(b.allocator), + "-mcpu", try target.query.serializeCpuAlloc(b.allocator), + }); + if (target.query.dynamic_linker) |*dynamic_linker| { + if (dynamic_linker.get()) |dynamic_linker_path| { + try zig_args.append("--dynamic-linker"); + try zig_args.append(dynamic_linker_path); + } else { + try zig_args.append("--no-dynamic-linker"); + } + } + } + } + + for (m.export_symbol_names) |symbol_name| { + try zig_args.append(b.fmt("--export={s}", .{symbol_name})); + } + + for (m.include_dirs.items) |include_dir| { + try appendIncludeDirFlags(include_dir, b, zig_args, asking_step); + } + + try zig_args.appendSlice(m.c_macros.items); + + try zig_args.ensureUnusedCapacity(2 * m.lib_paths.items.len); + for (m.lib_paths.items) |lib_path| { + zig_args.appendAssumeCapacity("-L"); + zig_args.appendAssumeCapacity(lib_path.getPath2(b, asking_step)); + } + + try zig_args.ensureUnusedCapacity(2 * m.rpaths.items.len); + for (m.rpaths.items) |rpath| switch (rpath) { + .lazy_path => |lp| { + zig_args.appendAssumeCapacity("-rpath"); + zig_args.appendAssumeCapacity(lp.getPath2(b, asking_step)); + }, + .special => |bytes| { + zig_args.appendAssumeCapacity("-rpath"); + zig_args.appendAssumeCapacity(bytes); + }, + }; +} + +fn appendIncludeDirFlags( + include_dir: Configuration.Module.IncludeDir, + b: *std.Build, + zig_args: *std.array_list.Managed([]const u8), + asking_step: ?*Step, +) !void { + const flag: []const u8, const lazy_path: Configuration.LazyPath = switch (include_dir) { + // zig fmt: off + .path => |lp| .{ "-I", lp }, + .path_system => |lp| .{ "-isystem", lp }, + .path_after => |lp| .{ "-idirafter", lp }, + .framework_path => |lp| .{ "-F", lp }, + .framework_path_system => |lp| .{ "-iframework", lp }, + .config_header_step => |ch| .{ "-I", ch.getOutputDir() }, + .other_step => |comp| .{ "-I", comp.installed_headers_include_tree.?.getDirectory() }, + // zig fmt: on + .embed_path => |lazy_path| { + // Special case: this is a single arg. + const resolved = lazy_path.getPath3(b, asking_step); + const arg = b.fmt("--embed-dir={f}", .{resolved}); + return zig_args.append(arg); + }, + }; + const resolved_str = try lazy_path.getPath3(b, asking_step).toString(b.graph.arena); + return zig_args.appendSlice(&.{ flag, resolved_str }); +} diff --git a/lib/compiler/configurer.zig b/lib/compiler/configurer.zig index bea788fba1..f6b52f057e 100644 --- a/lib/compiler/configurer.zig +++ b/lib/compiler/configurer.zig @@ -96,6 +96,7 @@ pub fn main(init: process.Init.Minimal) !void { .query = .{}, .result = try std.zig.system.resolveTargetQuery(io, .{}), }, + .generated_files = .empty, }; graph.cache.addPrefix(.{ .path = null, .handle = cwd }); @@ -242,7 +243,7 @@ const Serialize = struct { return gop.value_ptr.*; } - fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.OptionalLazyPath { + fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex { const wc = s.wc; return @enumFromInt(switch (lp orelse return .none) { .src_path => |src_path| i: { @@ -257,6 +258,7 @@ const Serialize = struct { const sub_path = try wc.addString(generated.sub_path); break :i try wc.addExtra(@as(Configuration.LazyPath.Generated, .{ .flags = .{ .up = @intCast(generated.up) }, + .index = generated.index, .sub_path = sub_path, })); }, @@ -278,11 +280,11 @@ const Serialize = struct { }); } - fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath { + fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath.Index { return (try addOptionalLazyPathEnum(s, lp)).unwrap(); } - fn addLazyPath(s: *Serialize, lp: std.Build.LazyPath) !Configuration.LazyPath { + fn addLazyPath(s: *Serialize, lp: std.Build.LazyPath) !Configuration.LazyPath.Index { return @enumFromInt(@intFromEnum(try addOptionalLazyPathEnum(s, lp))); } @@ -351,8 +353,8 @@ const Serialize = struct { }))); } - fn initLazyPathList(s: *Serialize, list: []const std.Build.LazyPath) ![]const Configuration.LazyPath { - const result = try s.arena.alloc(Configuration.LazyPath, list.len); + fn initLazyPathList(s: *Serialize, list: []const std.Build.LazyPath) ![]const Configuration.LazyPath.Index { + const result = try s.arena.alloc(Configuration.LazyPath.Index, list.len); for (result, list) |*dest, src| dest.* = try addLazyPath(s, src); return result; } @@ -665,6 +667,15 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { } else .none, .linker_script = c.linker_script != null, .version_script = c.version_script != null, + .emit_directory = c.emit_directory != .none, + .generated_docs = c.generated_docs != .none, + .generated_asm = c.generated_asm != .none, + .generated_bin = c.generated_bin != .none, + .generated_pdb = c.generated_pdb != .none, + .generated_implib = c.generated_implib != .none, + .generated_llvm_bc = c.generated_llvm_bc != .none, + .generated_llvm_ir = c.generated_llvm_ir != .none, + .generated_h = c.generated_h != .none, }, .root_module = try s.addModule(c.root_module), .root_name = try wc.addString(c.name), @@ -709,6 +720,16 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { .simple => .{ .simple = try s.addLazyPath(tr.path) }, .server => .{ .server = try s.addLazyPath(tr.path) }, } else .default }, + + .emit_directory = .{ .value = c.emit_directory.unwrap() }, + .generated_docs = .{ .value = c.generated_docs.unwrap() }, + .generated_asm = .{ .value = c.generated_asm.unwrap() }, + .generated_bin = .{ .value = c.generated_bin.unwrap() }, + .generated_pdb = .{ .value = c.generated_pdb.unwrap() }, + .generated_implib = .{ .value = c.generated_implib.unwrap() }, + .generated_llvm_bc = .{ .value = c.generated_llvm_bc.unwrap() }, + .generated_llvm_ir = .{ .value = c.generated_llvm_ir.unwrap() }, + .generated_h = .{ .value = c.generated_h.unwrap() }, })); break :e @enumFromInt(extra_index); @@ -804,6 +825,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { try wc.write(writer, .{ .default_step = s.stepIndex(b.default_step), + .generated_files_len = @intCast(graph.generated_files.items.len), }); } diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 284a2da346..8b3b8ec5fd 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -1,4 +1,5 @@ const Build = @This(); + const builtin = @import("builtin"); const std = @import("std.zig"); @@ -111,6 +112,14 @@ pub const Graph = struct { /// process via `Step.Run` API but cannot be observed in the configure /// phase. have_run_args: bool = false, + + /// Indexes correspond to `Configuration.GeneratedFileIndex`. + generated_files: std.ArrayList(*Step), + + pub fn addGeneratedFile(graph: *Graph, owner: *Step) Configuration.GeneratedFileIndex { + graph.generated_files.append(graph.arena, owner) catch @panic("OOM"); + return @enumFromInt(graph.generated_files.items.len - 1); + } }; const AvailableDeps = []const struct { []const u8, []const u8 }; @@ -865,7 +874,7 @@ pub fn dupe(b: *Build, bytes: []const u8) []u8 { return dupeInner(b.allocator, bytes); } -pub fn dupeInner(allocator: std.mem.Allocator, bytes: []const u8) []u8 { +pub fn dupeInner(allocator: Allocator, bytes: []const u8) []u8 { return allocator.dupe(u8, bytes) catch @panic("OOM"); } @@ -881,7 +890,7 @@ pub fn dupePath(b: *Build, bytes: []const u8) []u8 { return dupePathInner(b.allocator, bytes); } -fn dupePathInner(allocator: std.mem.Allocator, bytes: []const u8) []u8 { +fn dupePathInner(allocator: Allocator, bytes: []const u8) []u8 { const the_copy = dupeInner(allocator, bytes); for (the_copy) |*byte| { switch (byte.*) { @@ -2068,13 +2077,6 @@ pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void { } } -/// A file that is generated by a build step. -/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic. -pub const GeneratedFile = struct { - /// The step that generates the file. - step: *Step, -}; - // dirnameAllowEmpty is a variant of fs.path.dirname // that allows "" to refer to the root for relative paths. // @@ -2114,7 +2116,7 @@ pub const LazyPath = union(enum) { }, generated: struct { - file: *const GeneratedFile, + index: Configuration.GeneratedFileIndex, /// The number of parent directories to go up. /// 0 means the generated file itself. @@ -2242,7 +2244,11 @@ pub const LazyPath = union(enum) { pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void { switch (lazy_path) { .src_path, .cwd_relative, .dependency => {}, - .generated => |gen| other_step.dependOn(gen.file.step), + .generated => |gen| { + const graph = other_step.owner.graph; + const generated_owner_step = graph.generated_files.items[@intFromEnum(gen.index)]; + other_step.dependOn(generated_owner_step); + }, } } @@ -2266,7 +2272,7 @@ pub const LazyPath = union(enum) { return lazy_path.dupeInner(b.allocator); } - fn dupeInner(lazy_path: LazyPath, allocator: std.mem.Allocator) LazyPath { + fn dupeInner(lazy_path: LazyPath, allocator: Allocator) LazyPath { return switch (lazy_path) { .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, @@ -2274,7 +2280,7 @@ pub const LazyPath = union(enum) { } }, .cwd_relative => |p| .{ .cwd_relative = dupePathInner(allocator, p) }, .generated => |gen| .{ .generated = .{ - .file = gen.file, + .index = gen.index, .up = gen.up, .sub_path = dupePathInner(allocator, gen.sub_path), } }, diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 2074eb85db..22100e1b2e 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -89,7 +89,8 @@ pub const CSourceLanguage = enum { /// Assembly with the C preprocessor assembly_with_preprocessor, - pub fn internalIdentifier(self: CSourceLanguage) []const u8 { + /// The value passed to "-x" CLI flag of Clang. + pub fn clangIdentifier(self: CSourceLanguage) [:0]const u8 { return switch (self) { .c => "c", .cpp => "c++", @@ -164,33 +165,6 @@ pub const IncludeDir = union(enum) { other_step: *Step.Compile, config_header_step: *Step.ConfigHeader, embed_path: LazyPath, - - pub fn appendZigProcessFlags( - include_dir: IncludeDir, - b: *std.Build, - zig_args: *std.array_list.Managed([]const u8), - asking_step: ?*Step, - ) !void { - const flag: []const u8, const lazy_path: LazyPath = switch (include_dir) { - // zig fmt: off - .path => |lp| .{ "-I", lp }, - .path_system => |lp| .{ "-isystem", lp }, - .path_after => |lp| .{ "-idirafter", lp }, - .framework_path => |lp| .{ "-F", lp }, - .framework_path_system => |lp| .{ "-iframework", lp }, - .config_header_step => |ch| .{ "-I", ch.getOutputDir() }, - .other_step => |comp| .{ "-I", comp.installed_headers_include_tree.?.getDirectory() }, - // zig fmt: on - .embed_path => |lazy_path| { - // Special case: this is a single arg. - const resolved = lazy_path.getPath3(b, asking_step); - const arg = b.fmt("--embed-dir={f}", .{resolved}); - return zig_args.append(arg); - }, - }; - const resolved_str = try lazy_path.getPath3(b, asking_step).toString(b.graph.arena); - return zig_args.appendSlice(&.{ flag, resolved_str }); - } }; pub const LinkFrameworkOptions = struct { @@ -533,117 +507,6 @@ pub fn addCMacro(m: *Module, name: []const u8, value: []const u8) void { m.c_macros.append(b.allocator, b.fmt("-D{s}={s}", .{ name, value })) catch @panic("OOM"); } -pub fn appendZigProcessFlags( - m: *Module, - zig_args: *std.array_list.Managed([]const u8), - asking_step: ?*Step, -) !void { - const b = m.owner; - - try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip"); - try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded"); - try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check"); - try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector"); - try addFlag(zig_args, m.omit_frame_pointer, "-fomit-frame-pointer", "-fno-omit-frame-pointer"); - try addFlag(zig_args, m.error_tracing, "-ferror-tracing", "-fno-error-tracing"); - try addFlag(zig_args, m.sanitize_thread, "-fsanitize-thread", "-fno-sanitize-thread"); - try addFlag(zig_args, m.fuzz, "-ffuzz", "-fno-fuzz"); - try addFlag(zig_args, m.valgrind, "-fvalgrind", "-fno-valgrind"); - try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC"); - try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone"); - try addFlag(zig_args, m.no_builtin, "-fno-builtin", "-fbuiltin"); - - if (m.sanitize_c) |sc| switch (sc) { - .off => try zig_args.append("-fno-sanitize-c"), - .trap => try zig_args.append("-fsanitize-c=trap"), - .full => try zig_args.append("-fsanitize-c=full"), - }; - - if (m.dwarf_format) |dwarf_format| { - try zig_args.append(switch (dwarf_format) { - .@"32" => "-gdwarf32", - .@"64" => "-gdwarf64", - }); - } - - if (m.unwind_tables) |unwind_tables| { - try zig_args.append(switch (unwind_tables) { - .none => "-fno-unwind-tables", - .sync => "-funwind-tables", - .async => "-fasync-unwind-tables", - }); - } - - try zig_args.ensureUnusedCapacity(1); - if (m.optimize) |optimize| switch (optimize) { - .Debug => zig_args.appendAssumeCapacity("-ODebug"), - .ReleaseSmall => zig_args.appendAssumeCapacity("-OReleaseSmall"), - .ReleaseFast => zig_args.appendAssumeCapacity("-OReleaseFast"), - .ReleaseSafe => zig_args.appendAssumeCapacity("-OReleaseSafe"), - }; - - if (m.code_model != .default) { - try zig_args.append("-mcmodel"); - try zig_args.append(@tagName(m.code_model)); - } - - if (m.resolved_target) |*target| { - // Communicate the query via CLI since it's more compact. - if (!target.query.isNative()) { - try zig_args.appendSlice(&.{ - "-target", try target.query.zigTriple(b.allocator), - "-mcpu", try target.query.serializeCpuAlloc(b.allocator), - }); - if (target.query.dynamic_linker) |*dynamic_linker| { - if (dynamic_linker.get()) |dynamic_linker_path| { - try zig_args.append("--dynamic-linker"); - try zig_args.append(dynamic_linker_path); - } else { - try zig_args.append("--no-dynamic-linker"); - } - } - } - } - - for (m.export_symbol_names) |symbol_name| { - try zig_args.append(b.fmt("--export={s}", .{symbol_name})); - } - - for (m.include_dirs.items) |include_dir| { - try include_dir.appendZigProcessFlags(b, zig_args, asking_step); - } - - try zig_args.appendSlice(m.c_macros.items); - - try zig_args.ensureUnusedCapacity(2 * m.lib_paths.items.len); - for (m.lib_paths.items) |lib_path| { - zig_args.appendAssumeCapacity("-L"); - zig_args.appendAssumeCapacity(lib_path.getPath2(b, asking_step)); - } - - try zig_args.ensureUnusedCapacity(2 * m.rpaths.items.len); - for (m.rpaths.items) |rpath| switch (rpath) { - .lazy_path => |lp| { - zig_args.appendAssumeCapacity("-rpath"); - zig_args.appendAssumeCapacity(lp.getPath2(b, asking_step)); - }, - .special => |bytes| { - zig_args.appendAssumeCapacity("-rpath"); - zig_args.appendAssumeCapacity(bytes); - }, - }; -} - -fn addFlag( - args: *std.array_list.Managed([]const u8), - opt: ?bool, - then_name: []const u8, - else_name: []const u8, -) !void { - const cond = opt orelse return; - return args.append(if (cond) then_name else else_name); -} - fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void { const allocator = m.owner.allocator; _ = other.getEmittedBin(); // Indicate there is a dependency on the outputted binary. diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 76d45a54a1..9b0260c39e 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1,4 +1,5 @@ const Compile = @This(); + const builtin = @import("builtin"); const std = @import("std"); @@ -13,8 +14,8 @@ const Step = std.Build.Step; const LazyPath = std.Build.LazyPath; const Module = std.Build.Module; const InstallDir = std.Build.InstallDir; -const GeneratedFile = std.Build.GeneratedFile; const Path = std.Build.Cache.Path; +const Configuration = std.Build.Configuration; pub const base_tag: Step.Tag = .compile; @@ -212,19 +213,6 @@ allow_so_scripts: ?bool = null, /// otherwise. expect_errors: ?ExpectedCompileErrors = null, -emit_directory: ?*GeneratedFile, - -generated_docs: ?*GeneratedFile, -generated_asm: ?*GeneratedFile, -generated_bin: ?*GeneratedFile, -generated_pdb: ?*GeneratedFile, -// hack for stage2_x86_64 + coff -generated_compiler_rt_dyn_lib: ?*GeneratedFile, -generated_implib: ?*GeneratedFile, -generated_llvm_bc: ?*GeneratedFile, -generated_llvm_ir: ?*GeneratedFile, -generated_h: ?*GeneratedFile, - /// The maximum number of distinct errors within a compilation step Defaults to /// `std.math.maxInt(u16)`. Overrides the argument passed to `zig build`. error_limit: ?u32 = null, @@ -248,6 +236,16 @@ is_linking_libcpp: bool = false, /// builtin fuzzer, see the `fuzz` flag in `Module`. sanitize_coverage_trace_pc_guard: ?bool = null, +emit_directory: Configuration.OptionalGeneratedFileIndex = .none, +generated_docs: Configuration.OptionalGeneratedFileIndex = .none, +generated_asm: Configuration.OptionalGeneratedFileIndex = .none, +generated_bin: Configuration.OptionalGeneratedFileIndex = .none, +generated_pdb: Configuration.OptionalGeneratedFileIndex = .none, +generated_implib: Configuration.OptionalGeneratedFileIndex = .none, +generated_llvm_bc: Configuration.OptionalGeneratedFileIndex = .none, +generated_llvm_ir: Configuration.OptionalGeneratedFileIndex = .none, +generated_h: Configuration.OptionalGeneratedFileIndex = .none, + pub const ExpectedCompileErrors = union(enum) { contains: []const u8, exact: []const []const u8, @@ -291,7 +289,7 @@ pub const Options = struct { entitlements: ?LazyPath = null, }; -pub const Kind = std.Build.Configuration.Step.Compile.Kind; +pub const Kind = Configuration.Step.Compile.Kind; pub const HeaderInstallation = union(enum) { file: File, @@ -362,6 +360,9 @@ pub const TestRunner = struct { }; pub fn create(owner: *std.Build, options: Options) *Compile { + const graph = owner.graph; + const arena = graph.arena; + const name = owner.dupe(options.name); if (mem.find(u8, name, "/") != null or mem.find(u8, name, "\\") != null) { panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); @@ -376,12 +377,12 @@ pub fn create(owner: *std.Build, options: Options) *Compile { if (options.kind.isTest() and mem.eql(u8, name, "test")) @tagName(options.kind) else - owner.fmt("{s} {s}", .{ @tagName(options.kind), name }), + owner.fmt("{t} {s}", .{ options.kind, name }), @tagName(options.root_module.optimize orelse .Debug), - resolved_target.query.zigTriple(owner.allocator) catch @panic("OOM"), + resolved_target.query.zigTriple(arena) catch @panic("OOM"), }); - const out_filename = std.zig.binNameAlloc(owner.allocator, .{ + const out_filename = std.zig.binNameAlloc(arena, .{ .root_name = name, .target = target, .output_mode = switch (options.kind) { @@ -393,7 +394,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { .version = options.version, }) catch @panic("OOM"); - const compile = owner.allocator.create(Compile) catch @panic("OOM"); + const compile = arena.create(Compile) catch @panic("OOM"); compile.* = .{ .root_module = options.root_module, .verbose_link = false, @@ -420,17 +421,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile { .rdynamic = false, .force_undefined_symbols = .empty, - .emit_directory = null, - .generated_docs = null, - .generated_asm = null, - .generated_bin = null, - .generated_pdb = null, - .generated_compiler_rt_dyn_lib = null, - .generated_implib = null, - .generated_llvm_bc = null, - .generated_llvm_ir = null, - .generated_h = null, - .use_llvm = options.use_llvm, .use_lld = options.use_lld, .use_new_linker = null, @@ -710,13 +700,12 @@ pub fn setLibCFile(compile: *Compile, libc_file: ?LazyPath) void { } } -fn getEmittedFileGeneric(compile: *Compile, output_file: *?*GeneratedFile) LazyPath { - if (output_file.*) |file| return .{ .generated = .{ .file = file } }; - const arena = compile.step.owner.allocator; - const generated_file = arena.create(GeneratedFile) catch @panic("OOM"); - generated_file.* = .{ .step = &compile.step }; - output_file.* = generated_file; - return .{ .generated = .{ .file = generated_file } }; +fn getEmittedFileGeneric(compile: *Compile, output_file: *Configuration.OptionalGeneratedFileIndex) LazyPath { + if (output_file.unwrap()) |index| return .{ .generated = .{ .index = index } }; + const graph = compile.step.owner.graph; + const index = graph.addGeneratedFile(&compile.step); + output_file.* = .init(index); + return .{ .generated = .{ .index = index } }; } /// Returns the path to the directory that contains the emitted binary file. @@ -789,46 +778,6 @@ pub fn setExecCmd(compile: *Compile, args: []const ?[]const u8) void { compile.exec_cmd_args = duped_args; } -fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) ![]const u8 { - const step = &compile.step; - const b = step.owner; - const graph = b.graph; - const io = graph.io; - const maybe_path: ?*GeneratedFile = @field(compile, tag_name); - - const generated_file = maybe_path orelse { - const stderr = try io.lockStderr(&.{}, graph.stderr_mode); - std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {}; - io.unlockStderr(); - @panic("missing emit option for " ++ tag_name); - }; - - const path = generated_file.path orelse { - const stderr = try io.lockStderr(&.{}, graph.stderr_mode); - std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {}; - io.unlockStderr(); - @panic(tag_name ++ " is null. Is there a missing step dependency?"); - }; - - return path; -} - -fn outputPath(c: *Compile, out_dir: std.Build.Cache.Path, ea: std.zig.EmitArtifact) []const u8 { - const arena = c.step.owner.graph.arena; - const name = ea.cacheName(arena, .{ - .root_name = c.name, - .target = &c.root_module.resolved_target.?.result, - .output_mode = switch (c.kind) { - .lib => .Lib, - .obj, .test_obj => .Obj, - .exe, .@"test" => .Exe, - }, - .link_mode = c.linkage, - .version = c.version, - }) catch @panic("OOM"); - return out_dir.joinString(arena, name) catch @panic("OOM"); -} - pub fn rootModuleTarget(c: *Compile) std.Target { // The root module is always given a target, so we know this to be non-null. return c.root_module.resolved_target.?.result; diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index be2216b905..242e2069c3 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -5,6 +5,7 @@ const Io = std.Io; const Step = std.Build.Step; const Allocator = std.mem.Allocator; const Writer = std.Io.Writer; +const Configuration = std.Build.Configuration; pub const Style = union(enum) { /// A configure format supported by autotools that uses `#undef foo` to @@ -40,7 +41,7 @@ pub const Value = union(enum) { step: Step, values: std.array_hash_map.String(Value), /// This directory contains the generated file under the name `include_path`. -generated_dir: std.Build.GeneratedFile, +generated_dir: Configuration.GeneratedFileIndex, style: Style, max_bytes: usize, @@ -58,7 +59,9 @@ pub const Options = struct { }; pub fn create(owner: *std.Build, options: Options) *ConfigHeader { - const config_header = owner.allocator.create(ConfigHeader) catch @panic("OOM"); + const graph = owner.graph; + const arena = graph.arena; + const config_header = arena.create(ConfigHeader) catch @panic("OOM"); var include_path: []const u8 = "config.h"; @@ -80,11 +83,9 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { } const name = if (options.style.getPath()) |s| - owner.fmt("configure {s} header {s} to {s}", .{ - @tagName(options.style), s.getDisplayName(), include_path, - }) + owner.fmt("configure {t} header {s} to {s}", .{ options.style, s.getDisplayName(), include_path }) else - owner.fmt("configure {s} header to {s}", .{ @tagName(options.style), include_path }); + owner.fmt("configure {t} header to {s}", .{ options.style, include_path }); config_header.* = .{ .step = .init(.{ @@ -100,7 +101,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { .max_bytes = options.max_bytes, .include_path = include_path, .include_guard_override = options.include_guard_override, - .generated_dir = .{ .step = &config_header.step }, + .generated_dir = graph.addGeneratedFile(&config_header.step), }; if (options.style.getPath()) |s| { @@ -125,7 +126,7 @@ pub fn addValues(config_header: *ConfigHeader, values: anytype) void { } pub fn getOutputDir(ch: *ConfigHeader) std.Build.LazyPath { - return .{ .generated = .{ .file = &ch.generated_dir } }; + return .{ .generated = .{ .index = &ch.generated_dir } }; } pub fn getOutputFile(ch: *ConfigHeader) std.Build.LazyPath { return ch.getOutputDir().path(ch.step.owner, ch.include_path); diff --git a/lib/std/Build/Step/ObjCopy.zig b/lib/std/Build/Step/ObjCopy.zig index 5ab21c3bcc..d7de00c0ef 100644 --- a/lib/std/Build/Step/ObjCopy.zig +++ b/lib/std/Build/Step/ObjCopy.zig @@ -9,6 +9,7 @@ const Step = std.Build.Step; const elf = std.elf; const fs = std.fs; const sort = std.sort; +const Configuration = std.Build.Configuration; pub const base_tag: Step.Tag = .objcopy; @@ -71,8 +72,8 @@ pub const SetSectionFlags = struct { step: Step, input_file: std.Build.LazyPath, basename: []const u8, -output_file: std.Build.GeneratedFile, -output_file_debug: ?std.Build.GeneratedFile, +output_file: Configuration.GeneratedFileIndex, +output_file_debug: Configuration.OptionalGeneratedFileIndex, format: ?RawFormat, only_section: ?[]const u8, @@ -108,7 +109,10 @@ pub fn create( input_file: std.Build.LazyPath, options: Options, ) *ObjCopy { - const objcopy = owner.allocator.create(ObjCopy) catch @panic("OOM"); + const graph = owner.graph; + const arena = graph.arena; + + const objcopy = arena.create(ObjCopy) catch @panic("OOM"); objcopy.* = ObjCopy{ .step = Step.init(.{ .tag = base_tag, @@ -118,8 +122,11 @@ pub fn create( }), .input_file = input_file, .basename = options.basename orelse input_file.getDisplayName(), - .output_file = std.Build.GeneratedFile{ .step = &objcopy.step }, - .output_file_debug = if (options.strip != .none and options.extract_to_separate_file) std.Build.GeneratedFile{ .step = &objcopy.step } else null, + .output_file = graph.addGeneratedFile(&objcopy.step), + .output_file_debug = if (options.strip != .none and options.extract_to_separate_file) + .init(graph.addGeneratedFile(&objcopy.step)) + else + .none, .format = options.format, .only_section = options.only_section, .pad_to = options.pad_to, @@ -134,10 +141,10 @@ pub fn create( } pub fn getOutput(objcopy: *const ObjCopy) std.Build.LazyPath { - return .{ .generated = .{ .file = &objcopy.output_file } }; + return .{ .generated = .{ .index = objcopy.output_file } }; } pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath { - return if (objcopy.output_file_debug) |*file| .{ .generated = .{ .file = file } } else null; + return if (objcopy.output_file_debug.unwrap()) |index| .{ .generated = .{ .index = index } } else null; } fn make(step: *Step, options: Step.MakeOptions) !void { diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index 21df380b18..1bf8266ec0 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -1,24 +1,28 @@ const Options = @This(); + const builtin = @import("builtin"); const std = @import("std"); const Io = std.Io; const fs = std.fs; const Step = std.Build.Step; -const GeneratedFile = std.Build.GeneratedFile; const LazyPath = std.Build.LazyPath; +const Configuration = std.Build.Configuration; pub const base_tag: Step.Tag = .options; step: Step, -generated_file: GeneratedFile, +generated_file: Configuration.GeneratedFileIndex, contents: std.ArrayList(u8), args: std.ArrayList(Arg), encountered_types: std.StringHashMapUnmanaged(void), pub fn create(owner: *std.Build) *Options { - const options = owner.allocator.create(Options) catch @panic("OOM"); + const graph = owner.graph; + const arena = graph.arena; + + const options = arena.create(Options) catch @panic("OOM"); options.* = .{ .step = .init(.{ .tag = base_tag, @@ -26,12 +30,11 @@ pub fn create(owner: *std.Build) *Options { .owner = owner, .makeFn = make, }), - .generated_file = undefined, + .generated_file = graph.addGeneratedFile(&options.step), .contents = .empty, .args = .empty, .encountered_types = .empty, }; - options.generated_file = .{ .step = &options.step }; return options; } @@ -434,7 +437,7 @@ pub fn createModule(options: *Options) *std.Build.Module { /// Returns the main artifact of this Build Step which is a Zig source file /// generated from the key-value pairs of the Options. pub fn getOutput(options: *Options) LazyPath { - return .{ .generated = .{ .file = &options.generated_file } }; + return .{ .generated = .{ .index = options.generated_file } }; } fn make(step: *Step, make_options: Step.MakeOptions) !void { diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index 73aeba9321..e51be09242 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -11,6 +11,7 @@ const process = std.process; const EnvMap = std.process.Environ.Map; const assert = std.debug.assert; const Path = std.Build.Cache.Path; +const Configuration = std.Build.Configuration; pub const base_tag: Step.Tag = .run; @@ -162,7 +163,7 @@ pub const DecoratedLazyPath = struct { }; pub const Output = struct { - generated_file: std.Build.GeneratedFile, + generated_file: Configuration.GeneratedFileIndex, prefix: []const u8, basename: []const u8, }; @@ -272,21 +273,23 @@ pub fn addPrefixedOutputFileArg( basename: []const u8, ) std.Build.LazyPath { const b = run.step.owner; + const graph = b.graph; + const arena = graph.arena; if (basename.len == 0) @panic("basename must not be empty"); - const output = b.allocator.create(Output) catch @panic("OOM"); + const output = arena.create(Output) catch @panic("OOM"); output.* = .{ .prefix = b.dupe(prefix), .basename = b.dupe(basename), - .generated_file = .{ .step = &run.step }, + .generated_file = graph.addGeneratedFile(&run.step), }; - run.argv.append(b.allocator, .{ .output_file = output }) catch @panic("OOM"); + run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM"); if (run.rename_step_with_output_arg) { run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename })); } - return .{ .generated = .{ .file = &output.generated_file } }; + return .{ .generated = .{ .index = output.generated_file } }; } /// Appends an input file to the command line arguments. @@ -470,20 +473,22 @@ pub fn addDepFileOutputArg(run: *Run, basename: []const u8) std.Build.LazyPath { /// Only one dep file argument is allowed by instance. pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath { const b = run.step.owner; + const graph = b.graph; + const arena = graph.arena; assert(run.dep_output_file == null); - const dep_file = b.allocator.create(Output) catch @panic("OOM"); + const dep_file = arena.create(Output) catch @panic("OOM"); dep_file.* = .{ .prefix = b.dupe(prefix), .basename = b.dupe(basename), - .generated_file = .{ .step = &run.step }, + .generated_file = graph.addGeneratedFile(&run.step), }; run.dep_output_file = dep_file; - run.argv.append(b.allocator, .{ .output_file = dep_file }) catch @panic("OOM"); + run.argv.append(arena, .{ .output_file = dep_file }) catch @panic("OOM"); - return .{ .generated = .{ .file = &dep_file.generated_file } }; + return .{ .generated = .{ .index = dep_file.generated_file } }; } pub fn addArg(run: *Run, arg: []const u8) void { @@ -627,20 +632,22 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa assert(run.stdio != .zig_test); const b = run.step.owner; + const graph = b.graph; + const arena = graph.arena; - if (run.captured_stderr) |captured| return .{ .generated = .{ .file = &captured.output.generated_file } }; + if (run.captured_stderr) |captured| return .{ .generated = .{ .index = captured.output.generated_file } }; - const captured = b.allocator.create(CapturedStdIo) catch @panic("OOM"); + const captured = arena.create(CapturedStdIo) catch @panic("OOM"); captured.* = .{ .output = .{ .prefix = "", .basename = if (options.basename) |basename| b.dupe(basename) else "stderr", - .generated_file = .{ .step = &run.step }, + .generated_file = graph.addGeneratedFile(&run.step), }, .trim_whitespace = options.trim_whitespace, }; run.captured_stderr = captured; - return .{ .generated = .{ .file = &captured.output.generated_file } }; + return .{ .generated = .{ .index = captured.output.generated_file } }; } pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPath { @@ -648,20 +655,22 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa assert(run.stdio != .zig_test); const b = run.step.owner; + const graph = b.graph; + const arena = graph.arena; - if (run.captured_stdout) |captured| return .{ .generated = .{ .file = &captured.output.generated_file } }; + if (run.captured_stdout) |captured| return .{ .generated = .{ .index = captured.output.generated_file } }; - const captured = b.allocator.create(CapturedStdIo) catch @panic("OOM"); + const captured = arena.create(CapturedStdIo) catch @panic("OOM"); captured.* = .{ .output = .{ .prefix = "", .basename = if (options.basename) |basename| b.dupe(basename) else "stdout", - .generated_file = .{ .step = &run.step }, + .generated_file = graph.addGeneratedFile(&run.step), }, .trim_whitespace = options.trim_whitespace, }; run.captured_stdout = captured; - return .{ .generated = .{ .file = &captured.output.generated_file } }; + return .{ .generated = .{ .index = captured.output.generated_file } }; } /// Adds an additional input files that, when modified, indicates that this Run diff --git a/lib/std/Build/Step/TranslateC.zig b/lib/std/Build/Step/TranslateC.zig index 90d9e28155..0c0844d070 100644 --- a/lib/std/Build/Step/TranslateC.zig +++ b/lib/std/Build/Step/TranslateC.zig @@ -1,10 +1,11 @@ +const TranslateC = @This(); + const std = @import("std"); const Step = std.Build.Step; const LazyPath = std.Build.LazyPath; const fs = std.fs; const mem = std.mem; - -const TranslateC = @This(); +const Configuration = std.Build.Configuration; pub const base_tag: Step.Tag = .translate_c; @@ -16,7 +17,7 @@ c_macros: std.array_list.Managed([]const u8), out_basename: []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, -output_file: std.Build.GeneratedFile, +output_file: Configuration.GeneratedFileIndex, link_libc: bool, pub const Options = struct { @@ -27,7 +28,9 @@ pub const Options = struct { }; pub fn create(owner: *std.Build, options: Options) *TranslateC { - const translate_c = owner.allocator.create(TranslateC) catch @panic("OOM"); + const graph = owner.graph; + const arena = graph.arena; + const translate_c = arena.create(TranslateC) catch @panic("OOM"); const source = options.root_source_file.dupe(owner); translate_c.* = .{ .step = Step.init(.{ @@ -37,12 +40,12 @@ pub fn create(owner: *std.Build, options: Options) *TranslateC { .makeFn = make, }), .source = source, - .include_dirs = std.array_list.Managed(std.Build.Module.IncludeDir).init(owner.allocator), - .c_macros = std.array_list.Managed([]const u8).init(owner.allocator), + .include_dirs = std.array_list.Managed(std.Build.Module.IncludeDir).init(arena), + .c_macros = std.array_list.Managed([]const u8).init(arena), .out_basename = undefined, .target = options.target, .optimize = options.optimize, - .output_file = .{ .step = &translate_c.step }, + .output_file = graph.addGeneratedFile(&translate_c.step), .link_libc = options.link_libc, .system_libs = .empty, }; @@ -59,7 +62,7 @@ pub const AddExecutableOptions = struct { }; pub fn getOutput(translate_c: *TranslateC) std.Build.LazyPath { - return .{ .generated = .{ .file = &translate_c.output_file } }; + return .{ .generated = .{ .index = translate_c.output_file } }; } /// Creates a module from the translated source and adds it to the package's diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig index 06f030efbc..14097a76ed 100644 --- a/lib/std/Build/Step/WriteFile.zig +++ b/lib/std/Build/Step/WriteFile.zig @@ -9,13 +9,13 @@ const Dir = std.Io.Dir; const Step = std.Build.Step; const ArrayList = std.ArrayList; const assert = std.debug.assert; +const Configuration = std.Build.Configuration; step: Step, -/// The elements here are pointers because we need stable pointers for the GeneratedFile field. files: std.ArrayList(File), directories: std.ArrayList(Directory), -generated_directory: std.Build.GeneratedFile, +generated_directory: Configuration.GeneratedFileIndex, mode: Mode = .whole_cached, pub const base_tag: Step.Tag = .write_file; @@ -86,7 +86,9 @@ pub const Contents = union(enum) { }; pub fn create(owner: *std.Build) *WriteFile { - const write_file = owner.allocator.create(WriteFile) catch @panic("OOM"); + const graph = owner.graph; + const arena = graph.arena; + const write_file = arena.create(WriteFile) catch @panic("OOM"); write_file.* = .{ .step = Step.init(.{ .tag = base_tag, @@ -95,7 +97,7 @@ pub fn create(owner: *std.Build) *WriteFile { }), .files = .empty, .directories = .empty, - .generated_directory = .{ .step = &write_file.step }, + .generated_directory = graph.addGeneratedFile(&write_file.step), }; return write_file; } @@ -111,7 +113,7 @@ pub fn add(write_file: *WriteFile, sub_path: []const u8, bytes: []const u8) std. write_file.maybeUpdateName(); return .{ .generated = .{ - .file = &write_file.generated_directory, + .index = write_file.generated_directory, .sub_path = file.sub_path, }, }; @@ -137,7 +139,7 @@ pub fn addCopyFile(write_file: *WriteFile, source: std.Build.LazyPath, sub_path: source.addStepDependencies(&write_file.step); return .{ .generated = .{ - .file = &write_file.generated_directory, + .index = write_file.generated_directory, .sub_path = file.sub_path, }, }; @@ -165,7 +167,7 @@ pub fn addCopyDirectory( source.addStepDependencies(&write_file.step); return .{ .generated = .{ - .file = &write_file.generated_directory, + .index = write_file.generated_directory, .sub_path = dir.sub_path, }, }; @@ -174,7 +176,7 @@ pub fn addCopyDirectory( /// Returns a `LazyPath` representing the base directory that contains all the /// files from this `WriteFile`. pub fn getDirectory(write_file: *WriteFile) std.Build.LazyPath { - return .{ .generated = .{ .file = &write_file.generated_directory } }; + return .{ .generated = .{ .index = write_file.generated_directory } }; } fn maybeUpdateName(write_file: *WriteFile) void { diff --git a/lib/std/zig/Configuration.zig b/lib/std/zig/Configuration.zig index 23d027e777..b01c6cd8bc 100644 --- a/lib/std/zig/Configuration.zig +++ b/lib/std/zig/Configuration.zig @@ -15,6 +15,7 @@ system_integrations: []SystemIntegration, available_options: []AvailableOption, extra: []u32, default_step: Step.Index, +generated_files_len: u32, /// The field order here matches `Configuration` which documents the order in /// the serialized format. @@ -28,6 +29,9 @@ pub const Header = extern struct { extra_len: u32, default_step: Step.Index, + /// There is not actually any data stored for this - it just provides a way + /// for maker process to preallocate an array for these. + generated_files_len: u32, }; pub const Wip = struct { @@ -44,6 +48,7 @@ pub const Wip = struct { steps: std.ArrayList(Step) = .empty, path_deps: std.MultiArrayList(Path) = .empty, extra: std.ArrayList(u32) = .empty, + next_generated_file_index: u32 = 0, const DedupeTable = std.HashMapUnmanaged(ExtraSlice, void, ExtraSlice.Context, std.hash_map.default_max_load_percentage); const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage); @@ -127,6 +132,7 @@ pub const Wip = struct { pub const Static = struct { default_step: Step.Index, + generated_files_len: u32, }; pub fn write(wip: *Wip, w: *Io.Writer, static: Static) Io.Writer.Error!void { @@ -140,6 +146,7 @@ pub const Wip = struct { .extra_len = @intCast(wip.extra.items.len), .default_step = static.default_step, + .generated_files_len = static.generated_files_len, }; var buffers = [_][]const u8{ @ptrCast(&header), @@ -363,6 +370,11 @@ pub const Wip = struct { const string = optional_string orelse return; wip.extra.appendAssumeCapacity(@intFromEnum(string)); } + + pub fn addGeneratedFile(wip: *Wip) GeneratedFileIndex { + defer wip.next_generated_file_index += 1; + return @enumFromInt(wip.next_generated_file_index); + } }; pub const SystemIntegration = extern struct { @@ -471,16 +483,16 @@ pub const Step = extern struct { dest_dir: InstallDestDir, dest_sub_path: String, - emitted_bin: OptionalLazyPath, + emitted_bin: LazyPath.OptionalIndex, implib_dir: InstallDestDir, - emitted_implib: OptionalLazyPath, + emitted_implib: LazyPath.OptionalIndex, pdb_dir: InstallDestDir, - emitted_pdb: OptionalLazyPath, + emitted_pdb: LazyPath.OptionalIndex, h_dir: InstallDestDir, - emitted_h: OptionalLazyPath, + emitted_h: LazyPath.OptionalIndex, /// Always a compile step. artifact: Step.Index, @@ -493,11 +505,11 @@ pub const Step = extern struct { }; /// Trailing: - /// * LazyPath for each file_inputs_len + /// * LazyPath.Index for each file_inputs_len /// * Arg for each args_len /// * environ_map if corresponding flag is set /// * stdin: Bytes, // if StdIn.bytes is chosen - /// * stdin: LazyPath, // if StdIn.lazy_path is chosen + /// * stdin: LazyPath.Index, // if StdIn.lazy_path is chosen /// * checks: Checks, // if StdIo.check is chosen /// * stdio_limit: u64, // if stdio_limit is set /// * producer: Step.Index, // if producer is set. always compile step @@ -505,7 +517,7 @@ pub const Step = extern struct { flags: @This().Flags, file_inputs_len: u32, args_len: u32, - cwd: OptionalLazyPath, + cwd: LazyPath.OptionalIndex, captured_stdout: OptionalString, // basename captured_stderr: OptionalString, // basename @@ -514,7 +526,7 @@ pub const Step = extern struct { /// * String if suffix set /// * String if basename set /// * Step.Index which is always a compile step if tag is artifact - /// * LazyPath if tag is path_file, path_directory, or file_content + /// * LazyPath.Index if tag is path_file, path_directory, or file_content pub const Arg = struct { flags: Arg.Flags, @@ -591,13 +603,13 @@ pub const Step = extern struct { installed_headers: Storage.FlagLengthPrefixedList(.flags, .installed_headers_len, Storage.Extended(InstalledHeader.Flags, InstalledHeader)), force_undefined_symbols: Storage.FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String), expect_errors: Storage.FlagUnion(.flags4, .expect_errors, ExpectErrors), - linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath), - version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath), - zig_lib_dir: Storage.FlagOptional(.flags3, .zig_lib_dir, LazyPath), - libc_file: Storage.FlagOptional(.flags4, .libc_file, LazyPath), - win32_manifest: Storage.FlagOptional(.flags3, .win32_manifest, LazyPath), - win32_module_definition: Storage.FlagOptional(.flags3, .win32_module_definition, LazyPath), - entitlements: Storage.FlagOptional(.flags4, .entitlements, LazyPath), + linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath.Index), + version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath.Index), + zig_lib_dir: Storage.FlagOptional(.flags3, .zig_lib_dir, LazyPath.Index), + libc_file: Storage.FlagOptional(.flags4, .libc_file, LazyPath.Index), + win32_manifest: Storage.FlagOptional(.flags3, .win32_manifest, LazyPath.Index), + win32_module_definition: Storage.FlagOptional(.flags3, .win32_module_definition, LazyPath.Index), + entitlements: Storage.FlagOptional(.flags4, .entitlements, LazyPath.Index), version: Storage.FlagOptional(.flags3, .version, String), // semantic version string entry: Storage.EnumOptional(.flags3, .entry, .symbol_name, String), install_name: Storage.FlagOptional(.flags4, .install_name, String), @@ -614,6 +626,16 @@ pub const Step = extern struct { build_id: Storage.EnumOptional(.flags3, .build_id, .hexstring, String), test_runner: Storage.FlagUnion(.flags3, .test_runner, TestRunner), + emit_directory: Storage.FlagOptional(.flags4, .emit_directory, GeneratedFileIndex), + generated_docs: Storage.FlagOptional(.flags4, .generated_docs, GeneratedFileIndex), + generated_asm: Storage.FlagOptional(.flags4, .generated_asm, GeneratedFileIndex), + generated_bin: Storage.FlagOptional(.flags4, .generated_bin, GeneratedFileIndex), + generated_pdb: Storage.FlagOptional(.flags4, .generated_pdb, GeneratedFileIndex), + generated_implib: Storage.FlagOptional(.flags4, .generated_implib, GeneratedFileIndex), + generated_llvm_bc: Storage.FlagOptional(.flags4, .generated_llvm_bc, GeneratedFileIndex), + generated_llvm_ir: Storage.FlagOptional(.flags4, .generated_llvm_ir, GeneratedFileIndex), + generated_h: Storage.FlagOptional(.flags4, .generated_h, GeneratedFileIndex), + pub const InstalledHeader = union(@This().Tag) { file: File, directory: Directory, @@ -630,7 +652,7 @@ pub const Step = extern struct { pub const File = struct { flags: @This().Flags = .{}, - source: LazyPath, + source: LazyPath.Index, dest_sub_path: String, pub const Flags = packed struct(u32) { @@ -641,7 +663,7 @@ pub const Step = extern struct { pub const Directory = struct { flags: @This().Flags, - source: LazyPath, + source: LazyPath.Index, dest_sub_path: String, exclude_extensions: Storage.FlagLengthPrefixedList(.flags, .exclude_extensions, String), include_extensions: Storage.FlagLengthPrefixedList(.flags, .include_extensions, String), @@ -667,8 +689,8 @@ pub const Step = extern struct { pub const Tag = enum(u2) { default, simple, server }; default: void, - simple: LazyPath, - server: LazyPath, + simple: LazyPath.Index, + server: LazyPath.Index, }; pub const Entry = enum(u2) { default, disabled, enabled, symbol_name }; @@ -857,12 +879,37 @@ pub const Step = extern struct { expect_errors: ExpectErrors.Tag, linker_script: bool, version_script: bool, - _: u18 = 0, + emit_directory: bool, + generated_docs: bool, + generated_asm: bool, + generated_bin: bool, + generated_pdb: bool, + generated_implib: bool, + generated_llvm_bc: bool, + generated_llvm_ir: bool, + generated_h: bool, + _: u9 = 0, }; pub fn isDynamicLibrary(compile: *const Compile) bool { return compile.flags3.kind == .lib and compile.flags2.linkage == .dynamic; } + + pub fn isStaticLibrary(compile: *const Compile) bool { + return compile.flags3.kind == .lib and compile.flags2.linkage != .dynamic; + } + + pub fn producesImplib(compile: *const Compile, c: *const Configuration) bool { + return isDll(compile, c); + } + + pub fn isDll(compile: *const Compile, c: *const Configuration) bool { + return isDynamicLibrary(compile) and rootModuleTarget(compile, c).flags.os_tag == .windows; + } + + pub fn rootModuleTarget(compile: *const Compile, c: *const Configuration) TargetQuery { + return compile.root_module.get(c).resolved_target.get(c).?.result.get(c); + } }; pub const CheckFile = struct { @@ -1001,32 +1048,49 @@ pub const MaxRss = enum(u32) { } }; -/// An index into `extra`, or `null`. -pub const OptionalLazyPath = enum(u32) { - none = maxInt(u32), - _, - - pub fn unwrap(this: @This()) ?LazyPath { - return switch (this) { - .none => null, - else => @enumFromInt(@intFromEnum(this)), - }; - } -}; - -/// An index into `extra`. -pub const LazyPath = enum(u32) { - _, +pub const LazyPath = union(@This().Tag) { + source_path: SourcePath, + relative: Relative, + generated: Generated, pub const Tag = enum(u8) { /// A source file path relative to build root. source_path, - generated, + /// Relative to the directory indicated in flags. relative, + /// Path is available only after it is populated by its owning step. + generated, + }; + + pub const Flags = packed struct(u32) { + tag: Tag, + _: u24 = 0, + }; + + /// An index into `extra`. + pub const Index = enum(u32) { + _, + + pub fn get(this: @This(), c: *const Configuration) LazyPath { + return extraData(c, LazyPath, @intFromEnum(this)); + } + }; + + /// An index into `extra`, or `null`. + pub const OptionalIndex = enum(u32) { + none = maxInt(u32), + _, + + pub fn unwrap(this: @This()) ?Index { + return switch (this) { + .none => null, + else => @enumFromInt(@intFromEnum(this)), + }; + } }; pub const SourcePath = struct { - flags: Flags, + flags: @This().Flags, owner: Package.Index, sub_path: String, @@ -1037,9 +1101,10 @@ pub const LazyPath = enum(u32) { }; pub const Generated = struct { - flags: Flags, + flags: @This().Flags = .{}, + index: GeneratedFileIndex, /// Applied after `up`. - sub_path: String, + sub_path: String = .empty, pub const Flags = packed struct(u32) { tag: Tag = .generated, @@ -1047,12 +1112,12 @@ pub const LazyPath = enum(u32) { /// 0 means the generated file itself. /// 1 means the directory of the generated file. /// 2 means the parent of that directory, and so on. - up: u24, + up: u24 = 0, }; }; pub const Relative = struct { - flags: Flags, + flags: @This().Flags, sub_path: String, pub const Flags = packed struct(u32) { @@ -1063,6 +1128,26 @@ pub const LazyPath = enum(u32) { }; }; +pub const GeneratedFileIndex = enum(u32) { + _, +}; + +pub const OptionalGeneratedFileIndex = enum(u32) { + none = maxInt(u32), + _, + + pub fn init(i: ?GeneratedFileIndex) OptionalGeneratedFileIndex { + return @enumFromInt(@intFromEnum(i orelse return .none)); + } + + pub fn unwrap(this: @This()) ?GeneratedFileIndex { + return switch (this) { + .none => null, + else => @enumFromInt(@intFromEnum(this)), + }; + } +}; + pub const Package = struct { dep_prefix: String, hash: String, @@ -1071,9 +1156,15 @@ pub const Package = struct { root = maxInt(u32), _, - pub fn depPrefixSlice(i: Index, c: *const Configuration) [:0]const u8 { - if (i == .root) return ""; - return extraData(c, Package, @intFromEnum(i)).dep_prefix.slice(c); + /// Returns `null` for root package. + pub fn get(i: @This(), c: *const Configuration) ?Package { + if (i == .root) return null; + return extraData(c, Package, @intFromEnum(i)); + } + + pub fn depPrefixSlice(i: @This(), c: *const Configuration) [:0]const u8 { + const package = get(i, c) orelse return ""; + return package.dep_prefix.slice(c); } }; }; @@ -1083,10 +1174,10 @@ pub const Module = struct { flags2: Flags2, import_table: ImportTable.Index, owner: Package.Index, - root_source_file: OptionalLazyPath, + root_source_file: LazyPath.OptionalIndex, resolved_target: ResolvedTarget.OptionalIndex, c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String), - lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath), + lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath.Index), export_symbol_names: Storage.FlagLengthPrefixedList(.flags, .export_symbol_names, String), include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir), rpaths: Storage.UnionList(.flags, .rpaths, RPath), @@ -1195,29 +1286,29 @@ pub const Module = struct { }; pub const IncludeDir = union(enum(u3)) { - path: LazyPath, - path_system: LazyPath, - path_after: LazyPath, - framework_path: LazyPath, - framework_path_system: LazyPath, + path: LazyPath.Index, + path_system: LazyPath.Index, + path_after: LazyPath.Index, + framework_path: LazyPath.Index, + framework_path_system: LazyPath.Index, /// Always `Step.Tag.compile`. other_step: Step.Index, /// Always `Step.Tag.config_header`. config_header_step: Step.Index, - embed_path: LazyPath, + embed_path: LazyPath.Index, }; pub const RPath = union(enum(u1)) { - lazy_path: LazyPath, + lazy_path: LazyPath.Index, special: String, }; pub const LinkObject = union(enum(u3)) { - static_path: LazyPath, + static_path: LazyPath.Index, /// Always `Step.Tag.compile`. other_step: Step.Index, system_lib: SystemLib.Index, - assembly_file: LazyPath, + assembly_file: LazyPath.Index, c_source_file: CSourceFile.Index, c_source_files: CSourceFiles.Index, win32_resource_file: RcSourceFile.Index, @@ -1376,6 +1467,10 @@ pub const SystemLib = struct { pub const Index = enum(u32) { _, + + pub fn get(this: @This(), c: *const Configuration) SystemLib { + return extraData(c, SystemLib, @intFromEnum(this)); + } }; pub const UsePkgConfig = enum(u2) { @@ -1405,12 +1500,16 @@ pub const SystemLib = struct { pub const CSourceFiles = struct { flags: Flags, - root: LazyPath, + root: LazyPath.Index, args: Storage.FlagList(.flags, .args_len, String), sub_paths: Storage.LengthPrefixedList(String), pub const Index = enum(u32) { _, + + pub fn get(this: @This(), c: *const Configuration) CSourceFiles { + return extraData(c, CSourceFiles, @intFromEnum(this)); + } }; pub const Flags = packed struct(u32) { @@ -1422,11 +1521,15 @@ pub const CSourceFiles = struct { pub const CSourceFile = struct { flags: Flags, - file: LazyPath, + file: LazyPath.Index, args: Storage.FlagList(.flags, .args_len, String), pub const Index = enum(u32) { _, + + pub fn get(this: @This(), c: *const Configuration) CSourceFile { + return extraData(c, CSourceFile, @intFromEnum(this)); + } }; pub const Flags = packed struct(u32) { @@ -1438,12 +1541,16 @@ pub const CSourceFile = struct { pub const RcSourceFile = struct { flags: Flags, - file: LazyPath, + file: LazyPath.Index, args: Storage.FlagList(.flags, .args_len, String), - include_paths: Storage.FlagLengthPrefixedList(.flags, .include_paths, LazyPath), + include_paths: Storage.FlagLengthPrefixedList(.flags, .include_paths, LazyPath.Index), pub const Index = enum(u32) { _, + + pub fn get(this: @This(), c: *const Configuration) RcSourceFile { + return extraData(c, RcSourceFile, @intFromEnum(this)); + } }; pub const Flags = packed struct(u32) { @@ -1472,6 +1579,18 @@ pub const OptionalCSourceLanguage = enum(u3) { .assembly_with_preprocessor => .assembly_with_preprocessor, }; } + + pub fn get(this: @This()) ?std.Build.Module.CSourceLanguage { + return switch (this) { + .c => .c, + .cpp => .cpp, + .objective_c => .objective_c, + .objective_cpp => .objective_cpp, + .assembly => .assembly, + .assembly_with_preprocessor => .assembly_with_preprocessor, + .default => null, + }; + } }; pub const ResolvedTarget = struct { @@ -1483,7 +1602,7 @@ pub const ResolvedTarget = struct { pub const Index = enum(u32) { _, - pub fn get(this: @This(), c: *const Configuration) ?ResolvedTarget { + pub fn get(this: @This(), c: *const Configuration) ResolvedTarget { return extraData(c, ResolvedTarget, @intFromEnum(this)); } }; @@ -2006,13 +2125,27 @@ pub const Storage = enum { return end - i; } - pub fn data(buffer: []const u32, i: *usize, comptime S: type) S { - var result: S = undefined; - const fields = @typeInfo(S).@"struct".fields; - inline for (fields) |field| { - @field(result, field.name) = dataField(buffer, i, &result, field.type); + pub fn data(buffer: []const u32, i: *usize, comptime T: type) T { + switch (@typeInfo(T)) { + .@"struct" => |info| { + var result: T = undefined; + inline for (info.fields) |field| { + @field(result, field.name) = dataField(buffer, i, &result, field.type); + } + return result; + }, + .@"union" => |info| { + const flags: T.Flags = @bitCast(buffer[i.*]); + return switch (flags.tag) { + inline else => |comptime_tag| @unionInit( + T, + @tagName(comptime_tag), + data(buffer, i, info.fields[@intFromEnum(comptime_tag)].type), + ), + }; + }, + else => comptime unreachable, } - return result; } fn dataField(buffer: []const u32, i: *usize, container: anytype, comptime Field: type) Field { @@ -2332,6 +2465,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { .available_options = try arena.alloc(AvailableOption, header.available_options_len), .extra = try arena.alloc(u32, header.extra_len), .default_step = header.default_step, + .generated_files_len = header.generated_files_len, }; var vecs = [_][]u8{ result.string_bytes,