| author | |
| committer | |
| log | b04818644c958e05de9b0d5fb4a8a2a3da6d2164 |
| tree | b612dfe2fbae36626dc333454a119d1dc99e27b7 |
| parent | a180012dd2bdae6dd30e165e6c74923eeeeb95b7 |
3 files changed, 842 insertions(+), 842 deletions(-)
lib/compiler/configure_runner.zig deleted-841| ... | ... | @@ -1,841 +0,0 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const Allocator = std.mem.Allocator; | |
| 5 | const Color = std.zig.Color; | |
| 6 | const Configuration = std.Build.Configuration; | |
| 7 | const File = std.Io.File; | |
| 8 | const Io = std.Io; | |
| 9 | const Step = std.Build.Step; | |
| 10 | const Writer = std.Io.Writer; | |
| 11 | const assert = std.debug.assert; | |
| 12 | const fatal = std.process.fatal; | |
| 13 | const fmt = std.fmt; | |
| 14 | const log = std.log; | |
| 15 | const mem = std.mem; | |
| 16 | const process = std.process; | |
| 17 | ||
| 18 | pub const root = @import("@build"); | |
| 19 | pub const dependencies = @import("@dependencies"); | |
| 20 | ||
| 21 | pub const std_options: std.Options = .{ | |
| 22 | .side_channels_mitigations = .none, | |
| 23 | .http_disable_tls = true, | |
| 24 | }; | |
| 25 | ||
| 26 | pub fn main(init: process.Init.Minimal) !void { | |
| 27 | // The build runner is often short-lived, but thanks to `--watch` and `--webui`, that's not | |
| 28 | // always the case. So, we do need a true gpa for some things. | |
| 29 | var debug_gpa_state: std.heap.DebugAllocator(.{ | |
| 30 | // We'd rather have `zig build` run faster than catch harmless leaks in | |
| 31 | // the user's build.zig script. | |
| 32 | .stack_trace_frames = 0, | |
| 33 | }) = .init; | |
| 34 | defer _ = debug_gpa_state.deinit(); | |
| 35 | const gpa = debug_gpa_state.allocator(); | |
| 36 | ||
| 37 | var threaded: std.Io.Threaded = .init(gpa, .{ | |
| 38 | .environ = init.environ, | |
| 39 | .argv0 = .init(init.args), | |
| 40 | }); | |
| 41 | defer threaded.deinit(); | |
| 42 | const io = threaded.io(); | |
| 43 | ||
| 44 | // ...but we'll back our arena by `std.heap.page_allocator` for efficiency. | |
| 45 | var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator); | |
| 46 | defer arena_allocator.deinit(); | |
| 47 | const arena = arena_allocator.allocator(); | |
| 48 | ||
| 49 | const args = try init.args.toSlice(arena); | |
| 50 | ||
| 51 | // skip my own exe name | |
| 52 | var arg_idx: usize = 1; | |
| 53 | ||
| 54 | const zig_exe = expectArgOrFatal(args, &arg_idx, "--zig"); | |
| 55 | const zig_lib_dir = expectArgOrFatal(args, &arg_idx, "--zig-lib-dir"); | |
| 56 | const build_root = expectArgOrFatal(args, &arg_idx, "--build-root"); | |
| 57 | const local_cache_root = expectArgOrFatal(args, &arg_idx, "--local-cache"); | |
| 58 | const global_cache_root = expectArgOrFatal(args, &arg_idx, "--global-cache"); | |
| 59 | ||
| 60 | const cwd: Io.Dir = .cwd(); | |
| 61 | ||
| 62 | const zig_lib_directory: std.Build.Cache.Directory = .{ | |
| 63 | .path = zig_lib_dir, | |
| 64 | .handle = try cwd.openDir(io, zig_lib_dir, .{}), | |
| 65 | }; | |
| 66 | ||
| 67 | const build_root_directory: std.Build.Cache.Directory = .{ | |
| 68 | .path = build_root, | |
| 69 | .handle = try cwd.openDir(io, build_root, .{}), | |
| 70 | }; | |
| 71 | ||
| 72 | const local_cache_directory: std.Build.Cache.Directory = .{ | |
| 73 | .path = local_cache_root, | |
| 74 | .handle = try cwd.createDirPathOpen(io, local_cache_root, .{}), | |
| 75 | }; | |
| 76 | ||
| 77 | const global_cache_directory: std.Build.Cache.Directory = .{ | |
| 78 | .path = global_cache_root, | |
| 79 | .handle = try cwd.createDirPathOpen(io, global_cache_root, .{}), | |
| 80 | }; | |
| 81 | ||
| 82 | var graph: std.Build.Graph = .{ | |
| 83 | .io = io, | |
| 84 | .arena = arena, | |
| 85 | .cache = .{ | |
| 86 | .io = io, | |
| 87 | .gpa = gpa, | |
| 88 | .manifest_dir = try local_cache_directory.handle.createDirPathOpen(io, "h", .{}), | |
| 89 | .cwd = try process.currentPathAlloc(io, arena), | |
| 90 | }, | |
| 91 | .zig_exe = zig_exe, | |
| 92 | .environ_map = try init.environ.createMap(arena), | |
| 93 | .global_cache_root = global_cache_directory, | |
| 94 | .zig_lib_directory = zig_lib_directory, | |
| 95 | .host = .{ | |
| 96 | .query = .{}, | |
| 97 | .result = try std.zig.system.resolveTargetQuery(io, .{}), | |
| 98 | }, | |
| 99 | }; | |
| 100 | ||
| 101 | graph.cache.addPrefix(.{ .path = null, .handle = cwd }); | |
| 102 | graph.cache.addPrefix(build_root_directory); | |
| 103 | graph.cache.addPrefix(local_cache_directory); | |
| 104 | graph.cache.addPrefix(global_cache_directory); | |
| 105 | graph.cache.hash.addBytes(builtin.zig_version_string); | |
| 106 | ||
| 107 | const builder = try std.Build.create( | |
| 108 | &graph, | |
| 109 | build_root_directory, | |
| 110 | local_cache_directory, | |
| 111 | dependencies.root_deps, | |
| 112 | ); | |
| 113 | ||
| 114 | var error_style: ErrorStyle = .verbose; | |
| 115 | var multiline_errors: MultilineErrors = .indent; | |
| 116 | var color: Color = .auto; | |
| 117 | ||
| 118 | if (std.zig.EnvVar.ZIG_BUILD_ERROR_STYLE.get(&graph.environ_map)) |str| { | |
| 119 | if (std.meta.stringToEnum(ErrorStyle, str)) |style| { | |
| 120 | error_style = style; | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | if (std.zig.EnvVar.ZIG_BUILD_MULTILINE_ERRORS.get(&graph.environ_map)) |str| { | |
| 125 | if (std.meta.stringToEnum(MultilineErrors, str)) |style| { | |
| 126 | multiline_errors = style; | |
| 127 | } | |
| 128 | } | |
| 129 | ||
| 130 | while (nextArg(args, &arg_idx)) |arg| { | |
| 131 | if (mem.cutPrefix(u8, arg, "-D")) |option_contents| { | |
| 132 | if (option_contents.len == 0) | |
| 133 | fatalWithHint("expected option name after '-D'", .{}); | |
| 134 | if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| { | |
| 135 | const option_name = option_contents[0..name_end]; | |
| 136 | const option_value = option_contents[name_end + 1 ..]; | |
| 137 | if (try builder.addUserInputOption(option_name, option_value)) | |
| 138 | fatal(" access the help menu with 'zig build -h'", .{}); | |
| 139 | } else { | |
| 140 | if (try builder.addUserInputFlag(option_contents)) | |
| 141 | fatal(" access the help menu with 'zig build -h'", .{}); | |
| 142 | } | |
| 143 | } else if (mem.cutPrefix(u8, arg, "-fsys=")) |name| { | |
| 144 | try graph.system_integration_options.put(arena, name, .user_enabled); | |
| 145 | } else if (mem.cutPrefix(u8, arg, "-fno-sys=")) |name| { | |
| 146 | try graph.system_integration_options.put(arena, name, .user_disabled); | |
| 147 | } else if (mem.eql(u8, arg, "--release")) { | |
| 148 | graph.release_mode = .any; | |
| 149 | } else if (mem.cutPrefix(u8, arg, "--release=")) |text| { | |
| 150 | graph.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse { | |
| 151 | fatalWithHint("expected [off|any|fast|safe|small] in {q}, found {q}", .{ | |
| 152 | arg, text, | |
| 153 | }); | |
| 154 | }; | |
| 155 | } else if (mem.eql(u8, arg, "--color")) { | |
| 156 | const next_arg = nextArg(args, &arg_idx) orelse | |
| 157 | fatalWithHint("expected [auto|on|off] after {q}", .{arg}); | |
| 158 | color = std.meta.stringToEnum(Color, next_arg) orelse { | |
| 159 | fatalWithHint("expected [auto|on|off] after {q}, found {q}", .{ | |
| 160 | arg, next_arg, | |
| 161 | }); | |
| 162 | }; | |
| 163 | } else if (mem.eql(u8, arg, "--error-style")) { | |
| 164 | const next_arg = nextArg(args, &arg_idx) orelse | |
| 165 | fatalWithHint("expected style after {q}", .{arg}); | |
| 166 | error_style = std.meta.stringToEnum(ErrorStyle, next_arg) orelse { | |
| 167 | fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); | |
| 168 | }; | |
| 169 | } else if (mem.eql(u8, arg, "--multiline-errors")) { | |
| 170 | const next_arg = nextArg(args, &arg_idx) orelse | |
| 171 | fatalWithHint("expected style after {q}", .{arg}); | |
| 172 | multiline_errors = std.meta.stringToEnum(MultilineErrors, next_arg) orelse { | |
| 173 | fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); | |
| 174 | }; | |
| 175 | } else if (mem.eql(u8, arg, "--system")) { | |
| 176 | // The usage text shows another argument after this parameter | |
| 177 | // but it is handled by the parent process. The build runner | |
| 178 | // only sees this flag. | |
| 179 | graph.system_package_mode = true; | |
| 180 | } else if (mem.eql(u8, arg, "--have-run-args")) { | |
| 181 | graph.have_run_args = true; | |
| 182 | } else { | |
| 183 | fatalWithHint("unrecognized argument: {q}", .{arg}); | |
| 184 | } | |
| 185 | } | |
| 186 | ||
| 187 | const NO_COLOR = std.zig.EnvVar.NO_COLOR.isSet(&graph.environ_map); | |
| 188 | const CLICOLOR_FORCE = std.zig.EnvVar.CLICOLOR_FORCE.isSet(&graph.environ_map); | |
| 189 | ||
| 190 | graph.stderr_mode = switch (color) { | |
| 191 | .auto => try .detect(io, .stderr(), NO_COLOR, CLICOLOR_FORCE), | |
| 192 | .on => .escape_codes, | |
| 193 | .off => .no_color, | |
| 194 | }; | |
| 195 | ||
| 196 | try builder.runBuild(root); | |
| 197 | ||
| 198 | if (builder.validateUserInputDidItFail()) { | |
| 199 | fatal(" access the help menu with 'zig build -h'", .{}); | |
| 200 | } | |
| 201 | ||
| 202 | var wc: Configuration.Wip = .init(gpa); | |
| 203 | defer wc.deinit(); | |
| 204 | assert(try wc.addString("") == .empty); | |
| 205 | ||
| 206 | try serializeSystemIntegrationOptions(&graph, &wc); | |
| 207 | ||
| 208 | var stdout_buffer: [1024]u8 = undefined; | |
| 209 | var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); | |
| 210 | serialize(builder, &wc, &file_writer.interface) catch |err| switch (err) { | |
| 211 | error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}), | |
| 212 | error.OutOfMemory => |e| return e, | |
| 213 | }; | |
| 214 | ||
| 215 | // This executable is short-lived and run in Debug mode, so we'd rather | |
| 216 | // have `zig build` run faster than catch resource leaks in the user's | |
| 217 | // build.zig script (or, frankly, this configure runner), therefore we call | |
| 218 | // exit directly here rather than cleanExit. | |
| 219 | process.exit(0); | |
| 220 | } | |
| 221 | ||
| 222 | const Serialize = struct { | |
| 223 | arena: Allocator, | |
| 224 | wc: *Configuration.Wip, | |
| 225 | module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty, | |
| 226 | package_map: std.AutoArrayHashMapUnmanaged(*std.Build, Configuration.Package.Index) = .empty, | |
| 227 | ||
| 228 | fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index { | |
| 229 | if (b.pkg_hash.len == 0) return .root; | |
| 230 | const arena = s.arena; | |
| 231 | const wc = s.wc; | |
| 232 | const gop = try s.package_map.getOrPut(arena, b); | |
| 233 | if (!gop.found_existing) { | |
| 234 | gop.value_ptr.* = @enumFromInt(try wc.addExtra(@as(Configuration.Package, .{ | |
| 235 | .hash = try wc.addString(b.pkg_hash), | |
| 236 | .dep_prefix = try wc.addString(b.dep_prefix), | |
| 237 | }))); | |
| 238 | } | |
| 239 | return gop.value_ptr.*; | |
| 240 | } | |
| 241 | ||
| 242 | fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.OptionalLazyPath { | |
| 243 | const wc = s.wc; | |
| 244 | return @enumFromInt(switch (lp orelse return .none) { | |
| 245 | .src_path => |src_path| i: { | |
| 246 | const sub_path = try wc.addString(src_path.sub_path); | |
| 247 | break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{ | |
| 248 | .flags = .{}, | |
| 249 | .owner = try s.builderToPackage(src_path.owner), | |
| 250 | .sub_path = sub_path, | |
| 251 | })); | |
| 252 | }, | |
| 253 | .generated => |generated| i: { | |
| 254 | const sub_path = try wc.addString(generated.sub_path); | |
| 255 | break :i try wc.addExtra(@as(Configuration.LazyPath.Generated, .{ | |
| 256 | .flags = .{ .up = @intCast(generated.up) }, | |
| 257 | .sub_path = sub_path, | |
| 258 | })); | |
| 259 | }, | |
| 260 | .cwd_relative => |cwd_relative_sub_path| i: { | |
| 261 | const sub_path = try wc.addString(cwd_relative_sub_path); | |
| 262 | break :i try wc.addExtra(@as(Configuration.LazyPath.Relative, .{ | |
| 263 | .flags = .{ .base = .cwd }, | |
| 264 | .sub_path = sub_path, | |
| 265 | })); | |
| 266 | }, | |
| 267 | .dependency => |dependency| i: { | |
| 268 | const sub_path = try wc.addString(dependency.sub_path); | |
| 269 | break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{ | |
| 270 | .flags = .{}, | |
| 271 | .owner = try s.builderToPackage(dependency.dependency.builder), | |
| 272 | .sub_path = sub_path, | |
| 273 | })); | |
| 274 | }, | |
| 275 | }); | |
| 276 | } | |
| 277 | ||
| 278 | fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath { | |
| 279 | return (try addOptionalLazyPathEnum(s, lp)).unwrap(); | |
| 280 | } | |
| 281 | ||
| 282 | fn addLazyPath(s: *Serialize, lp: std.Build.LazyPath) !Configuration.LazyPath { | |
| 283 | return @enumFromInt(@intFromEnum(try addOptionalLazyPathEnum(s, lp))); | |
| 284 | } | |
| 285 | ||
| 286 | fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String { | |
| 287 | return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null; | |
| 288 | } | |
| 289 | ||
| 290 | fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String { | |
| 291 | return if (opt_slice) |slice| try s.wc.addString(slice) else null; | |
| 292 | } | |
| 293 | ||
| 294 | fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String { | |
| 295 | const wc = s.wc; | |
| 296 | const result = try s.arena.alloc(Configuration.String, list.len); | |
| 297 | for (result, list) |*dest, src| dest.* = try wc.addString(src); | |
| 298 | return result; | |
| 299 | } | |
| 300 | ||
| 301 | fn initOptionalStringList(s: *Serialize, list: []const ?[]const u8) ![]const Configuration.OptionalString { | |
| 302 | const wc = s.wc; | |
| 303 | const result = try s.arena.alloc(Configuration.OptionalString, list.len); | |
| 304 | for (result, list) |*dest, src| dest.* = try wc.addOptionalString(src); | |
| 305 | return result; | |
| 306 | } | |
| 307 | ||
| 308 | fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index { | |
| 309 | if (s.module_map.get(m)) |index| return index; | |
| 310 | ||
| 311 | const wc = s.wc; | |
| 312 | const arena = s.arena; | |
| 313 | const gpa = wc.gpa; | |
| 314 | ||
| 315 | const lib_paths = try arena.alloc(Configuration.LazyPath, m.lib_paths.items.len); | |
| 316 | for (lib_paths, m.lib_paths.items) |*dest, src| dest.* = try addLazyPath(s, src); | |
| 317 | ||
| 318 | const c_macros = try initStringList(s, m.c_macros.items); | |
| 319 | const export_symbol_names = try initStringList(s, m.export_symbol_names); | |
| 320 | ||
| 321 | const import_table: Configuration.ImportTable = @enumFromInt(wc.extra.items.len); | |
| 322 | const import_table_extra_len = 1 + 2 * m.import_table.entries.len; | |
| 323 | try wc.extra.ensureUnusedCapacity(gpa, import_table_extra_len); | |
| 324 | wc.extra.items.len += import_table_extra_len; | |
| 325 | wc.extra.appendAssumeCapacity(@intCast(m.import_table.entries.len)); | |
| 326 | wc.extra.items[@intFromEnum(import_table)] = @intCast(m.import_table.entries.len); | |
| 327 | for ( | |
| 328 | m.import_table.keys(), | |
| 329 | @intFromEnum(import_table) + 1.., | |
| 330 | ) |mod_name, extra_index| { | |
| 331 | wc.extra.items[extra_index] = @intFromEnum(try wc.addString(mod_name)); | |
| 332 | } | |
| 333 | for ( | |
| 334 | m.import_table.values(), | |
| 335 | @intFromEnum(import_table) + 1 + m.import_table.entries.len.., | |
| 336 | ) |dep, extra_index| { | |
| 337 | log.err("TODO module dependencies can be cyclic", .{}); | |
| 338 | wc.extra.items[extra_index] = @intFromEnum(try addModule(s, dep)); | |
| 339 | } | |
| 340 | ||
| 341 | const module_index: Configuration.Module.Index = @enumFromInt(try wc.addExtra(@as(Configuration.Module, .{ | |
| 342 | .flags = .{ | |
| 343 | .optimize = .init(m.optimize), | |
| 344 | .strip = .init(m.strip), | |
| 345 | .unwind_tables = .init(m.unwind_tables), | |
| 346 | .dwarf_format = .init(m.dwarf_format), | |
| 347 | .single_threaded = .init(m.strip), | |
| 348 | .stack_protector = .init(m.strip), | |
| 349 | .stack_check = .init(m.strip), | |
| 350 | .sanitize_c = .init(m.sanitize_c), | |
| 351 | .sanitize_thread = .init(m.strip), | |
| 352 | .fuzz = .init(m.strip), | |
| 353 | .code_model = m.code_model, | |
| 354 | .c_macros = c_macros.len != 0, | |
| 355 | .include_dirs = m.include_dirs.items.len != 0, | |
| 356 | .lib_paths = lib_paths.len != 0, | |
| 357 | .rpaths = m.rpaths.items.len != 0, | |
| 358 | .frameworks = m.frameworks.entries.len != 0, | |
| 359 | .link_objects = m.link_objects.items.len != 0, | |
| 360 | .export_symbol_names = export_symbol_names.len != 0, | |
| 361 | }, | |
| 362 | .flags2 = .{ | |
| 363 | .valgrind = .init(m.strip), | |
| 364 | .pic = .init(m.strip), | |
| 365 | .red_zone = .init(m.strip), | |
| 366 | .omit_frame_pointer = .init(m.strip), | |
| 367 | .error_tracing = .init(m.strip), | |
| 368 | .link_libc = .init(m.strip), | |
| 369 | .link_libcpp = .init(m.strip), | |
| 370 | .no_builtin = .init(m.strip), | |
| 371 | }, | |
| 372 | .owner = try s.builderToPackage(m.owner), | |
| 373 | .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file), | |
| 374 | .import_table = import_table, | |
| 375 | .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target), | |
| 376 | .c_macros = .{ .slice = c_macros }, | |
| 377 | .lib_paths = .{ .slice = lib_paths }, | |
| 378 | .export_symbol_names = .{ .slice = export_symbol_names }, | |
| 379 | }))); | |
| 380 | ||
| 381 | log.err("TODO serialize the trailing Module data", .{}); | |
| 382 | ||
| 383 | try s.module_map.putNoClobber(arena, m, module_index); | |
| 384 | ||
| 385 | return module_index; | |
| 386 | } | |
| 387 | }; | |
| 388 | ||
| 389 | fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { | |
| 390 | const graph = b.graph; | |
| 391 | const arena = graph.arena; | |
| 392 | const gpa = wc.gpa; | |
| 393 | ||
| 394 | var s: Serialize = .{ .wc = wc, .arena = arena }; | |
| 395 | ||
| 396 | // Starting from all top-level steps in `b`, traverse the entire step graph | |
| 397 | // and add all step dependencies implied by module graphs. | |
| 398 | const top_level_steps = b.top_level_steps.values(); | |
| 399 | // Index corresponds to `Configuration.steps` index. | |
| 400 | var step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty; | |
| 401 | try step_map.ensureUnusedCapacity(arena, top_level_steps.len); | |
| 402 | for (top_level_steps) |tls| { | |
| 403 | step_map.putAssumeCapacityNoClobber(&tls.step, {}); | |
| 404 | } | |
| 405 | { | |
| 406 | while (wc.steps.items.len < step_map.count()) { | |
| 407 | const step = step_map.keys()[wc.steps.items.len]; | |
| 408 | ||
| 409 | // Set up any implied dependencies for this step. It's important that we do this first, so | |
| 410 | // that the loop below discovers steps implied by the module graph. | |
| 411 | try createModuleDependenciesForStep(step); | |
| 412 | ||
| 413 | try step_map.ensureUnusedCapacity(arena, step.dependencies.items.len); | |
| 414 | for (step.dependencies.items) |other_step| { | |
| 415 | step_map.putAssumeCapacity(other_step, {}); | |
| 416 | } | |
| 417 | ||
| 418 | // Add and then de-duplicate dependencies. | |
| 419 | const deps = d: { | |
| 420 | const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len); | |
| 421 | for (try wc.reserveLengthPrefixed(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step| | |
| 422 | dep.* = @intCast(step_map.getIndex(dep_step).?); | |
| 423 | break :d try wc.dedupeDeps(deps); | |
| 424 | }; | |
| 425 | ||
| 426 | try wc.steps.ensureTotalCapacity(gpa, step_map.entries.capacity); | |
| 427 | wc.steps.appendAssumeCapacity(.{ | |
| 428 | .name = try wc.addString(step.name), | |
| 429 | .owner = try s.builderToPackage(step.owner), | |
| 430 | .deps = deps, | |
| 431 | .max_rss = .fromBytes(step.max_rss), | |
| 432 | .extended = switch (step.tag) { | |
| 433 | .top_level => e: { | |
| 434 | const top_level: *Step.TopLevel = @fieldParentPtr("step", step); | |
| 435 | break :e @enumFromInt(try wc.addExtra(@as(Configuration.Step.TopLevel, .{ | |
| 436 | .description = try wc.addString(top_level.description), | |
| 437 | }))); | |
| 438 | }, | |
| 439 | .compile => e: { | |
| 440 | const c: *Step.Compile = @fieldParentPtr("step", step); | |
| 441 | const exec_cmd_args: []const ?[]const u8 = c.exec_cmd_args orelse &.{}; | |
| 442 | const installed_headers: []u32 = try arena.alloc(u32, c.installed_headers.items.len); | |
| 443 | for (installed_headers, c.installed_headers.items) |*dst, src| switch (src) { | |
| 444 | .file => |file| { | |
| 445 | dst.* = try wc.addExtra(@as(Configuration.Step.Compile.InstalledHeader.File, .{ | |
| 446 | .source = try s.addLazyPath(file.source), | |
| 447 | .dest_sub_path = try wc.addString(file.dest_rel_path), | |
| 448 | })); | |
| 449 | }, | |
| 450 | .directory => |directory| { | |
| 451 | const include_extensions = directory.options.include_extensions orelse &.{}; | |
| 452 | dst.* = try wc.addExtra(@as(Configuration.Step.Compile.InstalledHeader.Directory, .{ | |
| 453 | .flags = .{ | |
| 454 | .include_extensions = include_extensions.len != 0, | |
| 455 | .exclude_extensions = directory.options.exclude_extensions.len != 0, | |
| 456 | }, | |
| 457 | .source = try s.addLazyPath(directory.source), | |
| 458 | .dest_sub_path = try wc.addString(directory.dest_rel_path), | |
| 459 | .exclude_extensions = .{ .slice = try s.initStringList(directory.options.exclude_extensions) }, | |
| 460 | .include_extensions = .{ .slice = try s.initStringList(include_extensions) }, | |
| 461 | })); | |
| 462 | }, | |
| 463 | }; | |
| 464 | ||
| 465 | const extra_index = try wc.addExtra(@as(Configuration.Step.Compile, .{ | |
| 466 | .flags = .{ | |
| 467 | .filters_len = c.filters.len != 0, | |
| 468 | .exec_cmd_args_len = exec_cmd_args.len != 0, | |
| 469 | .installed_headers_len = installed_headers.len != 0, | |
| 470 | .force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0, | |
| 471 | ||
| 472 | .verbose_link = c.verbose_link, | |
| 473 | .verbose_cc = c.verbose_cc, | |
| 474 | .rdynamic = c.rdynamic, | |
| 475 | .import_memory = c.import_memory, | |
| 476 | .export_memory = c.export_memory, | |
| 477 | .import_symbols = c.import_symbols, | |
| 478 | .import_table = c.import_table, | |
| 479 | .export_table = c.export_table, | |
| 480 | .shared_memory = c.shared_memory, | |
| 481 | .link_eh_frame_hdr = c.link_eh_frame_hdr, | |
| 482 | .link_emit_relocs = c.link_emit_relocs, | |
| 483 | .link_function_sections = c.link_function_sections, | |
| 484 | .link_data_sections = c.link_data_sections, | |
| 485 | .linker_dynamicbase = c.linker_dynamicbase, | |
| 486 | .link_z_notext = c.link_z_notext, | |
| 487 | .link_z_relro = c.link_z_relro, | |
| 488 | .link_z_lazy = c.link_z_lazy, | |
| 489 | .link_z_defs = c.link_z_defs, | |
| 490 | .headerpad_max_install_names = c.headerpad_max_install_names, | |
| 491 | .dead_strip_dylibs = c.dead_strip_dylibs, | |
| 492 | .force_load_objc = c.force_load_objc, | |
| 493 | .discard_local_symbols = c.discard_local_symbols, | |
| 494 | .mingw_unicode_entry_point = c.mingw_unicode_entry_point, | |
| 495 | }, | |
| 496 | .flags2 = .{ | |
| 497 | .pie = .init(c.pie), | |
| 498 | .formatted_panics = .init(c.formatted_panics), | |
| 499 | .bundle_compiler_rt = .init(c.bundle_compiler_rt), | |
| 500 | .bundle_ubsan_rt = .init(c.bundle_ubsan_rt), | |
| 501 | .each_lib_rpath = .init(c.each_lib_rpath), | |
| 502 | .link_gc_sections = .init(c.link_gc_sections), | |
| 503 | .linker_allow_shlib_undefined = .init(c.linker_allow_shlib_undefined), | |
| 504 | .linker_allow_undefined_version = .init(c.linker_allow_undefined_version), | |
| 505 | .linker_enable_new_dtags = .init(c.linker_enable_new_dtags), | |
| 506 | .dll_export_fns = .init(c.dll_export_fns), | |
| 507 | .use_llvm = .init(c.use_llvm), | |
| 508 | .use_lld = .init(c.use_lld), | |
| 509 | .use_new_linker = .init(c.use_new_linker), | |
| 510 | .allow_so_scripts = .init(c.allow_so_scripts), | |
| 511 | .sanitize_coverage_trace_pc_guard = .init(c.sanitize_coverage_trace_pc_guard), | |
| 512 | .linkage = .init(c.linkage), | |
| 513 | }, | |
| 514 | .flags3 = .{ | |
| 515 | .is_linking_libc = c.is_linking_libc, | |
| 516 | .is_linking_libcpp = c.is_linking_libcpp, | |
| 517 | .version = c.version != null, | |
| 518 | .compress_debug_sections = c.compress_debug_sections, | |
| 519 | .initial_memory = c.initial_memory != null, | |
| 520 | .max_memory = c.max_memory != null, | |
| 521 | .kind = c.kind, | |
| 522 | .global_base = c.global_base != null, | |
| 523 | .test_runner_mode = if (c.test_runner) |tr| switch (tr.mode) { | |
| 524 | .simple => .simple, | |
| 525 | .server => .server, | |
| 526 | } else .default, | |
| 527 | .wasi_exec_model = .init(c.wasi_exec_model), | |
| 528 | .win32_manifest = c.win32_manifest != null, | |
| 529 | .win32_module_definition = c.win32_module_definition != null, | |
| 530 | .zig_lib_dir = c.zig_lib_dir != null, | |
| 531 | .rc_includes = c.rc_includes, | |
| 532 | .image_base = c.image_base != null, | |
| 533 | .build_id = .init(c.build_id), | |
| 534 | .entry = switch (c.entry) { | |
| 535 | .default => .default, | |
| 536 | .disabled => .disabled, | |
| 537 | .enabled => .enabled, | |
| 538 | .symbol_name => .symbol_name, | |
| 539 | }, | |
| 540 | .lto = .init(c.lto), | |
| 541 | .subsystem = .init(c.subsystem), | |
| 542 | }, | |
| 543 | .flags4 = .{ | |
| 544 | .libc_file = c.libc_file != null, | |
| 545 | .link_z_common_page_size = c.link_z_common_page_size != null, | |
| 546 | .link_z_max_page_size = c.link_z_max_page_size != null, | |
| 547 | .pagezero_size = c.pagezero_size != null, | |
| 548 | .stack_size = c.stack_size != null, | |
| 549 | .headerpad_size = c.headerpad_size != null, | |
| 550 | .error_limit = c.error_limit != null, | |
| 551 | .install_name = c.install_name != null, | |
| 552 | .entitlements = c.entitlements != null, | |
| 553 | .expect_errors = if (c.expect_errors) |x| switch (x) { | |
| 554 | .contains => .contains, | |
| 555 | .exact => .exact, | |
| 556 | .starts_with => .starts_with, | |
| 557 | .stderr_contains => .stderr_contains, | |
| 558 | } else .none, | |
| 559 | .linker_script = c.linker_script != null, | |
| 560 | .version_script = c.version_script != null, | |
| 561 | }, | |
| 562 | .root_module = try s.addModule(c.root_module), | |
| 563 | .root_name = try wc.addString(c.name), | |
| 564 | .linker_script = .{ .value = try s.addOptionalLazyPath(c.linker_script) }, | |
| 565 | .version_script = .{ .value = try s.addOptionalLazyPath(c.version_script) }, | |
| 566 | .zig_lib_dir = .{ .value = try s.addOptionalLazyPath(c.zig_lib_dir) }, | |
| 567 | .libc_file = .{ .value = try s.addOptionalLazyPath(c.libc_file) }, | |
| 568 | .win32_manifest = .{ .value = try s.addOptionalLazyPath(c.win32_manifest) }, | |
| 569 | .win32_module_definition = .{ .value = try s.addOptionalLazyPath(c.win32_module_definition) }, | |
| 570 | .entitlements = .{ .value = try s.addOptionalLazyPath(c.entitlements) }, | |
| 571 | .version = .{ .value = try s.addOptionalSemVer(c.version) }, | |
| 572 | .install_name = .{ .value = try s.addOptionalString(c.install_name) }, | |
| 573 | .initial_memory = .{ .value = c.initial_memory }, | |
| 574 | .max_memory = .{ .value = c.max_memory }, | |
| 575 | .global_base = .{ .value = c.global_base }, | |
| 576 | .image_base = .{ .value = c.image_base }, | |
| 577 | .link_z_common_page_size = .{ .value = c.link_z_common_page_size }, | |
| 578 | .link_z_max_page_size = .{ .value = c.link_z_max_page_size }, | |
| 579 | .pagezero_size = .{ .value = c.pagezero_size }, | |
| 580 | .stack_size = .{ .value = c.stack_size }, | |
| 581 | .headerpad_size = .{ .value = c.headerpad_size }, | |
| 582 | .error_limit = .{ .value = c.error_limit }, | |
| 583 | .entry = .{ .value = switch (c.entry) { | |
| 584 | .symbol_name => |name| try wc.addString(name), | |
| 585 | .default, .disabled, .enabled => null, | |
| 586 | } }, | |
| 587 | .build_id = .{ .value = if (c.build_id) |id| switch (id) { | |
| 588 | .hexstring => |*hexstring| try wc.addString(hexstring.toSlice()), | |
| 589 | .none, .fast, .uuid, .sha1, .md5 => null, | |
| 590 | } else null }, | |
| 591 | .filters = .{ .slice = try s.initStringList(c.filters) }, | |
| 592 | .exec_cmd_args = .{ .slice = try s.initOptionalStringList(exec_cmd_args) }, | |
| 593 | .installed_headers = .initErased(installed_headers), | |
| 594 | .force_undefined_symbols = .{ .slice = try s.initStringList(c.force_undefined_symbols.keys()) }, | |
| 595 | })); | |
| 596 | ||
| 597 | log.err("TODO serialize the trailing Compile step data", .{}); | |
| 598 | ||
| 599 | break :e @enumFromInt(extra_index); | |
| 600 | }, | |
| 601 | .install_artifact => e: { | |
| 602 | const ia: *Step.InstallArtifact = @fieldParentPtr("step", step); | |
| 603 | break :e @enumFromInt(try wc.addExtra(@as(Configuration.Step.InstallArtifact, .{ | |
| 604 | .flags = .{ | |
| 605 | .dylib_symlinks = ia.dylib_symlinks != null, | |
| 606 | }, | |
| 607 | .dest_dir = try addInstallDir(wc, ia.dest_dir), | |
| 608 | .dest_sub_path = try wc.addString(ia.dest_sub_path), | |
| 609 | .emitted_bin = try s.addOptionalLazyPathEnum(ia.emitted_bin), | |
| 610 | .implib_dir = try addInstallDir(wc, ia.implib_dir), | |
| 611 | .emitted_implib = try s.addOptionalLazyPathEnum(ia.emitted_implib), | |
| 612 | .pdb_dir = try addInstallDir(wc, ia.pdb_dir), | |
| 613 | .emitted_pdb = try s.addOptionalLazyPathEnum(ia.emitted_pdb), | |
| 614 | .h_dir = try addInstallDir(wc, ia.h_dir), | |
| 615 | .emitted_h = try s.addOptionalLazyPathEnum(ia.emitted_h), | |
| 616 | .artifact = stepIndex(&step_map, &ia.artifact.step), | |
| 617 | }))); | |
| 618 | }, | |
| 619 | .install_file => @panic("TODO"), | |
| 620 | .install_dir => @panic("TODO"), | |
| 621 | .remove_dir => @panic("TODO"), | |
| 622 | .fail => @panic("TODO"), | |
| 623 | .fmt => @panic("TODO"), | |
| 624 | .translate_c => @panic("TODO"), | |
| 625 | .write_file => @panic("TODO"), | |
| 626 | .update_source_files => @panic("TODO"), | |
| 627 | .run => e: { | |
| 628 | const run: *Step.Run = @fieldParentPtr("step", step); | |
| 629 | ||
| 630 | const captured_stdout: Configuration.OptionalString = if (run.captured_stdout) |cs| | |
| 631 | .init(try wc.addString(cs.output.basename)) | |
| 632 | else | |
| 633 | .none; | |
| 634 | ||
| 635 | const captured_stderr: Configuration.OptionalString = if (run.captured_stderr) |cs| | |
| 636 | .init(try wc.addString(cs.output.basename)) | |
| 637 | else | |
| 638 | .none; | |
| 639 | ||
| 640 | const extra_index = try wc.addExtra(@as(Configuration.Step.Run, .{ | |
| 641 | .flags = .{ | |
| 642 | .disable_zig_progress = run.disable_zig_progress, | |
| 643 | .skip_foreign_checks = run.skip_foreign_checks, | |
| 644 | .failing_to_execute_foreign_is_an_error = run.failing_to_execute_foreign_is_an_error, | |
| 645 | .has_side_effects = run.has_side_effects, | |
| 646 | .test_runner_mode = run.test_runner_mode, | |
| 647 | .color = run.color, | |
| 648 | .stdio = switch (run.stdio) { | |
| 649 | .infer_from_args => .infer_from_args, | |
| 650 | .inherit => .inherit, | |
| 651 | .check => .check, | |
| 652 | .zig_test => .zig_test, | |
| 653 | }, | |
| 654 | .stdin = switch (run.stdin) { | |
| 655 | .none => .none, | |
| 656 | .bytes => .bytes, | |
| 657 | .lazy_path => .lazy_path, | |
| 658 | }, | |
| 659 | .stdout_trim_whitespace = if (run.captured_stdout) |cs| cs.trim_whitespace else .none, | |
| 660 | .stderr_trim_whitespace = if (run.captured_stderr) |cs| cs.trim_whitespace else .none, | |
| 661 | .stdio_limit = run.stdio_limit != .unlimited, | |
| 662 | .producer = run.producer != null, | |
| 663 | }, | |
| 664 | .file_inputs_len = @intCast(run.file_inputs.items.len), | |
| 665 | .args_len = @intCast(run.argv.items.len), | |
| 666 | .cwd = try s.addOptionalLazyPathEnum(run.cwd), | |
| 667 | .captured_stdout = captured_stdout, | |
| 668 | .captured_stderr = captured_stderr, | |
| 669 | })); | |
| 670 | ||
| 671 | log.err("TODO serialize the trailing Run step data", .{}); | |
| 672 | ||
| 673 | break :e @enumFromInt(extra_index); | |
| 674 | }, | |
| 675 | .check_file => @panic("TODO"), | |
| 676 | .check_object => @panic("TODO"), | |
| 677 | .config_header => @panic("TODO"), | |
| 678 | .objcopy => @panic("TODO"), | |
| 679 | .options => @panic("TODO"), | |
| 680 | }, | |
| 681 | }); | |
| 682 | } | |
| 683 | } | |
| 684 | ||
| 685 | try wc.unlazy_deps.ensureUnusedCapacity(gpa, graph.needed_lazy_dependencies.keys().len); | |
| 686 | for (graph.needed_lazy_dependencies.keys()) |k| { | |
| 687 | wc.unlazy_deps.appendAssumeCapacity(try wc.addString(k)); | |
| 688 | } | |
| 689 | ||
| 690 | try wc.write(writer, .{ | |
| 691 | .default_step = stepIndex(&step_map, b.default_step), | |
| 692 | }); | |
| 693 | } | |
| 694 | ||
| 695 | fn addOptionalResolvedTarget( | |
| 696 | wc: *Configuration.Wip, | |
| 697 | optional_resolved_target: ?std.Build.ResolvedTarget, | |
| 698 | ) !Configuration.ResolvedTarget.OptionalIndex { | |
| 699 | const resolved_target = optional_resolved_target orelse return .none; | |
| 700 | log.debug("TODO deduplicate resolved targets", .{}); | |
| 701 | return @enumFromInt(try wc.addExtra(@as(Configuration.ResolvedTarget, .{ | |
| 702 | .query = try wc.addTargetQuery(resolved_target.query), | |
| 703 | .result = try wc.addTarget(resolved_target.result), | |
| 704 | }))); | |
| 705 | } | |
| 706 | ||
| 707 | fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Configuration.InstallDestDir { | |
| 708 | switch (install_dir orelse return .none) { | |
| 709 | .prefix => return .prefix, | |
| 710 | .lib => return .lib, | |
| 711 | .bin => return .bin, | |
| 712 | .header => return .header, | |
| 713 | .custom => |sub_path| return .initCustom(try wc.addString(sub_path)), | |
| 714 | } | |
| 715 | } | |
| 716 | ||
| 717 | fn stepIndex(step_map: *const std.AutoArrayHashMapUnmanaged(*Step, void), step: *Step) Configuration.Step.Index { | |
| 718 | return @enumFromInt(step_map.getIndex(step).?); | |
| 719 | } | |
| 720 | ||
| 721 | /// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which | |
| 722 | /// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`. | |
| 723 | fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void { | |
| 724 | const root_module = if (step.cast(Step.Compile)) |cs| root: { | |
| 725 | break :root cs.root_module; | |
| 726 | } else return; // not a compile step so no module dependencies | |
| 727 | ||
| 728 | // Starting from `root_module`, discover all modules in this graph. | |
| 729 | const modules = root_module.getGraph().modules; | |
| 730 | ||
| 731 | // For each of those modules, set up the implied step dependencies. | |
| 732 | for (modules) |mod| { | |
| 733 | if (mod.root_source_file) |lp| lp.addStepDependencies(step); | |
| 734 | for (mod.include_dirs.items) |include_dir| switch (include_dir) { | |
| 735 | .path, | |
| 736 | .path_system, | |
| 737 | .path_after, | |
| 738 | .framework_path, | |
| 739 | .framework_path_system, | |
| 740 | .embed_path, | |
| 741 | => |lp| lp.addStepDependencies(step), | |
| 742 | ||
| 743 | .other_step => |other| { | |
| 744 | other.getEmittedIncludeTree().addStepDependencies(step); | |
| 745 | step.dependOn(&other.step); | |
| 746 | }, | |
| 747 | ||
| 748 | .config_header_step => |other| step.dependOn(&other.step), | |
| 749 | }; | |
| 750 | for (mod.lib_paths.items) |lp| lp.addStepDependencies(step); | |
| 751 | for (mod.rpaths.items) |rpath| switch (rpath) { | |
| 752 | .lazy_path => |lp| lp.addStepDependencies(step), | |
| 753 | .special => {}, | |
| 754 | }; | |
| 755 | for (mod.link_objects.items) |link_object| switch (link_object) { | |
| 756 | .static_path, | |
| 757 | .assembly_file, | |
| 758 | => |lp| lp.addStepDependencies(step), | |
| 759 | .other_step => |other| step.dependOn(&other.step), | |
| 760 | .system_lib => {}, | |
| 761 | .c_source_file => |source| source.file.addStepDependencies(step), | |
| 762 | .c_source_files => |source_files| source_files.root.addStepDependencies(step), | |
| 763 | .win32_resource_file => |rc_source| { | |
| 764 | rc_source.file.addStepDependencies(step); | |
| 765 | for (rc_source.include_paths) |lp| lp.addStepDependencies(step); | |
| 766 | }, | |
| 767 | }; | |
| 768 | } | |
| 769 | } | |
| 770 | ||
| 771 | fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 { | |
| 772 | if (idx.* >= args.len) return null; | |
| 773 | defer idx.* += 1; | |
| 774 | return args[idx.*]; | |
| 775 | } | |
| 776 | ||
| 777 | fn nextArgOrFatal(args: []const [:0]const u8, idx: *usize) [:0]const u8 { | |
| 778 | return nextArg(args, idx) orelse { | |
| 779 | fatalWithHint("expected argument after: {s}", .{args[idx.* - 1]}); | |
| 780 | }; | |
| 781 | } | |
| 782 | ||
| 783 | fn expectArgOrFatal(args: []const [:0]const u8, index_ptr: *usize, first: []const u8) []const u8 { | |
| 784 | const next_arg = nextArg(args, index_ptr) orelse fatal("missing {q} argument", .{first}); | |
| 785 | if (!mem.eql(u8, first, next_arg)) fatal("expected {q} instead of {q}", .{ first, next_arg }); | |
| 786 | const arg = nextArg(args, index_ptr) orelse fatal("expected argument after {q}", .{first}); | |
| 787 | return arg; | |
| 788 | } | |
| 789 | ||
| 790 | const ErrorStyle = enum { | |
| 791 | verbose, | |
| 792 | minimal, | |
| 793 | verbose_clear, | |
| 794 | minimal_clear, | |
| 795 | fn verboseContext(s: ErrorStyle) bool { | |
| 796 | return switch (s) { | |
| 797 | .verbose, .verbose_clear => true, | |
| 798 | .minimal, .minimal_clear => false, | |
| 799 | }; | |
| 800 | } | |
| 801 | fn clearOnUpdate(s: ErrorStyle) bool { | |
| 802 | return switch (s) { | |
| 803 | .verbose, .minimal => false, | |
| 804 | .verbose_clear, .minimal_clear => true, | |
| 805 | }; | |
| 806 | } | |
| 807 | }; | |
| 808 | const MultilineErrors = enum { indent, newline, none }; | |
| 809 | const Summary = enum { all, new, failures, line, none }; | |
| 810 | ||
| 811 | fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn { | |
| 812 | log.info("to access the help menu: zig build -h", .{}); | |
| 813 | fatal(f, args); | |
| 814 | } | |
| 815 | ||
| 816 | fn serializeSystemIntegrationOptions(graph: *std.Build.Graph, wc: *Configuration.Wip) Allocator.Error!void { | |
| 817 | const gpa = wc.gpa; | |
| 818 | ||
| 819 | var bad = false; | |
| 820 | try wc.system_integrations.ensureTotalCapacityPrecise(gpa, graph.system_integration_options.entries.len); | |
| 821 | for (graph.system_integration_options.keys(), graph.system_integration_options.values()) |k, v| { | |
| 822 | wc.system_integrations.appendAssumeCapacity(.{ | |
| 823 | .name = try wc.addString(k), | |
| 824 | .status = switch (v) { | |
| 825 | .user_disabled, .user_enabled => x: { | |
| 826 | // The user tried to enable or disable a system library integration, but | |
| 827 | // the configure script did not recognize that option. | |
| 828 | log.err("system integration name not recognized by configure script: {s}", .{k}); | |
| 829 | bad = true; | |
| 830 | break :x .disabled; | |
| 831 | }, | |
| 832 | .declared_disabled => .disabled, | |
| 833 | .declared_enabled => .enabled, | |
| 834 | }, | |
| 835 | }); | |
| 836 | } | |
| 837 | if (bad) { | |
| 838 | log.info("help menu contains available options: zig build -h", .{}); | |
| 839 | process.exit(1); | |
| 840 | } | |
| 841 | } |
lib/compiler/configurer.zig created+841| ... | ... | @@ -0,0 +1,841 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const Allocator = std.mem.Allocator; | |
| 5 | const Color = std.zig.Color; | |
| 6 | const Configuration = std.Build.Configuration; | |
| 7 | const File = std.Io.File; | |
| 8 | const Io = std.Io; | |
| 9 | const Step = std.Build.Step; | |
| 10 | const Writer = std.Io.Writer; | |
| 11 | const assert = std.debug.assert; | |
| 12 | const fatal = std.process.fatal; | |
| 13 | const fmt = std.fmt; | |
| 14 | const log = std.log; | |
| 15 | const mem = std.mem; | |
| 16 | const process = std.process; | |
| 17 | ||
| 18 | pub const root = @import("@build"); | |
| 19 | pub const dependencies = @import("@dependencies"); | |
| 20 | ||
| 21 | pub const std_options: std.Options = .{ | |
| 22 | .side_channels_mitigations = .none, | |
| 23 | .http_disable_tls = true, | |
| 24 | }; | |
| 25 | ||
| 26 | pub fn main(init: process.Init.Minimal) !void { | |
| 27 | // The build runner is often short-lived, but thanks to `--watch` and `--webui`, that's not | |
| 28 | // always the case. So, we do need a true gpa for some things. | |
| 29 | var debug_gpa_state: std.heap.DebugAllocator(.{ | |
| 30 | // We'd rather have `zig build` run faster than catch harmless leaks in | |
| 31 | // the user's build.zig script. | |
| 32 | .stack_trace_frames = 0, | |
| 33 | }) = .init; | |
| 34 | defer _ = debug_gpa_state.deinit(); | |
| 35 | const gpa = debug_gpa_state.allocator(); | |
| 36 | ||
| 37 | var threaded: std.Io.Threaded = .init(gpa, .{ | |
| 38 | .environ = init.environ, | |
| 39 | .argv0 = .init(init.args), | |
| 40 | }); | |
| 41 | defer threaded.deinit(); | |
| 42 | const io = threaded.io(); | |
| 43 | ||
| 44 | // ...but we'll back our arena by `std.heap.page_allocator` for efficiency. | |
| 45 | var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator); | |
| 46 | defer arena_allocator.deinit(); | |
| 47 | const arena = arena_allocator.allocator(); | |
| 48 | ||
| 49 | const args = try init.args.toSlice(arena); | |
| 50 | ||
| 51 | // skip my own exe name | |
| 52 | var arg_idx: usize = 1; | |
| 53 | ||
| 54 | const zig_exe = expectArgOrFatal(args, &arg_idx, "--zig"); | |
| 55 | const zig_lib_dir = expectArgOrFatal(args, &arg_idx, "--zig-lib-dir"); | |
| 56 | const build_root = expectArgOrFatal(args, &arg_idx, "--build-root"); | |
| 57 | const local_cache_root = expectArgOrFatal(args, &arg_idx, "--local-cache"); | |
| 58 | const global_cache_root = expectArgOrFatal(args, &arg_idx, "--global-cache"); | |
| 59 | ||
| 60 | const cwd: Io.Dir = .cwd(); | |
| 61 | ||
| 62 | const zig_lib_directory: std.Build.Cache.Directory = .{ | |
| 63 | .path = zig_lib_dir, | |
| 64 | .handle = try cwd.openDir(io, zig_lib_dir, .{}), | |
| 65 | }; | |
| 66 | ||
| 67 | const build_root_directory: std.Build.Cache.Directory = .{ | |
| 68 | .path = build_root, | |
| 69 | .handle = try cwd.openDir(io, build_root, .{}), | |
| 70 | }; | |
| 71 | ||
| 72 | const local_cache_directory: std.Build.Cache.Directory = .{ | |
| 73 | .path = local_cache_root, | |
| 74 | .handle = try cwd.createDirPathOpen(io, local_cache_root, .{}), | |
| 75 | }; | |
| 76 | ||
| 77 | const global_cache_directory: std.Build.Cache.Directory = .{ | |
| 78 | .path = global_cache_root, | |
| 79 | .handle = try cwd.createDirPathOpen(io, global_cache_root, .{}), | |
| 80 | }; | |
| 81 | ||
| 82 | var graph: std.Build.Graph = .{ | |
| 83 | .io = io, | |
| 84 | .arena = arena, | |
| 85 | .cache = .{ | |
| 86 | .io = io, | |
| 87 | .gpa = gpa, | |
| 88 | .manifest_dir = try local_cache_directory.handle.createDirPathOpen(io, "h", .{}), | |
| 89 | .cwd = try process.currentPathAlloc(io, arena), | |
| 90 | }, | |
| 91 | .zig_exe = zig_exe, | |
| 92 | .environ_map = try init.environ.createMap(arena), | |
| 93 | .global_cache_root = global_cache_directory, | |
| 94 | .zig_lib_directory = zig_lib_directory, | |
| 95 | .host = .{ | |
| 96 | .query = .{}, | |
| 97 | .result = try std.zig.system.resolveTargetQuery(io, .{}), | |
| 98 | }, | |
| 99 | }; | |
| 100 | ||
| 101 | graph.cache.addPrefix(.{ .path = null, .handle = cwd }); | |
| 102 | graph.cache.addPrefix(build_root_directory); | |
| 103 | graph.cache.addPrefix(local_cache_directory); | |
| 104 | graph.cache.addPrefix(global_cache_directory); | |
| 105 | graph.cache.hash.addBytes(builtin.zig_version_string); | |
| 106 | ||
| 107 | const builder = try std.Build.create( | |
| 108 | &graph, | |
| 109 | build_root_directory, | |
| 110 | local_cache_directory, | |
| 111 | dependencies.root_deps, | |
| 112 | ); | |
| 113 | ||
| 114 | var error_style: ErrorStyle = .verbose; | |
| 115 | var multiline_errors: MultilineErrors = .indent; | |
| 116 | var color: Color = .auto; | |
| 117 | ||
| 118 | if (std.zig.EnvVar.ZIG_BUILD_ERROR_STYLE.get(&graph.environ_map)) |str| { | |
| 119 | if (std.meta.stringToEnum(ErrorStyle, str)) |style| { | |
| 120 | error_style = style; | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | if (std.zig.EnvVar.ZIG_BUILD_MULTILINE_ERRORS.get(&graph.environ_map)) |str| { | |
| 125 | if (std.meta.stringToEnum(MultilineErrors, str)) |style| { | |
| 126 | multiline_errors = style; | |
| 127 | } | |
| 128 | } | |
| 129 | ||
| 130 | while (nextArg(args, &arg_idx)) |arg| { | |
| 131 | if (mem.cutPrefix(u8, arg, "-D")) |option_contents| { | |
| 132 | if (option_contents.len == 0) | |
| 133 | fatalWithHint("expected option name after '-D'", .{}); | |
| 134 | if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| { | |
| 135 | const option_name = option_contents[0..name_end]; | |
| 136 | const option_value = option_contents[name_end + 1 ..]; | |
| 137 | if (try builder.addUserInputOption(option_name, option_value)) | |
| 138 | fatal(" access the help menu with 'zig build -h'", .{}); | |
| 139 | } else { | |
| 140 | if (try builder.addUserInputFlag(option_contents)) | |
| 141 | fatal(" access the help menu with 'zig build -h'", .{}); | |
| 142 | } | |
| 143 | } else if (mem.cutPrefix(u8, arg, "-fsys=")) |name| { | |
| 144 | try graph.system_integration_options.put(arena, name, .user_enabled); | |
| 145 | } else if (mem.cutPrefix(u8, arg, "-fno-sys=")) |name| { | |
| 146 | try graph.system_integration_options.put(arena, name, .user_disabled); | |
| 147 | } else if (mem.eql(u8, arg, "--release")) { | |
| 148 | graph.release_mode = .any; | |
| 149 | } else if (mem.cutPrefix(u8, arg, "--release=")) |text| { | |
| 150 | graph.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse { | |
| 151 | fatalWithHint("expected [off|any|fast|safe|small] in {q}, found {q}", .{ | |
| 152 | arg, text, | |
| 153 | }); | |
| 154 | }; | |
| 155 | } else if (mem.eql(u8, arg, "--color")) { | |
| 156 | const next_arg = nextArg(args, &arg_idx) orelse | |
| 157 | fatalWithHint("expected [auto|on|off] after {q}", .{arg}); | |
| 158 | color = std.meta.stringToEnum(Color, next_arg) orelse { | |
| 159 | fatalWithHint("expected [auto|on|off] after {q}, found {q}", .{ | |
| 160 | arg, next_arg, | |
| 161 | }); | |
| 162 | }; | |
| 163 | } else if (mem.eql(u8, arg, "--error-style")) { | |
| 164 | const next_arg = nextArg(args, &arg_idx) orelse | |
| 165 | fatalWithHint("expected style after {q}", .{arg}); | |
| 166 | error_style = std.meta.stringToEnum(ErrorStyle, next_arg) orelse { | |
| 167 | fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); | |
| 168 | }; | |
| 169 | } else if (mem.eql(u8, arg, "--multiline-errors")) { | |
| 170 | const next_arg = nextArg(args, &arg_idx) orelse | |
| 171 | fatalWithHint("expected style after {q}", .{arg}); | |
| 172 | multiline_errors = std.meta.stringToEnum(MultilineErrors, next_arg) orelse { | |
| 173 | fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); | |
| 174 | }; | |
| 175 | } else if (mem.eql(u8, arg, "--system")) { | |
| 176 | // The usage text shows another argument after this parameter | |
| 177 | // but it is handled by the parent process. The build runner | |
| 178 | // only sees this flag. | |
| 179 | graph.system_package_mode = true; | |
| 180 | } else if (mem.eql(u8, arg, "--have-run-args")) { | |
| 181 | graph.have_run_args = true; | |
| 182 | } else { | |
| 183 | fatalWithHint("unrecognized argument: {q}", .{arg}); | |
| 184 | } | |
| 185 | } | |
| 186 | ||
| 187 | const NO_COLOR = std.zig.EnvVar.NO_COLOR.isSet(&graph.environ_map); | |
| 188 | const CLICOLOR_FORCE = std.zig.EnvVar.CLICOLOR_FORCE.isSet(&graph.environ_map); | |
| 189 | ||
| 190 | graph.stderr_mode = switch (color) { | |
| 191 | .auto => try .detect(io, .stderr(), NO_COLOR, CLICOLOR_FORCE), | |
| 192 | .on => .escape_codes, | |
| 193 | .off => .no_color, | |
| 194 | }; | |
| 195 | ||
| 196 | try builder.runBuild(root); | |
| 197 | ||
| 198 | if (builder.validateUserInputDidItFail()) { | |
| 199 | fatal(" access the help menu with 'zig build -h'", .{}); | |
| 200 | } | |
| 201 | ||
| 202 | var wc: Configuration.Wip = .init(gpa); | |
| 203 | defer wc.deinit(); | |
| 204 | assert(try wc.addString("") == .empty); | |
| 205 | ||
| 206 | try serializeSystemIntegrationOptions(&graph, &wc); | |
| 207 | ||
| 208 | var stdout_buffer: [1024]u8 = undefined; | |
| 209 | var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); | |
| 210 | serialize(builder, &wc, &file_writer.interface) catch |err| switch (err) { | |
| 211 | error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}), | |
| 212 | error.OutOfMemory => |e| return e, | |
| 213 | }; | |
| 214 | ||
| 215 | // This executable is short-lived and run in Debug mode, so we'd rather | |
| 216 | // have `zig build` run faster than catch resource leaks in the user's | |
| 217 | // build.zig script (or, frankly, this configure runner), therefore we call | |
| 218 | // exit directly here rather than cleanExit. | |
| 219 | process.exit(0); | |
| 220 | } | |
| 221 | ||
| 222 | const Serialize = struct { | |
| 223 | arena: Allocator, | |
| 224 | wc: *Configuration.Wip, | |
| 225 | module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty, | |
| 226 | package_map: std.AutoArrayHashMapUnmanaged(*std.Build, Configuration.Package.Index) = .empty, | |
| 227 | ||
| 228 | fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index { | |
| 229 | if (b.pkg_hash.len == 0) return .root; | |
| 230 | const arena = s.arena; | |
| 231 | const wc = s.wc; | |
| 232 | const gop = try s.package_map.getOrPut(arena, b); | |
| 233 | if (!gop.found_existing) { | |
| 234 | gop.value_ptr.* = @enumFromInt(try wc.addExtra(@as(Configuration.Package, .{ | |
| 235 | .hash = try wc.addString(b.pkg_hash), | |
| 236 | .dep_prefix = try wc.addString(b.dep_prefix), | |
| 237 | }))); | |
| 238 | } | |
| 239 | return gop.value_ptr.*; | |
| 240 | } | |
| 241 | ||
| 242 | fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.OptionalLazyPath { | |
| 243 | const wc = s.wc; | |
| 244 | return @enumFromInt(switch (lp orelse return .none) { | |
| 245 | .src_path => |src_path| i: { | |
| 246 | const sub_path = try wc.addString(src_path.sub_path); | |
| 247 | break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{ | |
| 248 | .flags = .{}, | |
| 249 | .owner = try s.builderToPackage(src_path.owner), | |
| 250 | .sub_path = sub_path, | |
| 251 | })); | |
| 252 | }, | |
| 253 | .generated => |generated| i: { | |
| 254 | const sub_path = try wc.addString(generated.sub_path); | |
| 255 | break :i try wc.addExtra(@as(Configuration.LazyPath.Generated, .{ | |
| 256 | .flags = .{ .up = @intCast(generated.up) }, | |
| 257 | .sub_path = sub_path, | |
| 258 | })); | |
| 259 | }, | |
| 260 | .cwd_relative => |cwd_relative_sub_path| i: { | |
| 261 | const sub_path = try wc.addString(cwd_relative_sub_path); | |
| 262 | break :i try wc.addExtra(@as(Configuration.LazyPath.Relative, .{ | |
| 263 | .flags = .{ .base = .cwd }, | |
| 264 | .sub_path = sub_path, | |
| 265 | })); | |
| 266 | }, | |
| 267 | .dependency => |dependency| i: { | |
| 268 | const sub_path = try wc.addString(dependency.sub_path); | |
| 269 | break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{ | |
| 270 | .flags = .{}, | |
| 271 | .owner = try s.builderToPackage(dependency.dependency.builder), | |
| 272 | .sub_path = sub_path, | |
| 273 | })); | |
| 274 | }, | |
| 275 | }); | |
| 276 | } | |
| 277 | ||
| 278 | fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath { | |
| 279 | return (try addOptionalLazyPathEnum(s, lp)).unwrap(); | |
| 280 | } | |
| 281 | ||
| 282 | fn addLazyPath(s: *Serialize, lp: std.Build.LazyPath) !Configuration.LazyPath { | |
| 283 | return @enumFromInt(@intFromEnum(try addOptionalLazyPathEnum(s, lp))); | |
| 284 | } | |
| 285 | ||
| 286 | fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String { | |
| 287 | return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null; | |
| 288 | } | |
| 289 | ||
| 290 | fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String { | |
| 291 | return if (opt_slice) |slice| try s.wc.addString(slice) else null; | |
| 292 | } | |
| 293 | ||
| 294 | fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String { | |
| 295 | const wc = s.wc; | |
| 296 | const result = try s.arena.alloc(Configuration.String, list.len); | |
| 297 | for (result, list) |*dest, src| dest.* = try wc.addString(src); | |
| 298 | return result; | |
| 299 | } | |
| 300 | ||
| 301 | fn initOptionalStringList(s: *Serialize, list: []const ?[]const u8) ![]const Configuration.OptionalString { | |
| 302 | const wc = s.wc; | |
| 303 | const result = try s.arena.alloc(Configuration.OptionalString, list.len); | |
| 304 | for (result, list) |*dest, src| dest.* = try wc.addOptionalString(src); | |
| 305 | return result; | |
| 306 | } | |
| 307 | ||
| 308 | fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index { | |
| 309 | if (s.module_map.get(m)) |index| return index; | |
| 310 | ||
| 311 | const wc = s.wc; | |
| 312 | const arena = s.arena; | |
| 313 | const gpa = wc.gpa; | |
| 314 | ||
| 315 | const lib_paths = try arena.alloc(Configuration.LazyPath, m.lib_paths.items.len); | |
| 316 | for (lib_paths, m.lib_paths.items) |*dest, src| dest.* = try addLazyPath(s, src); | |
| 317 | ||
| 318 | const c_macros = try initStringList(s, m.c_macros.items); | |
| 319 | const export_symbol_names = try initStringList(s, m.export_symbol_names); | |
| 320 | ||
| 321 | const import_table: Configuration.ImportTable = @enumFromInt(wc.extra.items.len); | |
| 322 | const import_table_extra_len = 1 + 2 * m.import_table.entries.len; | |
| 323 | try wc.extra.ensureUnusedCapacity(gpa, import_table_extra_len); | |
| 324 | wc.extra.items.len += import_table_extra_len; | |
| 325 | wc.extra.appendAssumeCapacity(@intCast(m.import_table.entries.len)); | |
| 326 | wc.extra.items[@intFromEnum(import_table)] = @intCast(m.import_table.entries.len); | |
| 327 | for ( | |
| 328 | m.import_table.keys(), | |
| 329 | @intFromEnum(import_table) + 1.., | |
| 330 | ) |mod_name, extra_index| { | |
| 331 | wc.extra.items[extra_index] = @intFromEnum(try wc.addString(mod_name)); | |
| 332 | } | |
| 333 | for ( | |
| 334 | m.import_table.values(), | |
| 335 | @intFromEnum(import_table) + 1 + m.import_table.entries.len.., | |
| 336 | ) |dep, extra_index| { | |
| 337 | log.err("TODO module dependencies can be cyclic", .{}); | |
| 338 | wc.extra.items[extra_index] = @intFromEnum(try addModule(s, dep)); | |
| 339 | } | |
| 340 | ||
| 341 | const module_index: Configuration.Module.Index = @enumFromInt(try wc.addExtra(@as(Configuration.Module, .{ | |
| 342 | .flags = .{ | |
| 343 | .optimize = .init(m.optimize), | |
| 344 | .strip = .init(m.strip), | |
| 345 | .unwind_tables = .init(m.unwind_tables), | |
| 346 | .dwarf_format = .init(m.dwarf_format), | |
| 347 | .single_threaded = .init(m.strip), | |
| 348 | .stack_protector = .init(m.strip), | |
| 349 | .stack_check = .init(m.strip), | |
| 350 | .sanitize_c = .init(m.sanitize_c), | |
| 351 | .sanitize_thread = .init(m.strip), | |
| 352 | .fuzz = .init(m.strip), | |
| 353 | .code_model = m.code_model, | |
| 354 | .c_macros = c_macros.len != 0, | |
| 355 | .include_dirs = m.include_dirs.items.len != 0, | |
| 356 | .lib_paths = lib_paths.len != 0, | |
| 357 | .rpaths = m.rpaths.items.len != 0, | |
| 358 | .frameworks = m.frameworks.entries.len != 0, | |
| 359 | .link_objects = m.link_objects.items.len != 0, | |
| 360 | .export_symbol_names = export_symbol_names.len != 0, | |
| 361 | }, | |
| 362 | .flags2 = .{ | |
| 363 | .valgrind = .init(m.strip), | |
| 364 | .pic = .init(m.strip), | |
| 365 | .red_zone = .init(m.strip), | |
| 366 | .omit_frame_pointer = .init(m.strip), | |
| 367 | .error_tracing = .init(m.strip), | |
| 368 | .link_libc = .init(m.strip), | |
| 369 | .link_libcpp = .init(m.strip), | |
| 370 | .no_builtin = .init(m.strip), | |
| 371 | }, | |
| 372 | .owner = try s.builderToPackage(m.owner), | |
| 373 | .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file), | |
| 374 | .import_table = import_table, | |
| 375 | .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target), | |
| 376 | .c_macros = .{ .slice = c_macros }, | |
| 377 | .lib_paths = .{ .slice = lib_paths }, | |
| 378 | .export_symbol_names = .{ .slice = export_symbol_names }, | |
| 379 | }))); | |
| 380 | ||
| 381 | log.err("TODO serialize the trailing Module data", .{}); | |
| 382 | ||
| 383 | try s.module_map.putNoClobber(arena, m, module_index); | |
| 384 | ||
| 385 | return module_index; | |
| 386 | } | |
| 387 | }; | |
| 388 | ||
| 389 | fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { | |
| 390 | const graph = b.graph; | |
| 391 | const arena = graph.arena; | |
| 392 | const gpa = wc.gpa; | |
| 393 | ||
| 394 | var s: Serialize = .{ .wc = wc, .arena = arena }; | |
| 395 | ||
| 396 | // Starting from all top-level steps in `b`, traverse the entire step graph | |
| 397 | // and add all step dependencies implied by module graphs. | |
| 398 | const top_level_steps = b.top_level_steps.values(); | |
| 399 | // Index corresponds to `Configuration.steps` index. | |
| 400 | var step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty; | |
| 401 | try step_map.ensureUnusedCapacity(arena, top_level_steps.len); | |
| 402 | for (top_level_steps) |tls| { | |
| 403 | step_map.putAssumeCapacityNoClobber(&tls.step, {}); | |
| 404 | } | |
| 405 | { | |
| 406 | while (wc.steps.items.len < step_map.count()) { | |
| 407 | const step = step_map.keys()[wc.steps.items.len]; | |
| 408 | ||
| 409 | // Set up any implied dependencies for this step. It's important that we do this first, so | |
| 410 | // that the loop below discovers steps implied by the module graph. | |
| 411 | try createModuleDependenciesForStep(step); | |
| 412 | ||
| 413 | try step_map.ensureUnusedCapacity(arena, step.dependencies.items.len); | |
| 414 | for (step.dependencies.items) |other_step| { | |
| 415 | step_map.putAssumeCapacity(other_step, {}); | |
| 416 | } | |
| 417 | ||
| 418 | // Add and then de-duplicate dependencies. | |
| 419 | const deps = d: { | |
| 420 | const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len); | |
| 421 | for (try wc.reserveLengthPrefixed(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step| | |
| 422 | dep.* = @intCast(step_map.getIndex(dep_step).?); | |
| 423 | break :d try wc.dedupeDeps(deps); | |
| 424 | }; | |
| 425 | ||
| 426 | try wc.steps.ensureTotalCapacity(gpa, step_map.entries.capacity); | |
| 427 | wc.steps.appendAssumeCapacity(.{ | |
| 428 | .name = try wc.addString(step.name), | |
| 429 | .owner = try s.builderToPackage(step.owner), | |
| 430 | .deps = deps, | |
| 431 | .max_rss = .fromBytes(step.max_rss), | |
| 432 | .extended = switch (step.tag) { | |
| 433 | .top_level => e: { | |
| 434 | const top_level: *Step.TopLevel = @fieldParentPtr("step", step); | |
| 435 | break :e @enumFromInt(try wc.addExtra(@as(Configuration.Step.TopLevel, .{ | |
| 436 | .description = try wc.addString(top_level.description), | |
| 437 | }))); | |
| 438 | }, | |
| 439 | .compile => e: { | |
| 440 | const c: *Step.Compile = @fieldParentPtr("step", step); | |
| 441 | const exec_cmd_args: []const ?[]const u8 = c.exec_cmd_args orelse &.{}; | |
| 442 | const installed_headers: []u32 = try arena.alloc(u32, c.installed_headers.items.len); | |
| 443 | for (installed_headers, c.installed_headers.items) |*dst, src| switch (src) { | |
| 444 | .file => |file| { | |
| 445 | dst.* = try wc.addExtra(@as(Configuration.Step.Compile.InstalledHeader.File, .{ | |
| 446 | .source = try s.addLazyPath(file.source), | |
| 447 | .dest_sub_path = try wc.addString(file.dest_rel_path), | |
| 448 | })); | |
| 449 | }, | |
| 450 | .directory => |directory| { | |
| 451 | const include_extensions = directory.options.include_extensions orelse &.{}; | |
| 452 | dst.* = try wc.addExtra(@as(Configuration.Step.Compile.InstalledHeader.Directory, .{ | |
| 453 | .flags = .{ | |
| 454 | .include_extensions = include_extensions.len != 0, | |
| 455 | .exclude_extensions = directory.options.exclude_extensions.len != 0, | |
| 456 | }, | |
| 457 | .source = try s.addLazyPath(directory.source), | |
| 458 | .dest_sub_path = try wc.addString(directory.dest_rel_path), | |
| 459 | .exclude_extensions = .{ .slice = try s.initStringList(directory.options.exclude_extensions) }, | |
| 460 | .include_extensions = .{ .slice = try s.initStringList(include_extensions) }, | |
| 461 | })); | |
| 462 | }, | |
| 463 | }; | |
| 464 | ||
| 465 | const extra_index = try wc.addExtra(@as(Configuration.Step.Compile, .{ | |
| 466 | .flags = .{ | |
| 467 | .filters_len = c.filters.len != 0, | |
| 468 | .exec_cmd_args_len = exec_cmd_args.len != 0, | |
| 469 | .installed_headers_len = installed_headers.len != 0, | |
| 470 | .force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0, | |
| 471 | ||
| 472 | .verbose_link = c.verbose_link, | |
| 473 | .verbose_cc = c.verbose_cc, | |
| 474 | .rdynamic = c.rdynamic, | |
| 475 | .import_memory = c.import_memory, | |
| 476 | .export_memory = c.export_memory, | |
| 477 | .import_symbols = c.import_symbols, | |
| 478 | .import_table = c.import_table, | |
| 479 | .export_table = c.export_table, | |
| 480 | .shared_memory = c.shared_memory, | |
| 481 | .link_eh_frame_hdr = c.link_eh_frame_hdr, | |
| 482 | .link_emit_relocs = c.link_emit_relocs, | |
| 483 | .link_function_sections = c.link_function_sections, | |
| 484 | .link_data_sections = c.link_data_sections, | |
| 485 | .linker_dynamicbase = c.linker_dynamicbase, | |
| 486 | .link_z_notext = c.link_z_notext, | |
| 487 | .link_z_relro = c.link_z_relro, | |
| 488 | .link_z_lazy = c.link_z_lazy, | |
| 489 | .link_z_defs = c.link_z_defs, | |
| 490 | .headerpad_max_install_names = c.headerpad_max_install_names, | |
| 491 | .dead_strip_dylibs = c.dead_strip_dylibs, | |
| 492 | .force_load_objc = c.force_load_objc, | |
| 493 | .discard_local_symbols = c.discard_local_symbols, | |
| 494 | .mingw_unicode_entry_point = c.mingw_unicode_entry_point, | |
| 495 | }, | |
| 496 | .flags2 = .{ | |
| 497 | .pie = .init(c.pie), | |
| 498 | .formatted_panics = .init(c.formatted_panics), | |
| 499 | .bundle_compiler_rt = .init(c.bundle_compiler_rt), | |
| 500 | .bundle_ubsan_rt = .init(c.bundle_ubsan_rt), | |
| 501 | .each_lib_rpath = .init(c.each_lib_rpath), | |
| 502 | .link_gc_sections = .init(c.link_gc_sections), | |
| 503 | .linker_allow_shlib_undefined = .init(c.linker_allow_shlib_undefined), | |
| 504 | .linker_allow_undefined_version = .init(c.linker_allow_undefined_version), | |
| 505 | .linker_enable_new_dtags = .init(c.linker_enable_new_dtags), | |
| 506 | .dll_export_fns = .init(c.dll_export_fns), | |
| 507 | .use_llvm = .init(c.use_llvm), | |
| 508 | .use_lld = .init(c.use_lld), | |
| 509 | .use_new_linker = .init(c.use_new_linker), | |
| 510 | .allow_so_scripts = .init(c.allow_so_scripts), | |
| 511 | .sanitize_coverage_trace_pc_guard = .init(c.sanitize_coverage_trace_pc_guard), | |
| 512 | .linkage = .init(c.linkage), | |
| 513 | }, | |
| 514 | .flags3 = .{ | |
| 515 | .is_linking_libc = c.is_linking_libc, | |
| 516 | .is_linking_libcpp = c.is_linking_libcpp, | |
| 517 | .version = c.version != null, | |
| 518 | .compress_debug_sections = c.compress_debug_sections, | |
| 519 | .initial_memory = c.initial_memory != null, | |
| 520 | .max_memory = c.max_memory != null, | |
| 521 | .kind = c.kind, | |
| 522 | .global_base = c.global_base != null, | |
| 523 | .test_runner_mode = if (c.test_runner) |tr| switch (tr.mode) { | |
| 524 | .simple => .simple, | |
| 525 | .server => .server, | |
| 526 | } else .default, | |
| 527 | .wasi_exec_model = .init(c.wasi_exec_model), | |
| 528 | .win32_manifest = c.win32_manifest != null, | |
| 529 | .win32_module_definition = c.win32_module_definition != null, | |
| 530 | .zig_lib_dir = c.zig_lib_dir != null, | |
| 531 | .rc_includes = c.rc_includes, | |
| 532 | .image_base = c.image_base != null, | |
| 533 | .build_id = .init(c.build_id), | |
| 534 | .entry = switch (c.entry) { | |
| 535 | .default => .default, | |
| 536 | .disabled => .disabled, | |
| 537 | .enabled => .enabled, | |
| 538 | .symbol_name => .symbol_name, | |
| 539 | }, | |
| 540 | .lto = .init(c.lto), | |
| 541 | .subsystem = .init(c.subsystem), | |
| 542 | }, | |
| 543 | .flags4 = .{ | |
| 544 | .libc_file = c.libc_file != null, | |
| 545 | .link_z_common_page_size = c.link_z_common_page_size != null, | |
| 546 | .link_z_max_page_size = c.link_z_max_page_size != null, | |
| 547 | .pagezero_size = c.pagezero_size != null, | |
| 548 | .stack_size = c.stack_size != null, | |
| 549 | .headerpad_size = c.headerpad_size != null, | |
| 550 | .error_limit = c.error_limit != null, | |
| 551 | .install_name = c.install_name != null, | |
| 552 | .entitlements = c.entitlements != null, | |
| 553 | .expect_errors = if (c.expect_errors) |x| switch (x) { | |
| 554 | .contains => .contains, | |
| 555 | .exact => .exact, | |
| 556 | .starts_with => .starts_with, | |
| 557 | .stderr_contains => .stderr_contains, | |
| 558 | } else .none, | |
| 559 | .linker_script = c.linker_script != null, | |
| 560 | .version_script = c.version_script != null, | |
| 561 | }, | |
| 562 | .root_module = try s.addModule(c.root_module), | |
| 563 | .root_name = try wc.addString(c.name), | |
| 564 | .linker_script = .{ .value = try s.addOptionalLazyPath(c.linker_script) }, | |
| 565 | .version_script = .{ .value = try s.addOptionalLazyPath(c.version_script) }, | |
| 566 | .zig_lib_dir = .{ .value = try s.addOptionalLazyPath(c.zig_lib_dir) }, | |
| 567 | .libc_file = .{ .value = try s.addOptionalLazyPath(c.libc_file) }, | |
| 568 | .win32_manifest = .{ .value = try s.addOptionalLazyPath(c.win32_manifest) }, | |
| 569 | .win32_module_definition = .{ .value = try s.addOptionalLazyPath(c.win32_module_definition) }, | |
| 570 | .entitlements = .{ .value = try s.addOptionalLazyPath(c.entitlements) }, | |
| 571 | .version = .{ .value = try s.addOptionalSemVer(c.version) }, | |
| 572 | .install_name = .{ .value = try s.addOptionalString(c.install_name) }, | |
| 573 | .initial_memory = .{ .value = c.initial_memory }, | |
| 574 | .max_memory = .{ .value = c.max_memory }, | |
| 575 | .global_base = .{ .value = c.global_base }, | |
| 576 | .image_base = .{ .value = c.image_base }, | |
| 577 | .link_z_common_page_size = .{ .value = c.link_z_common_page_size }, | |
| 578 | .link_z_max_page_size = .{ .value = c.link_z_max_page_size }, | |
| 579 | .pagezero_size = .{ .value = c.pagezero_size }, | |
| 580 | .stack_size = .{ .value = c.stack_size }, | |
| 581 | .headerpad_size = .{ .value = c.headerpad_size }, | |
| 582 | .error_limit = .{ .value = c.error_limit }, | |
| 583 | .entry = .{ .value = switch (c.entry) { | |
| 584 | .symbol_name => |name| try wc.addString(name), | |
| 585 | .default, .disabled, .enabled => null, | |
| 586 | } }, | |
| 587 | .build_id = .{ .value = if (c.build_id) |id| switch (id) { | |
| 588 | .hexstring => |*hexstring| try wc.addString(hexstring.toSlice()), | |
| 589 | .none, .fast, .uuid, .sha1, .md5 => null, | |
| 590 | } else null }, | |
| 591 | .filters = .{ .slice = try s.initStringList(c.filters) }, | |
| 592 | .exec_cmd_args = .{ .slice = try s.initOptionalStringList(exec_cmd_args) }, | |
| 593 | .installed_headers = .initErased(installed_headers), | |
| 594 | .force_undefined_symbols = .{ .slice = try s.initStringList(c.force_undefined_symbols.keys()) }, | |
| 595 | })); | |
| 596 | ||
| 597 | log.err("TODO serialize the trailing Compile step data", .{}); | |
| 598 | ||
| 599 | break :e @enumFromInt(extra_index); | |
| 600 | }, | |
| 601 | .install_artifact => e: { | |
| 602 | const ia: *Step.InstallArtifact = @fieldParentPtr("step", step); | |
| 603 | break :e @enumFromInt(try wc.addExtra(@as(Configuration.Step.InstallArtifact, .{ | |
| 604 | .flags = .{ | |
| 605 | .dylib_symlinks = ia.dylib_symlinks != null, | |
| 606 | }, | |
| 607 | .dest_dir = try addInstallDir(wc, ia.dest_dir), | |
| 608 | .dest_sub_path = try wc.addString(ia.dest_sub_path), | |
| 609 | .emitted_bin = try s.addOptionalLazyPathEnum(ia.emitted_bin), | |
| 610 | .implib_dir = try addInstallDir(wc, ia.implib_dir), | |
| 611 | .emitted_implib = try s.addOptionalLazyPathEnum(ia.emitted_implib), | |
| 612 | .pdb_dir = try addInstallDir(wc, ia.pdb_dir), | |
| 613 | .emitted_pdb = try s.addOptionalLazyPathEnum(ia.emitted_pdb), | |
| 614 | .h_dir = try addInstallDir(wc, ia.h_dir), | |
| 615 | .emitted_h = try s.addOptionalLazyPathEnum(ia.emitted_h), | |
| 616 | .artifact = stepIndex(&step_map, &ia.artifact.step), | |
| 617 | }))); | |
| 618 | }, | |
| 619 | .install_file => @panic("TODO"), | |
| 620 | .install_dir => @panic("TODO"), | |
| 621 | .remove_dir => @panic("TODO"), | |
| 622 | .fail => @panic("TODO"), | |
| 623 | .fmt => @panic("TODO"), | |
| 624 | .translate_c => @panic("TODO"), | |
| 625 | .write_file => @panic("TODO"), | |
| 626 | .update_source_files => @panic("TODO"), | |
| 627 | .run => e: { | |
| 628 | const run: *Step.Run = @fieldParentPtr("step", step); | |
| 629 | ||
| 630 | const captured_stdout: Configuration.OptionalString = if (run.captured_stdout) |cs| | |
| 631 | .init(try wc.addString(cs.output.basename)) | |
| 632 | else | |
| 633 | .none; | |
| 634 | ||
| 635 | const captured_stderr: Configuration.OptionalString = if (run.captured_stderr) |cs| | |
| 636 | .init(try wc.addString(cs.output.basename)) | |
| 637 | else | |
| 638 | .none; | |
| 639 | ||
| 640 | const extra_index = try wc.addExtra(@as(Configuration.Step.Run, .{ | |
| 641 | .flags = .{ | |
| 642 | .disable_zig_progress = run.disable_zig_progress, | |
| 643 | .skip_foreign_checks = run.skip_foreign_checks, | |
| 644 | .failing_to_execute_foreign_is_an_error = run.failing_to_execute_foreign_is_an_error, | |
| 645 | .has_side_effects = run.has_side_effects, | |
| 646 | .test_runner_mode = run.test_runner_mode, | |
| 647 | .color = run.color, | |
| 648 | .stdio = switch (run.stdio) { | |
| 649 | .infer_from_args => .infer_from_args, | |
| 650 | .inherit => .inherit, | |
| 651 | .check => .check, | |
| 652 | .zig_test => .zig_test, | |
| 653 | }, | |
| 654 | .stdin = switch (run.stdin) { | |
| 655 | .none => .none, | |
| 656 | .bytes => .bytes, | |
| 657 | .lazy_path => .lazy_path, | |
| 658 | }, | |
| 659 | .stdout_trim_whitespace = if (run.captured_stdout) |cs| cs.trim_whitespace else .none, | |
| 660 | .stderr_trim_whitespace = if (run.captured_stderr) |cs| cs.trim_whitespace else .none, | |
| 661 | .stdio_limit = run.stdio_limit != .unlimited, | |
| 662 | .producer = run.producer != null, | |
| 663 | }, | |
| 664 | .file_inputs_len = @intCast(run.file_inputs.items.len), | |
| 665 | .args_len = @intCast(run.argv.items.len), | |
| 666 | .cwd = try s.addOptionalLazyPathEnum(run.cwd), | |
| 667 | .captured_stdout = captured_stdout, | |
| 668 | .captured_stderr = captured_stderr, | |
| 669 | })); | |
| 670 | ||
| 671 | log.err("TODO serialize the trailing Run step data", .{}); | |
| 672 | ||
| 673 | break :e @enumFromInt(extra_index); | |
| 674 | }, | |
| 675 | .check_file => @panic("TODO"), | |
| 676 | .check_object => @panic("TODO"), | |
| 677 | .config_header => @panic("TODO"), | |
| 678 | .objcopy => @panic("TODO"), | |
| 679 | .options => @panic("TODO"), | |
| 680 | }, | |
| 681 | }); | |
| 682 | } | |
| 683 | } | |
| 684 | ||
| 685 | try wc.unlazy_deps.ensureUnusedCapacity(gpa, graph.needed_lazy_dependencies.keys().len); | |
| 686 | for (graph.needed_lazy_dependencies.keys()) |k| { | |
| 687 | wc.unlazy_deps.appendAssumeCapacity(try wc.addString(k)); | |
| 688 | } | |
| 689 | ||
| 690 | try wc.write(writer, .{ | |
| 691 | .default_step = stepIndex(&step_map, b.default_step), | |
| 692 | }); | |
| 693 | } | |
| 694 | ||
| 695 | fn addOptionalResolvedTarget( | |
| 696 | wc: *Configuration.Wip, | |
| 697 | optional_resolved_target: ?std.Build.ResolvedTarget, | |
| 698 | ) !Configuration.ResolvedTarget.OptionalIndex { | |
| 699 | const resolved_target = optional_resolved_target orelse return .none; | |
| 700 | log.debug("TODO deduplicate resolved targets", .{}); | |
| 701 | return @enumFromInt(try wc.addExtra(@as(Configuration.ResolvedTarget, .{ | |
| 702 | .query = try wc.addTargetQuery(resolved_target.query), | |
| 703 | .result = try wc.addTarget(resolved_target.result), | |
| 704 | }))); | |
| 705 | } | |
| 706 | ||
| 707 | fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Configuration.InstallDestDir { | |
| 708 | switch (install_dir orelse return .none) { | |
| 709 | .prefix => return .prefix, | |
| 710 | .lib => return .lib, | |
| 711 | .bin => return .bin, | |
| 712 | .header => return .header, | |
| 713 | .custom => |sub_path| return .initCustom(try wc.addString(sub_path)), | |
| 714 | } | |
| 715 | } | |
| 716 | ||
| 717 | fn stepIndex(step_map: *const std.AutoArrayHashMapUnmanaged(*Step, void), step: *Step) Configuration.Step.Index { | |
| 718 | return @enumFromInt(step_map.getIndex(step).?); | |
| 719 | } | |
| 720 | ||
| 721 | /// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which | |
| 722 | /// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`. | |
| 723 | fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void { | |
| 724 | const root_module = if (step.cast(Step.Compile)) |cs| root: { | |
| 725 | break :root cs.root_module; | |
| 726 | } else return; // not a compile step so no module dependencies | |
| 727 | ||
| 728 | // Starting from `root_module`, discover all modules in this graph. | |
| 729 | const modules = root_module.getGraph().modules; | |
| 730 | ||
| 731 | // For each of those modules, set up the implied step dependencies. | |
| 732 | for (modules) |mod| { | |
| 733 | if (mod.root_source_file) |lp| lp.addStepDependencies(step); | |
| 734 | for (mod.include_dirs.items) |include_dir| switch (include_dir) { | |
| 735 | .path, | |
| 736 | .path_system, | |
| 737 | .path_after, | |
| 738 | .framework_path, | |
| 739 | .framework_path_system, | |
| 740 | .embed_path, | |
| 741 | => |lp| lp.addStepDependencies(step), | |
| 742 | ||
| 743 | .other_step => |other| { | |
| 744 | other.getEmittedIncludeTree().addStepDependencies(step); | |
| 745 | step.dependOn(&other.step); | |
| 746 | }, | |
| 747 | ||
| 748 | .config_header_step => |other| step.dependOn(&other.step), | |
| 749 | }; | |
| 750 | for (mod.lib_paths.items) |lp| lp.addStepDependencies(step); | |
| 751 | for (mod.rpaths.items) |rpath| switch (rpath) { | |
| 752 | .lazy_path => |lp| lp.addStepDependencies(step), | |
| 753 | .special => {}, | |
| 754 | }; | |
| 755 | for (mod.link_objects.items) |link_object| switch (link_object) { | |
| 756 | .static_path, | |
| 757 | .assembly_file, | |
| 758 | => |lp| lp.addStepDependencies(step), | |
| 759 | .other_step => |other| step.dependOn(&other.step), | |
| 760 | .system_lib => {}, | |
| 761 | .c_source_file => |source| source.file.addStepDependencies(step), | |
| 762 | .c_source_files => |source_files| source_files.root.addStepDependencies(step), | |
| 763 | .win32_resource_file => |rc_source| { | |
| 764 | rc_source.file.addStepDependencies(step); | |
| 765 | for (rc_source.include_paths) |lp| lp.addStepDependencies(step); | |
| 766 | }, | |
| 767 | }; | |
| 768 | } | |
| 769 | } | |
| 770 | ||
| 771 | fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 { | |
| 772 | if (idx.* >= args.len) return null; | |
| 773 | defer idx.* += 1; | |
| 774 | return args[idx.*]; | |
| 775 | } | |
| 776 | ||
| 777 | fn nextArgOrFatal(args: []const [:0]const u8, idx: *usize) [:0]const u8 { | |
| 778 | return nextArg(args, idx) orelse { | |
| 779 | fatalWithHint("expected argument after: {s}", .{args[idx.* - 1]}); | |
| 780 | }; | |
| 781 | } | |
| 782 | ||
| 783 | fn expectArgOrFatal(args: []const [:0]const u8, index_ptr: *usize, first: []const u8) []const u8 { | |
| 784 | const next_arg = nextArg(args, index_ptr) orelse fatal("missing {q} argument", .{first}); | |
| 785 | if (!mem.eql(u8, first, next_arg)) fatal("expected {q} instead of {q}", .{ first, next_arg }); | |
| 786 | const arg = nextArg(args, index_ptr) orelse fatal("expected argument after {q}", .{first}); | |
| 787 | return arg; | |
| 788 | } | |
| 789 | ||
| 790 | const ErrorStyle = enum { | |
| 791 | verbose, | |
| 792 | minimal, | |
| 793 | verbose_clear, | |
| 794 | minimal_clear, | |
| 795 | fn verboseContext(s: ErrorStyle) bool { | |
| 796 | return switch (s) { | |
| 797 | .verbose, .verbose_clear => true, | |
| 798 | .minimal, .minimal_clear => false, | |
| 799 | }; | |
| 800 | } | |
| 801 | fn clearOnUpdate(s: ErrorStyle) bool { | |
| 802 | return switch (s) { | |
| 803 | .verbose, .minimal => false, | |
| 804 | .verbose_clear, .minimal_clear => true, | |
| 805 | }; | |
| 806 | } | |
| 807 | }; | |
| 808 | const MultilineErrors = enum { indent, newline, none }; | |
| 809 | const Summary = enum { all, new, failures, line, none }; | |
| 810 | ||
| 811 | fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn { | |
| 812 | log.info("to access the help menu: zig build -h", .{}); | |
| 813 | fatal(f, args); | |
| 814 | } | |
| 815 | ||
| 816 | fn serializeSystemIntegrationOptions(graph: *std.Build.Graph, wc: *Configuration.Wip) Allocator.Error!void { | |
| 817 | const gpa = wc.gpa; | |
| 818 | ||
| 819 | var bad = false; | |
| 820 | try wc.system_integrations.ensureTotalCapacityPrecise(gpa, graph.system_integration_options.entries.len); | |
| 821 | for (graph.system_integration_options.keys(), graph.system_integration_options.values()) |k, v| { | |
| 822 | wc.system_integrations.appendAssumeCapacity(.{ | |
| 823 | .name = try wc.addString(k), | |
| 824 | .status = switch (v) { | |
| 825 | .user_disabled, .user_enabled => x: { | |
| 826 | // The user tried to enable or disable a system library integration, but | |
| 827 | // the configure script did not recognize that option. | |
| 828 | log.err("system integration name not recognized by configure script: {s}", .{k}); | |
| 829 | bad = true; | |
| 830 | break :x .disabled; | |
| 831 | }, | |
| 832 | .declared_disabled => .disabled, | |
| 833 | .declared_enabled => .enabled, | |
| 834 | }, | |
| 835 | }); | |
| 836 | } | |
| 837 | if (bad) { | |
| 838 | log.info("help menu contains available options: zig build -h", .{}); | |
| 839 | process.exit(1); | |
| 840 | } | |
| 841 | } |
src/main.zig+1-1| ... | ... | @@ -5333,7 +5333,7 @@ fn cmdBuild( |
| 5333 | 5333 | .root_src_path = fs.path.basename(runner), |
| 5334 | 5334 | } else .{ |
| 5335 | 5335 | .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"), |
| 5336 | .root_src_path = "configure_runner.zig", | |
| 5336 | .root_src_path = "configurer.zig", | |
| 5337 | 5337 | }; |
| 5338 | 5338 | |
| 5339 | 5339 | const config = try Compilation.Config.resolve(.{ |