diff --git a/CMakeLists.txt b/CMakeLists.txt index e9c24112daefb6350d78de46f765828eab78a7a8..6f144cd68374ec7c0ec8c7ba7964cde06943d88a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -729,6 +729,8 @@ endif() set(ZIG_BUILD_ARGS + "--zig-lib=${PROJECT_SOURCE_DIR}/lib" + "-Dversion-string=${RESOLVED_ZIG_VERSION}" "-Dtarget=${ZIG_TARGET_TRIPLE}" "-Dcpu=${ZIG_TARGET_MCPU}" @@ -791,7 +793,7 @@ set(ZIG2_WORKING_DIR "${PROJECT_SOURCE_DIR}") add_custom_command( OUTPUT "${PROJECT_BINARY_DIR}/stage3/bin/zig" - COMMAND zig2 build --prefix "${PROJECT_BINARY_DIR}/stage3" ${ZIG_BUILD_ARGS} + COMMAND zig2 build ${ZIG_BUILD_ARGS} --prefix "${PROJECT_BINARY_DIR}/stage3" COMMENT "Building stage3" WORKING_DIRECTORY "${ZIG2_WORKING_DIR}" ) diff --git a/cmake/install.cmake b/cmake/install.cmake index 67ebe790532e4cac5cccdf8c0c165855804e67f5..1d3ebbf96016522757b18eb6a1dcb12ee07bce33 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -1,4 +1,4 @@ -set(ZIG_INSTALL_ARGS build --prefix "${CMAKE_INSTALL_PREFIX}" ${ZIG_BUILD_ARGS}) +set(ZIG_INSTALL_ARGS build ${ZIG_BUILD_ARGS} --prefix "${CMAKE_INSTALL_PREFIX}") execute_process( COMMAND "${ZIG_EXECUTABLE}" ${ZIG_INSTALL_ARGS} WORKING_DIRECTORY "${ZIG2_WORKING_DIR}" diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 565214d5d05cbe7978f3fc3538374cfc425b89dd..c48e60debe05c09a450a9f2a4c382c31604f950f 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -283,11 +283,11 @@ pub fn main(init: process.Init.Minimal) !void { cache_poison = .poisoned; configure_argv.appendAssumeCapacity("--cache-poison=poisoned"); } else if (mem.cutPrefix(u8, arg, "--cache-poison=")) |rest| { - // Allow the configurer process to report parse failure. - if (stringToEnum(std.Build.Graph.CachePoison, rest)) |poison| { - cache_poison = poison; - } - configure_argv.appendAssumeCapacity(arg); + // We have to report parse failure here otherwise we would + // potentially get false positive cache hits for misspellings. + cache_poison = stringToEnum(std.Build.Graph.CachePoison, rest) orelse + fatalWithHint("expected --cache-poison=[pure|poisoned|disallowed|ignored]; found: {s}", .{arg}); + if (cache_poison != .pure) configure_argv.appendAssumeCapacity(arg); } else if (mem.eql(u8, arg, "--verbose")) { // Intentionally is added both to make and configure but // does not go into the cache hash. @@ -316,6 +316,8 @@ pub fn main(init: process.Init.Minimal) !void { try forks.append(arena, .init(rest)); } else if (mem.eql(u8, arg, "--fork")) { try forks.append(arena, .init(nextArgOrFatal(args, &arg_i))); + } else if (mem.startsWith(u8, arg, "--zig-lib=")) { + fatal("--zig-lib= argument is special and must be first", .{}); } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { help_menu = true; } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) { @@ -981,27 +983,35 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { // This loop is re-evaluated when the build script exits with an indication that it // could not continue due to missing lazy dependencies. const configuration_path: Path, var configuration_lock: ?Cache.Lock = cp: while (true) { + build_mod.deps.clearRetainingCapacity(); + deps_mod.deps.clearRetainingCapacity(); + // Cache lookup for configure options. If we get a match, we can skip // execution of the configure script. If not, we get the file path to pass // to the configure process. // // In the hot path, we only check this cache, which means that also // configure source files need to go in here. - var config_man = graph.cache.obtain(); - defer config_man.deinit(); + var config_man_allocation: Cache.Manifest = undefined; + const config_man: ?*Cache.Manifest = switch (options.cache_poison) { + .pure, .disallowed, .ignored => m: { + config_man_allocation = graph.cache.obtain(); - for (options.cached_passthru_configure) |i| - config_man.hash.addBytes(configure_argv[i]); + for (options.cached_passthru_configure) |i| + config_man_allocation.hash.addBytes(configure_argv[i]); - if (target_arch_os_abi) |triple| - config_man.hash.addBytes(triple); + if (target_arch_os_abi) |triple| + config_man_allocation.hash.addBytes(triple); - // Prevents a `zig build` from getting a false positive cache hit following - // a `zig build --cache-poison=ignored`. - config_man.hash.add(options.cache_poison == .ignored); + // Prevents a `zig build` from getting a false positive cache hit following + // a `zig build --cache-poison=ignored`. + config_man_allocation.hash.add(options.cache_poison == .ignored); - build_mod.deps.clearRetainingCapacity(); - deps_mod.deps.clearRetainingCapacity(); + break :m &config_man_allocation; + }, + .poisoned => null, + }; + defer if (config_man) |man| man.deinit(); // We want to release all the locks before executing the child process, so we make a nice // big block here to ensure the cleanup gets run when we extract out our argv. @@ -1217,26 +1227,24 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { const compile_prog_node = options.parent_progress_node.start("Compile Configure Script", 0); defer compile_prog_node.end(); - switch (options.cache_poison) { - .pure, .disallowed, .ignored => if (try config_man.hit(compile_prog_node)) { - const digest = config_man.final(); + if (config_man) |man| { + if (try man.hit(compile_prog_node)) { + const digest = man.final(); break :cp .{ .{ .root_dir = graph.local_cache_root, .sub_path = try arena.print("c/{s}", .{&digest}), }, - config_man.toOwnedLock(), + man.toOwnedLock(), }; - }, - .poisoned => {}, // Don't bother checking for cache hit. + } } - const configure_exe_path: Path = if (std.zig.buildExeSubprocess(gpa, io, .{ .argv = build_configurer_argv.items, .cache_root = graph.local_cache_root, .root_name = configurer_exe_name, .environ_map = &graph.environ_map, - .cache_manifest = &config_man, + .cache_manifest = config_man, .arch_os_abi = target_arch_os_abi, .progress_node = compile_prog_node, .skip_log_cmdline_on_compile_errors = !graph.verbose, @@ -1318,20 +1326,21 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { continue :cp; } - for (configuration.path_deps) |path_dep| { + if (config_man) |man| for (configuration.path_deps) |path_dep| { switch (path_dep.flags.mode) { .directory => {}, // TODO - .contents => try config_man.addPathPost(confPathDepToCachePath(graph, &configuration, path_dep)), + .contents => try man.addPathPost(confPathDepToCachePath(graph, &configuration, path_dep)), .metadata => {}, // TODO } - } + }; // If it is poisoned, there is no point in moving it to cached // location. Just leave it in the tmp directory. if (configuration.poisoned) { break :cp .{ config_tmp_path, null }; } else { - const digest = config_man.final(); + const man = config_man.?; + const digest = man.final(); const final_path: Path = .{ .root_dir = graph.local_cache_root, .sub_path = try arena.print("c/{s}", .{&digest}), @@ -1362,8 +1371,8 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { config_tmp_path, final_path, e, }); }; - config_man.writeManifest() catch |err| log.warn("failed to write cache manifest: {t}", .{err}); - break :cp .{ final_path, config_man.toOwnedLock() }; + man.writeManifest() catch |err| log.warn("failed to write cache manifest: {t}", .{err}); + break :cp .{ final_path, man.toOwnedLock() }; } }; // Hang on to the configuration file lock until we finish loading the configuration file. diff --git a/lib/compiler/Maker/ScannedConfig.zig b/lib/compiler/Maker/ScannedConfig.zig index 8421cd008547b17ff14f1c416d64040d6c33f56e..b137ee3a5325c8f811488bbc57e9222e9f9229b7 100644 --- a/lib/compiler/Maker/ScannedConfig.zig +++ b/lib/compiler/Maker/ScannedConfig.zig @@ -342,6 +342,7 @@ pub fn printUsage(sc: *const ScannedConfig, graph: *Graph, w: *Writer) !void { \\ --build-file [file] Override path to build.zig \\ --cache-dir [path] Override path to local Zig cache directory \\ --global-cache-dir [path] Override path to global Zig cache directory + \\ --zig-lib=[arg] Override path to Zig lib directory \\ --seed [integer] For shuffling dependency traversal order (default: random) \\ --cache-poison[=mode] Override configuration caching behavior \\ pure (default) Avoid false positive cache hits diff --git a/lib/compiler/configurer.zig b/lib/compiler/configurer.zig index 9151d0d06bab9540bb2382693553ac06ad8d964e..a4f82bb391b5e35f2ab6cbdb67ec84d2208ae089 100644 --- a/lib/compiler/configurer.zig +++ b/lib/compiler/configurer.zig @@ -113,8 +113,8 @@ pub fn main(init: process.Init.Minimal) !void { } else if (mem.eql(u8, arg, "--verbose")) { graph.verbose = true; } else if (mem.cutPrefix(u8, arg, "--cache-poison=")) |rest| { - graph.cache_poison = std.meta.stringToEnum(std.Build.Graph.CachePoison, rest) orelse - fatalWithHint("expected --cache-poison=[pure|poisoned|disallowed|ignored]; found: {s}", .{arg}); + // Already parsed and validated by Maker. + graph.cache_poison = std.meta.stringToEnum(std.Build.Graph.CachePoison, rest).?; } else if (mem.eql(u8, arg, "--search-prefix")) { try graph.search_prefixes.append(arena, nextArgOrFatal(args, &arg_i)); } else { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 52e5f6c2608fce8fc49ccff006d786da91a6775e..64228b0de3ed9fa1a7cf921afdd300aab88fc344 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -1351,7 +1351,7 @@ pub const Directories = struct { if (override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib"); if (wasi) break :d getPreopen(preopens, "/lib"); break :d findZigLibDirFromSelfExe(arena, io, cwd, self_exe_path) catch |err| { - fatal("unable to find zig installation directory {q}: {t}", .{ self_exe_path, err }); + fatal("unable to find zig installation directory from executable path {q}: {t}", .{ self_exe_path, err }); }; }; diff --git a/src/main.zig b/src/main.zig index 56266b1724c15a1370dacbf4499a7bff47239f87..a7182be42eab77d15582da3ffc9341c855f72d55 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4932,9 +4932,18 @@ fn jitCmdInner( else options.release_mode; const strip = optimize_mode != .Debug; - const override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); + var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); + // Special case: if first arg starts with --zig-lib= then it is handled here. + var args_i: usize = 0; + if (args.len - args_i != 0) { + if (mem.cutPrefix(u8, args[args_i], "--zig-lib=")) |rest| { + override_lib_dir = rest; + args_i += 1; + } + } + const cwd_path = try std.zig.getResolvedCwd(io, arena); // This `init` calls `fatal` on error. @@ -4952,7 +4961,7 @@ fn jitCmdInner( defer dirs.deinit(io); var child_argv: std.ArrayList([]const u8) = .empty; - try child_argv.ensureUnusedCapacity(arena, args.len + 6); + try child_argv.ensureUnusedCapacity(arena, (args.len - args_i) + 6); // We want to release all the locks before executing the child process, so we make a nice // big block here to ensure the cleanup gets run when we extract out our argv. @@ -5064,7 +5073,7 @@ fn jitCmdInner( if (options.prepend_seed) child_argv.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{randInt(io, u32)})); - child_argv.appendSliceAssumeCapacity(args); + child_argv.appendSliceAssumeCapacity(args[args_i..]); if (EnvVar.ZIG_VERBOSE_CMD.isSet(environ_map)) { const cmd: std.zig.SubprocessCommand = .{