| ... | @@ -3166,6 +3166,8 @@ fn buildOutputType( | ... | @@ -3166,6 +3166,8 @@ fn buildOutputType( |
| 3166 | else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}), | 3166 | else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}), |
| 3167 | }; | 3167 | }; |
| 3168 | | 3168 | |
| | 3169 | const cwd_path = try introspect.getResolvedCwd(io, arena); |
| | 3170 | |
| 3169 | // This `init` calls `fatal` on error. | 3171 | // This `init` calls `fatal` on error. |
| 3170 | var dirs: Compilation.Directories = .init( | 3172 | var dirs: Compilation.Directories = .init( |
| 3171 | arena, | 3173 | arena, |
| ... | @@ -3182,6 +3184,7 @@ fn buildOutputType( | ... | @@ -3182,6 +3184,7 @@ fn buildOutputType( |
| 3182 | preopens, | 3184 | preopens, |
| 3183 | self_exe_path, | 3185 | self_exe_path, |
| 3184 | environ_map, | 3186 | environ_map, |
| | 3187 | cwd_path, |
| 3185 | ); | 3188 | ); |
| 3186 | defer dirs.deinit(io); | 3189 | defer dirs.deinit(io); |
| 3187 | | 3190 | |
| ... | @@ -4936,16 +4939,21 @@ test sanitizeExampleName { | ... | @@ -4936,16 +4939,21 @@ test sanitizeExampleName { |
| 4936 | try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project")); | 4939 | try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project")); |
| 4937 | } | 4940 | } |
| 4938 | | 4941 | |
| 4939 | fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, environ_map: *process.Environ.Map) !void { | 4942 | fn cmdBuild( |
| 4940 | dev.check(.build_command); | 4943 | gpa: Allocator, |
| 4941 | | 4944 | arena: Allocator, |
| | 4945 | io: Io, |
| | 4946 | args: []const []const u8, |
| | 4947 | environ_map: *process.Environ.Map, |
| | 4948 | ) !void { |
| 4942 | var build_file: ?[]const u8 = null; | 4949 | var build_file: ?[]const u8 = null; |
| 4943 | var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); | 4950 | var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); |
| 4944 | var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); | 4951 | var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); |
| 4945 | var override_local_cache_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_CACHE_DIR.get(environ_map); | 4952 | var override_local_cache_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_CACHE_DIR.get(environ_map); |
| 4946 | var override_pkg_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_PKG_DIR.get(environ_map); | 4953 | var override_pkg_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_PKG_DIR.get(environ_map); |
| 4947 | var override_build_runner: ?[]const u8 = EnvVar.ZIG_BUILD_RUNNER.get(environ_map); | 4954 | var override_make_runner: ?[]const u8 = EnvVar.ZIG_BUILD_RUNNER.get(environ_map); |
| 4948 | var child_argv: std.ArrayList([]const u8) = .empty; | 4955 | var configure_argv: std.ArrayList([]const u8) = .empty; |
| | 4956 | var make_argv: std.ArrayList([]const u8) = .empty; |
| 4949 | var forks: std.ArrayList(Fork) = .empty; | 4957 | var forks: std.ArrayList(Fork) = .empty; |
| 4950 | var reference_trace: ?u32 = null; | 4958 | var reference_trace: ?u32 = null; |
| 4951 | var debug_compile_errors = false; | 4959 | var debug_compile_errors = false; |
| ... | @@ -4965,46 +4973,32 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -4965,46 +4973,32 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 4965 | var debug_target: ?[]const u8 = null; | 4973 | var debug_target: ?[]const u8 = null; |
| 4966 | var debug_libc_paths_file: ?[]const u8 = null; | 4974 | var debug_libc_paths_file: ?[]const u8 = null; |
| 4967 | | 4975 | |
| 4968 | const argv_index_exe = child_argv.items.len; | 4976 | const argv_index_exe = configure_argv.items.len; |
| 4969 | _ = try child_argv.addOne(arena); | 4977 | _ = try configure_argv.addOne(arena); |
| 4970 | | 4978 | |
| 4971 | const self_exe_path = try process.executablePathAlloc(io, arena); | 4979 | const self_exe_path = try process.executablePathAlloc(io, arena); |
| 4972 | try child_argv.append(arena, self_exe_path); | 4980 | try configure_argv.append(arena, self_exe_path); |
| 4973 | | 4981 | |
| 4974 | const argv_index_zig_lib_dir = child_argv.items.len; | 4982 | const argv_index_zig_lib_dir = configure_argv.items.len; |
| 4975 | _ = try child_argv.addOne(arena); | 4983 | _ = try configure_argv.addOne(arena); |
| 4976 | | 4984 | |
| 4977 | const argv_index_build_file = child_argv.items.len; | 4985 | const argv_index_build_file = configure_argv.items.len; |
| 4978 | _ = try child_argv.addOne(arena); | 4986 | _ = try configure_argv.addOne(arena); |
| 4979 | | 4987 | |
| 4980 | const argv_index_cache_dir = child_argv.items.len; | 4988 | const argv_index_cache_dir = configure_argv.items.len; |
| 4981 | _ = try child_argv.addOne(arena); | 4989 | _ = try configure_argv.addOne(arena); |
| 4982 | | 4990 | |
| 4983 | const argv_index_global_cache_dir = child_argv.items.len; | 4991 | const argv_index_global_cache_dir = configure_argv.items.len; |
| 4984 | _ = try child_argv.addOne(arena); | 4992 | _ = try configure_argv.addOne(arena); |
| 4985 | | 4993 | |
| 4986 | try child_argv.appendSlice(arena, &.{ | 4994 | try configure_argv.appendSlice(arena, &.{ |
| 4987 | "--seed", | 4995 | "--seed", |
| 4988 | try std.fmt.allocPrint(arena, "0x{x}", .{randInt(io, u32)}), | 4996 | try std.fmt.allocPrint(arena, "0x{x}", .{randInt(io, u32)}), |
| 4989 | }); | 4997 | }); |
| 4990 | const argv_index_seed = child_argv.items.len - 1; | 4998 | const argv_index_seed = configure_argv.items.len - 1; |
| 4991 | | 4999 | |
| 4992 | // This parent process needs a way to obtain results from the configuration | 5000 | const argv_index_configuration_file = make_argv.items.len; |
| 4993 | // phase of the child process. In the future, the make phase will be | 5001 | _ = try make_argv.addOne(arena); |
| 4994 | // executed in a separate process than the configure phase, and we can then | | |
| 4995 | // use stdout from the configuration phase for this purpose. | | |
| 4996 | // | | |
| 4997 | // However, currently, both phases are in the same process, and Run Step | | |
| 4998 | // provides API for making the runned subprocesses inherit stdout and stderr | | |
| 4999 | // which means these streams are not available for passing metadata back | | |
| 5000 | // to the parent. | | |
| 5001 | // | | |
| 5002 | // Until make and configure phases are separated into different processes, | | |
| 5003 | // the strategy is to choose a temporary file name ahead of time, and then | | |
| 5004 | // read this file in the parent to obtain the results, in the case the child | | |
| 5005 | // exits with code 3. | | |
| 5006 | const results_tmp_file_nonce = std.fmt.hex(randInt(io, u64)); | | |
| 5007 | try child_argv.append(arena, "-Z" ++ results_tmp_file_nonce); | | |
| 5008 | | 5002 | |
| 5009 | var color: Color = .auto; | 5003 | var color: Color = .auto; |
| 5010 | var n_jobs: ?u32 = null; | 5004 | var n_jobs: ?u32 = null; |
| ... | @@ -5027,7 +5021,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5027,7 +5021,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5027 | } else if (mem.eql(u8, arg, "--build-runner")) { | 5021 | } else if (mem.eql(u8, arg, "--build-runner")) { |
| 5028 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); | 5022 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); |
| 5029 | i += 1; | 5023 | i += 1; |
| 5030 | override_build_runner = args[i]; | 5024 | override_make_runner = args[i]; |
| 5031 | continue; | 5025 | continue; |
| 5032 | } else if (mem.eql(u8, arg, "--cache-dir")) { | 5026 | } else if (mem.eql(u8, arg, "--cache-dir")) { |
| 5033 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); | 5027 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); |
| ... | @@ -5071,7 +5065,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5071,7 +5065,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5071 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); | 5065 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); |
| 5072 | i += 1; | 5066 | i += 1; |
| 5073 | system_pkg_dir_path = args[i]; | 5067 | system_pkg_dir_path = args[i]; |
| 5074 | try child_argv.append(arena, "--system"); | 5068 | try configure_argv.append(arena, "--system"); |
| 5075 | continue; | 5069 | continue; |
| 5076 | } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| { | 5070 | } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| { |
| 5077 | reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { | 5071 | reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { |
| ... | @@ -5081,7 +5075,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5081,7 +5075,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5081 | reference_trace = null; | 5075 | reference_trace = null; |
| 5082 | } else if (mem.eql(u8, arg, "--debug-log")) { | 5076 | } else if (mem.eql(u8, arg, "--debug-log")) { |
| 5083 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); | 5077 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); |
| 5084 | try child_argv.appendSlice(arena, args[i .. i + 2]); | 5078 | try make_argv.appendSlice(arena, args[i .. i + 2]); |
| 5085 | i += 1; | 5079 | i += 1; |
| 5086 | try addDebugLog(arena, args[i]); | 5080 | try addDebugLog(arena, args[i]); |
| 5087 | continue; | 5081 | continue; |
| ... | @@ -5131,7 +5125,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5131,7 +5125,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5131 | color = std.meta.stringToEnum(Color, args[i]) orelse { | 5125 | color = std.meta.stringToEnum(Color, args[i]) orelse { |
| 5132 | fatal("expected [auto|on|off] after {s}, found '{s}'", .{ arg, args[i] }); | 5126 | fatal("expected [auto|on|off] after {s}, found '{s}'", .{ arg, args[i] }); |
| 5133 | }; | 5127 | }; |
| 5134 | try child_argv.appendSlice(arena, &.{ arg, args[i] }); | 5128 | try configure_argv.appendSlice(arena, &.{ arg, args[i] }); |
| 5135 | continue; | 5129 | continue; |
| 5136 | } else if (mem.cutPrefix(u8, arg, "-j")) |str| { | 5130 | } else if (mem.cutPrefix(u8, arg, "-j")) |str| { |
| 5137 | const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| { | 5131 | const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| { |
| ... | @@ -5146,25 +5140,85 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5146,25 +5140,85 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5146 | } else if (mem.eql(u8, arg, "--seed")) { | 5140 | } else if (mem.eql(u8, arg, "--seed")) { |
| 5147 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); | 5141 | if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); |
| 5148 | i += 1; | 5142 | i += 1; |
| 5149 | child_argv.items[argv_index_seed] = args[i]; | 5143 | configure_argv.items[argv_index_seed] = args[i]; |
| 5150 | continue; | 5144 | continue; |
| 5151 | } else if (mem.eql(u8, arg, "--")) { | 5145 | } else if (mem.eql(u8, arg, "--")) { |
| 5152 | // The rest of the args are supposed to get passed onto | 5146 | // The rest of the args are supposed to get passed onto |
| 5153 | // build runner's `build.args` | 5147 | // build runner's `build.args` |
| 5154 | try child_argv.appendSlice(arena, args[i..]); | 5148 | try configure_argv.appendSlice(arena, args[i..]); |
| 5155 | break; | 5149 | break; |
| 5156 | } | 5150 | } |
| 5157 | } | 5151 | } |
| 5158 | try child_argv.append(arena, arg); | 5152 | try make_argv.append(arena, arg); |
| 5159 | } | 5153 | } |
| 5160 | } | 5154 | } |
| 5161 | | 5155 | |
| 5162 | const root_prog_node = std.Progress.start(io, .{ | 5156 | const root_prog_node = std.Progress.start(io, .{ |
| 5163 | .disable_printing = (color == .off), | 5157 | .disable_printing = (color == .off), |
| 5164 | .root_name = "Compile Build Script", | 5158 | .root_name = "", |
| 5165 | }); | 5159 | }); |
| 5166 | defer root_prog_node.end(); | 5160 | defer root_prog_node.end(); |
| 5167 | | 5161 | |
| | 5162 | process.raiseFileDescriptorLimit(); |
| | 5163 | |
| | 5164 | const cwd_path = introspect.getResolvedCwd(io, arena) catch |err| |
| | 5165 | fatal("failed to get current directory path: {t}", .{err}); |
| | 5166 | |
| | 5167 | const build_root = try findBuildRoot(arena, io, .{ |
| | 5168 | .cwd_path = cwd_path, |
| | 5169 | .build_file = build_file, |
| | 5170 | }); |
| | 5171 | |
| | 5172 | // This `init` calls `fatal` on error. |
| | 5173 | var dirs: Compilation.Directories = .init( |
| | 5174 | arena, |
| | 5175 | io, |
| | 5176 | override_lib_dir, |
| | 5177 | override_global_cache_dir, |
| | 5178 | .{ .override = path: { |
| | 5179 | if (override_local_cache_dir) |d| break :path d; |
| | 5180 | break :path try build_root.directory.join(arena, &.{introspect.default_local_zig_cache_basename}); |
| | 5181 | } }, |
| | 5182 | .empty, |
| | 5183 | self_exe_path, |
| | 5184 | environ_map, |
| | 5185 | cwd_path, |
| | 5186 | ); |
| | 5187 | defer dirs.deinit(io); |
| | 5188 | |
| | 5189 | const thread_limit = @min( |
| | 5190 | @max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), |
| | 5191 | std.math.maxInt(Zcu.PerThread.IdBacking), |
| | 5192 | ); |
| | 5193 | try setThreadLimit(arena, thread_limit); |
| | 5194 | |
| | 5195 | // Kick off an optimized compilation of the make runner. |
| | 5196 | var make_runner_task = io.async(compileMakeRunner, .{ io, .{ |
| | 5197 | .dirs = &dirs, |
| | 5198 | .optimize = .ReleaseSafe, |
| | 5199 | .parent_prog_node = root_prog_node, |
| | 5200 | } }); |
| | 5201 | defer if (make_runner_task.cancel(io)) |mr| mr.deinit(io) else |_| {}; |
| | 5202 | |
| | 5203 | // Cache lookup for configure options. If we get a match, we can skip |
| | 5204 | // execution of the configure script. If not, we get the file path to pass |
| | 5205 | // to the configure process. |
| | 5206 | var local_cache: Cache = .{ |
| | 5207 | .gpa = gpa, |
| | 5208 | .io = io, |
| | 5209 | .manifest_dir = try dirs.local_cache.handle.createDirPathOpen(io, "h", .{}), |
| | 5210 | .cwd = cwd_path, |
| | 5211 | }; |
| | 5212 | local_cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() }); |
| | 5213 | local_cache.addPrefix(dirs.zig_lib); |
| | 5214 | local_cache.addPrefix(dirs.local_cache); |
| | 5215 | local_cache.addPrefix(dirs.global_cache); |
| | 5216 | defer local_cache.manifest_dir.close(io); |
| | 5217 | |
| | 5218 | var config_man = local_cache.obtain(); |
| | 5219 | defer config_man.deinit(); |
| | 5220 | config_man.hash.addBytes(build_options.version); |
| | 5221 | |
| 5168 | // Normally the build runner is compiled for the host target but here is | 5222 | // Normally the build runner is compiled for the host target but here is |
| 5169 | // some code to help when debugging edits to the build runner so that you | 5223 | // some code to help when debugging edits to the build runner so that you |
| 5170 | // can make sure it compiles successfully on other targets. | 5224 | // can make sure it compiles successfully on other targets. |
| ... | @@ -5174,6 +5228,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5174,6 +5228,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5174 | const target_query = try std.Target.Query.parse(.{ | 5228 | const target_query = try std.Target.Query.parse(.{ |
| 5175 | .arch_os_abi = triple, | 5229 | .arch_os_abi = triple, |
| 5176 | }); | 5230 | }); |
| | 5231 | config_man.hash.addBytes(triple); |
| 5177 | break :t .{ | 5232 | break :t .{ |
| 5178 | .result = std.zig.resolveTargetQueryOrFatal(io, target_query), | 5233 | .result = std.zig.resolveTargetQueryOrFatal(io, target_query), |
| 5179 | .is_native_os = false, | 5234 | .is_native_os = false, |
| ... | @@ -5189,49 +5244,21 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5189,49 +5244,21 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5189 | .is_explicit_dynamic_linker = false, | 5244 | .is_explicit_dynamic_linker = false, |
| 5190 | }; | 5245 | }; |
| 5191 | }; | 5246 | }; |
| | 5247 | |
| 5192 | // Likewise, `--debug-libc` allows overriding the libc installation. | 5248 | // Likewise, `--debug-libc` allows overriding the libc installation. |
| 5193 | const libc_installation: ?*const LibCInstallation = lci: { | 5249 | const libc_installation: ?*const LibCInstallation = lci: { |
| 5194 | const paths_file = debug_libc_paths_file orelse break :lci null; | 5250 | const paths_file = debug_libc_paths_file orelse break :lci null; |
| 5195 | if (!build_options.enable_debug_extensions) unreachable; | 5251 | if (!build_options.enable_debug_extensions) unreachable; |
| 5196 | const lci = try arena.create(LibCInstallation); | 5252 | const lci = try arena.create(LibCInstallation); |
| 5197 | lci.* = try .parse(arena, io, paths_file, &resolved_target.result); | 5253 | lci.* = try .parse(arena, io, paths_file, &resolved_target.result); |
| | 5254 | LibCInstallation.addToHash(lci, &config_man.hash, resolved_target.result.abi); |
| 5198 | break :lci lci; | 5255 | break :lci lci; |
| 5199 | }; | 5256 | }; |
| 5200 | | 5257 | |
| 5201 | process.raiseFileDescriptorLimit(); | 5258 | configure_argv.items[argv_index_zig_lib_dir] = dirs.zig_lib.path orelse cwd_path; |
| 5202 | | 5259 | configure_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path; |
| 5203 | const cwd_path = try introspect.getResolvedCwd(io, arena); | 5260 | configure_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path; |
| 5204 | const build_root = try findBuildRoot(arena, io, .{ | 5261 | configure_argv.items[argv_index_cache_dir] = dirs.local_cache.path orelse cwd_path; |
| 5205 | .cwd_path = cwd_path, | | |
| 5206 | .build_file = build_file, | | |
| 5207 | }); | | |
| 5208 | | | |
| 5209 | // This `init` calls `fatal` on error. | | |
| 5210 | var dirs: Compilation.Directories = .init( | | |
| 5211 | arena, | | |
| 5212 | io, | | |
| 5213 | override_lib_dir, | | |
| 5214 | override_global_cache_dir, | | |
| 5215 | .{ .override = path: { | | |
| 5216 | if (override_local_cache_dir) |d| break :path d; | | |
| 5217 | break :path try build_root.directory.join(arena, &.{introspect.default_local_zig_cache_basename}); | | |
| 5218 | } }, | | |
| 5219 | .empty, | | |
| 5220 | self_exe_path, | | |
| 5221 | environ_map, | | |
| 5222 | ); | | |
| 5223 | defer dirs.deinit(io); | | |
| 5224 | | | |
| 5225 | child_argv.items[argv_index_zig_lib_dir] = dirs.zig_lib.path orelse cwd_path; | | |
| 5226 | child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path; | | |
| 5227 | child_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path; | | |
| 5228 | child_argv.items[argv_index_cache_dir] = dirs.local_cache.path orelse cwd_path; | | |
| 5229 | | | |
| 5230 | const thread_limit = @min( | | |
| 5231 | @max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), | | |
| 5232 | std.math.maxInt(Zcu.PerThread.IdBacking), | | |
| 5233 | ); | | |
| 5234 | try setThreadLimit(arena, thread_limit); | | |
| 5235 | | 5262 | |
| 5236 | // Dummy http client that is not actually used when fetch_command is unsupported. | 5263 | // Dummy http client that is not actually used when fetch_command is unsupported. |
| 5237 | // Prevents bootstrap from depending on a bunch of unnecessary stuff. | 5264 | // Prevents bootstrap from depending on a bunch of unnecessary stuff. |
| ... | @@ -5269,11 +5296,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5269,11 +5296,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5269 | | 5296 | |
| 5270 | // This loop is re-evaluated when the build script exits with an indication that it | 5297 | // This loop is re-evaluated when the build script exits with an indication that it |
| 5271 | // could not continue due to missing lazy dependencies. | 5298 | // could not continue due to missing lazy dependencies. |
| 5272 | while (true) { | 5299 | const configuration_path: Path = cp: while (true) { |
| 5273 | // We want to release all the locks before executing the child process, so we make a nice | 5300 | // We want to release all the locks before executing the child process, so we make a nice |
| 5274 | // big block here to ensure the cleanup gets run when we extract out our argv. | 5301 | // big block here to ensure the cleanup gets run when we extract out our argv. |
| 5275 | { | 5302 | { |
| 5276 | const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_build_runner) |runner| .{ | 5303 | const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_make_runner) |runner| .{ |
| 5277 | .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(runner) orelse "."}), | 5304 | .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(runner) orelse "."}), |
| 5278 | .root_src_path = fs.path.basename(runner), | 5305 | .root_src_path = fs.path.basename(runner), |
| 5279 | } else .{ | 5306 | } else .{ |
| ... | @@ -5497,6 +5524,9 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5497,6 +5524,9 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5497 | config, | 5524 | config, |
| 5498 | ); | 5525 | ); |
| 5499 | | 5526 | |
| | 5527 | const compile_prog_node = root_prog_node.start("Compile Configure Script", 0); |
| | 5528 | defer compile_prog_node.end(); |
| | 5529 | |
| 5500 | try root_mod.deps.put(arena, "@build", build_mod); | 5530 | try root_mod.deps.put(arena, "@build", build_mod); |
| 5501 | | 5531 | |
| 5502 | var create_diag: Compilation.CreateDiagnostic = undefined; | 5532 | var create_diag: Compilation.CreateDiagnostic = undefined; |
| ... | @@ -5528,7 +5558,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5528,7 +5558,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5528 | }; | 5558 | }; |
| 5529 | defer comp.destroy(); | 5559 | defer comp.destroy(); |
| 5530 | | 5560 | |
| 5531 | updateModule(comp, color, root_prog_node) catch |err| switch (err) { | 5561 | updateModule(comp, color, compile_prog_node) catch |err| switch (err) { |
| 5532 | error.CompileErrorsReported => process.exit(2), | 5562 | error.CompileErrorsReported => process.exit(2), |
| 5533 | else => |e| return e, | 5563 | else => |e| return e, |
| 5534 | }; | 5564 | }; |
| ... | @@ -5536,52 +5566,74 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5536,52 +5566,74 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5536 | // Since incremental compilation isn't done yet, we use cache_mode = whole | 5566 | // Since incremental compilation isn't done yet, we use cache_mode = whole |
| 5537 | // above, and thus the output file is already closed. | 5567 | // above, and thus the output file is already closed. |
| 5538 | //try comp.makeBinFileExecutable(); | 5568 | //try comp.makeBinFileExecutable(); |
| 5539 | child_argv.items[argv_index_exe] = try dirs.local_cache.join(arena, &.{ | 5569 | const hex_digest: []const u8 = &Cache.binToHex(comp.digest.?); |
| 5540 | "o", | 5570 | const exe_path: Path = .{ |
| 5541 | &Cache.binToHex(comp.digest.?), | 5571 | .root_dir = dirs.local_cache, |
| 5542 | comp.emit_bin.?, | 5572 | .sub_path = try std.fmt.allocPrint(arena, "o/{s}/{s}", .{ hex_digest, comp.emit_bin.? }), |
| 5543 | }); | 5573 | }; |
| | 5574 | _ = try config_man.addFilePath(exe_path, null); |
| | 5575 | configure_argv.items[argv_index_exe] = try exe_path.toString(arena); |
| | 5576 | |
| | 5577 | if (try config_man.hit()) { |
| | 5578 | const digest = config_man.final(); |
| | 5579 | break :cp .{ |
| | 5580 | .root_dir = dirs.local_cache, |
| | 5581 | .sub_path = try std.fmt.allocPrint(arena, "o/{s}", .{&digest}), |
| | 5582 | }; |
| | 5583 | } |
| 5544 | } | 5584 | } |
| 5545 | | 5585 | |
| 5546 | if (!process.can_spawn) { | 5586 | if (!process.can_spawn) { |
| 5547 | const cmd = try std.mem.join(arena, " ", child_argv.items); | 5587 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| 5548 | fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{s}", .{ native_os, cmd }); | 5588 | fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{s}", .{ native_os, cmd }); |
| 5549 | } | 5589 | } |
| | 5590 | |
| | 5591 | const rand_int = randInt(io, u64); |
| | 5592 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int); |
| | 5593 | const config_tmp_path: Path = .{ |
| | 5594 | .root_dir = dirs.local_cache, |
| | 5595 | .sub_path = tmp_dir_sub_path, |
| | 5596 | }; |
| | 5597 | const config_tmp_file: Io.File = try config_tmp_path.root_dir.handle.createFile( |
| | 5598 | io, |
| | 5599 | config_tmp_path.sub_path, |
| | 5600 | .{ .read = true, .exclusive = true }, |
| | 5601 | ); |
| | 5602 | defer config_tmp_file.close(io); |
| | 5603 | |
| 5550 | switch (term: { | 5604 | switch (term: { |
| 5551 | _ = try io.lockStderr(&.{}, .no_color); | 5605 | const child_node = root_prog_node.start("Run Configure Script", 0); |
| 5552 | defer io.unlockStderr(); | 5606 | defer child_node.end(); |
| 5553 | var child = std.process.spawn(io, .{ | 5607 | var child = std.process.spawn(io, .{ |
| 5554 | .argv = child_argv.items, | 5608 | .argv = configure_argv.items, |
| 5555 | }) catch |err| fatal("failed to spawn build runner {s}: {t}", .{ child_argv.items[0], err }); | 5609 | .stdout = .{ .file = config_tmp_file }, |
| | 5610 | .progress_node = child_node, |
| | 5611 | }) catch |err| fatal("failed to spawn configure script {s}: {t}", .{ configure_argv.items[0], err }); |
| 5556 | defer child.kill(io); | 5612 | defer child.kill(io); |
| 5557 | break :term child.wait(io) catch |err| | 5613 | break :term child.wait(io) catch |err| |
| 5558 | fatal("failed to wait build runner {s}: {t}", .{ child_argv.items[0], err }); | 5614 | fatal("failed to wait configure script {s}: {t}", .{ configure_argv.items[0], err }); |
| 5559 | }) { | 5615 | }) { |
| 5560 | .exited => |code| { | 5616 | .exited => |code| { |
| 5561 | if (code == 0) return cleanExit(io); | 5617 | if (code != 0) { |
| 5562 | // Indicates that the build runner has reported compile errors | 5618 | // Failure to produce the configuration file. |
| 5563 | // and this parent process does not need to report any further | 5619 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| 5564 | // diagnostics. | 5620 | fatal("the following configure command failed with exit code {d}:\n{s}", .{ code, cmd }); |
| 5565 | if (code == 2) process.exit(2); | 5621 | } |
| 5566 | | 5622 | // Even though the file is designed to be sent directly to make |
| 5567 | if (code == 3) { | 5623 | // runner, we must load it now because: |
| 5568 | if (!dev.env.supports(.fetch_command)) process.exit(3); | 5624 | // * If it contains additional file dependencies, we need to |
| 5569 | // Indicates the configure phase failed due to missing lazy | 5625 | // add them to `config_man` before obtaining the final digest. |
| 5570 | // dependencies and stdout contains the hashes of the ones | 5626 | // * If it contains a set of lazy packages that need to be |
| 5571 | // that are missing. | 5627 | // fetched, we need to fetch those now and re-run configure. |
| 5572 | const s = fs.path.sep_str; | 5628 | var configuration = std.zig.Configuration.load(arena, io, config_tmp_file) catch |err| |
| 5573 | const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce; | 5629 | fatal("failed to load configuration file {f}: {t}", .{ config_tmp_path, err }); |
| 5574 | const stdout = dirs.local_cache.handle.readFileAlloc(io, tmp_sub_path, arena, .limited(50 * 1024 * 1024)) catch |err| { | 5630 | |
| 5575 | fatal("unable to read results of configure phase from '{f}{s}': {t}", .{ | 5631 | if (configuration.unlazy_deps.len != 0) { |
| 5576 | dirs.local_cache, tmp_sub_path, err, | 5632 | if (!dev.env.supports(.fetch_command)) process.exit(1); |
| 5577 | }); | | |
| 5578 | }; | | |
| 5579 | dirs.local_cache.handle.deleteFile(io, tmp_sub_path) catch {}; | | |
| 5580 | | | |
| 5581 | var it = mem.splitScalar(u8, stdout, '\n'); | | |
| 5582 | var any_errors = false; | 5633 | var any_errors = false; |
| 5583 | while (it.next()) |hash| { | 5634 | for (configuration.unlazy_deps) |hash_string| { |
| 5584 | if (hash.len == 0) continue; | 5635 | const hash = hash_string.slice(&configuration); |
| | 5636 | assert(hash.len != 0); |
| 5585 | if (hash.len > Package.Hash.max_len) { | 5637 | if (hash.len > Package.Hash.max_len) { |
| 5586 | std.log.err("invalid digest (length {d} exceeds maximum): '{s}'", .{ | 5638 | std.log.err("invalid digest (length {d} exceeds maximum): '{s}'", .{ |
| 5587 | hash.len, hash, | 5639 | hash.len, hash, |
| ... | @@ -5591,10 +5643,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5591,10 +5643,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5591 | } | 5643 | } |
| 5592 | try unlazy_set.put(arena, .fromSlice(hash), {}); | 5644 | try unlazy_set.put(arena, .fromSlice(hash), {}); |
| 5593 | } | 5645 | } |
| 5594 | if (any_errors) process.exit(3); | 5646 | if (any_errors) process.exit(1); |
| 5595 | if (system_pkg_dir_path) |p| { | 5647 | if (system_pkg_dir_path) |p| { |
| 5596 | // In this mode, the system needs to provide these packages; they | 5648 | // In this mode, the system needs to provide these packages; they |
| 5597 | // cannot be fetched by Zig. | 5649 | // cannot be fetched by Zig. |
| | 5650 | const s = fs.path.sep_str; |
| 5598 | for (unlazy_set.keys()) |*hash| { | 5651 | for (unlazy_set.keys()) |*hash| { |
| 5599 | std.log.err("lazy dependency package not found: {s}" ++ s ++ "{s}", .{ | 5652 | std.log.err("lazy dependency package not found: {s}" ++ s ++ "{s}", .{ |
| 5600 | p, hash.toSlice(), | 5653 | p, hash.toSlice(), |
| ... | @@ -5602,28 +5655,115 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, | ... | @@ -5602,28 +5655,115 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 5602 | } | 5655 | } |
| 5603 | std.log.info("remote package fetching disabled due to --system mode", .{}); | 5656 | std.log.info("remote package fetching disabled due to --system mode", .{}); |
| 5604 | std.log.info("dependencies might be avoidable depending on build configuration", .{}); | 5657 | std.log.info("dependencies might be avoidable depending on build configuration", .{}); |
| 5605 | process.exit(3); | 5658 | process.exit(1); |
| 5606 | } | 5659 | } |
| 5607 | continue; | 5660 | continue :cp; |
| | 5661 | } |
| | 5662 | |
| | 5663 | for (configuration.path_deps_base, configuration.path_deps_sub) |base, sub| { |
| | 5664 | const conf_path: std.zig.Configuration.Path = .{ .base = base, .sub = sub }; |
| | 5665 | try config_man.addPathPost(conf_path.toCachePath(&configuration, arena)); |
| 5608 | } | 5666 | } |
| 5609 | | 5667 | |
| 5610 | const cmd = try std.mem.join(arena, " ", child_argv.items); | 5668 | const digest = config_man.final(); |
| 5611 | fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); | 5669 | const final_path: Path = .{ |
| | 5670 | .root_dir = dirs.local_cache, |
| | 5671 | .sub_path = try std.fmt.allocPrint(arena, "o/{s}", .{&digest}), |
| | 5672 | }; |
| | 5673 | Io.Dir.rename( |
| | 5674 | config_tmp_path.root_dir.handle, |
| | 5675 | config_tmp_path.sub_path, |
| | 5676 | final_path.root_dir.handle, |
| | 5677 | final_path.sub_path, |
| | 5678 | io, |
| | 5679 | ) catch |err| { |
| | 5680 | fatal("failed to rename configuration file from {f} into {f}: {t}", .{ |
| | 5681 | config_tmp_path, final_path, err, |
| | 5682 | }); |
| | 5683 | }; |
| | 5684 | config_man.writeManifest() catch |err| warn("failed to write cache manifest: {t}", .{err}); |
| | 5685 | |
| | 5686 | break :cp final_path; |
| 5612 | }, | 5687 | }, |
| 5613 | .signal => |sig| { | 5688 | .signal => |sig| { |
| 5614 | const cmd = try std.mem.join(arena, " ", child_argv.items); | 5689 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| 5615 | fatal("the following build command terminated with signal {t}:\n{s}", .{ sig, cmd }); | 5690 | fatal("the following configure command terminated with signal {t}:\n{s}", .{ sig, cmd }); |
| 5616 | }, | 5691 | }, |
| 5617 | .stopped => |sig| { | 5692 | .stopped => |sig| { |
| 5618 | const cmd = try std.mem.join(arena, " ", child_argv.items); | 5693 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| 5619 | fatal("the following build command stopped with signal {t}:\n{s}", .{ sig, cmd }); | 5694 | fatal("the following build command stopped with signal {t}:\n{s}", .{ sig, cmd }); |
| 5620 | }, | 5695 | }, |
| 5621 | .unknown => { | 5696 | .unknown => { |
| 5622 | const cmd = try std.mem.join(arena, " ", child_argv.items); | 5697 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| 5623 | fatal("the following build command crashed:\n{s}", .{cmd}); | 5698 | fatal("the following build command crashed:\n{s}", .{cmd}); |
| 5624 | }, | 5699 | }, |
| 5625 | } | 5700 | } |
| | 5701 | }; |
| | 5702 | |
| | 5703 | { |
| | 5704 | // Release all file system locks just before running the maker process. |
| | 5705 | var configuration_lock = config_man.toOwnedLock(); |
| | 5706 | defer configuration_lock.release(io); |
| | 5707 | |
| | 5708 | const make_runner = make_runner_task.await(io) catch |err| |
| | 5709 | fatal("failed to compile maker: {t}", .{err}); |
| | 5710 | defer make_runner.deinit(io); |
| | 5711 | |
| | 5712 | make_argv.items[0] = try make_runner.exe_path.toString(arena); |
| | 5713 | make_argv.items[argv_index_configuration_file] = try configuration_path.toString(arena); |
| | 5714 | } |
| | 5715 | |
| | 5716 | if (!process.can_spawn) { |
| | 5717 | const cmd = try std.mem.join(arena, " ", make_argv.items); |
| | 5718 | fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{s}", .{ native_os, cmd }); |
| | 5719 | } |
| | 5720 | |
| | 5721 | switch (term: { |
| | 5722 | _ = try io.lockStderr(&.{}, .no_color); |
| | 5723 | defer io.unlockStderr(); |
| | 5724 | var child = std.process.spawn(io, .{ |
| | 5725 | .argv = make_argv.items, |
| | 5726 | }) catch |err| fatal("failed to spawn maker {s}: {t}", .{ make_argv.items[0], err }); |
| | 5727 | defer child.kill(io); |
| | 5728 | break :term child.wait(io) catch |err| |
| | 5729 | fatal("failed to wait maker {s}: {t}", .{ make_argv.items[0], err }); |
| | 5730 | }) { |
| | 5731 | .exited => |code| { |
| | 5732 | if (code == 0) return cleanExit(io); |
| | 5733 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| | 5734 | fatal("the following maker command failed with exit code {d}:\n{s}", .{ code, cmd }); |
| | 5735 | }, |
| | 5736 | .signal => |sig| { |
| | 5737 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| | 5738 | fatal("the following maker command terminated with signal {t}:\n{s}", .{ sig, cmd }); |
| | 5739 | }, |
| | 5740 | else => { |
| | 5741 | const cmd = try std.mem.join(arena, " ", configure_argv.items); |
| | 5742 | fatal("the following maker command crashed:\n{s}", .{cmd}); |
| | 5743 | }, |
| | 5744 | } |
| | 5745 | } |
| | 5746 | |
| | 5747 | const MakeRunner = struct { |
| | 5748 | exe_path: Path, |
| | 5749 | |
| | 5750 | const Options = struct { |
| | 5751 | dirs: *Compilation.Directories, |
| | 5752 | optimize: std.builtin.OptimizeMode, |
| | 5753 | parent_prog_node: std.Progress.Node, |
| | 5754 | }; |
| | 5755 | |
| | 5756 | fn deinit(mr: MakeRunner, io: Io) void { |
| | 5757 | _ = mr; |
| | 5758 | _ = io; |
| | 5759 | @panic("TODO"); |
| 5626 | } | 5760 | } |
| | 5761 | }; |
| | 5762 | |
| | 5763 | fn compileMakeRunner(io: Io, options: MakeRunner.Options) !MakeRunner { |
| | 5764 | _ = io; |
| | 5765 | _ = options; |
| | 5766 | @panic("TODO"); |
| 5627 | } | 5767 | } |
| 5628 | | 5768 | |
| 5629 | const Fork = struct { | 5769 | const Fork = struct { |
| ... | @@ -5749,6 +5889,8 @@ fn jitCmdInner( | ... | @@ -5749,6 +5889,8 @@ fn jitCmdInner( |
| 5749 | const override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); | 5889 | const override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); |
| 5750 | const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); | 5890 | const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); |
| 5751 | | 5891 | |
| | 5892 | const cwd_path = try introspect.getResolvedCwd(io, arena); |
| | 5893 | |
| 5752 | // This `init` calls `fatal` on error. | 5894 | // This `init` calls `fatal` on error. |
| 5753 | var dirs: Compilation.Directories = .init( | 5895 | var dirs: Compilation.Directories = .init( |
| 5754 | arena, | 5896 | arena, |
| ... | @@ -5759,6 +5901,7 @@ fn jitCmdInner( | ... | @@ -5759,6 +5901,7 @@ fn jitCmdInner( |
| 5759 | preopens, | 5901 | preopens, |
| 5760 | self_exe_path, | 5902 | self_exe_path, |
| 5761 | environ_map, | 5903 | environ_map, |
| | 5904 | cwd_path, |
| 5762 | ); | 5905 | ); |
| 5763 | defer dirs.deinit(io); | 5906 | defer dirs.deinit(io); |
| 5764 | | 5907 | |