build system: implement --system [dir]

This prevents package fetching and enables system_package_mode in the
build system which flips the defaults for system integrations.
This commit is contained in:
Andrew Kelley 2024-02-01 22:43:41 -07:00
parent 22537873f4
commit ed4ccea7ba
4 changed files with 70 additions and 17 deletions

View File

@ -202,6 +202,11 @@ pub fn main() !void {
builder.debug_pkg_config = true;
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
builder.debug_compile_errors = true;
} else if (mem.eql(u8, arg, "--system")) {
// The usage text shows another argument after this parameter
// but it is handled by the parent process. The build runner
// only sees this flag.
graph.system_package_mode = true;
} else if (mem.eql(u8, arg, "--glibc-runtimes")) {
builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--verbose-link")) {
@ -1053,18 +1058,14 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
try out_stream.writeAll(
\\
\\General Options:
\\ -p, --prefix [path] Where to put installed files (default: zig-out)
\\ --prefix-lib-dir [path] Where to put installed libraries
\\ --prefix-exe-dir [path] Where to put installed executables
\\ --prefix-include-dir [path] Where to put installed C header files
\\ -p, --prefix [path] Where to install files (default: zig-out)
\\ --prefix-lib-dir [path] Where to install libraries
\\ --prefix-exe-dir [path] Where to install executables
\\ --prefix-include-dir [path] Where to install C header files
\\
\\ --release[=mode] Request release mode, optionally specifying a
\\ preferred optimization mode: fast, safe, small
\\
\\ --sysroot [path] Set the system root directory (usually /)
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers
\\ --libc [file] Provide a file which specifies libc paths
\\
\\ -fdarling, -fno-darling Integration with system-installed Darling to
\\ execute macOS programs on Linux hosts
\\ (default: no)
@ -1122,13 +1123,18 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
try out_stream.writeAll(
\\
\\System Integration Options:
\\ --system [dir] System Package Mode. Disable fetching; prefer system libs
\\ -fsys=[name] Enable a system integration
\\ -fno-sys=[name] Disable a system integration
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers
\\ --sysroot [path] Set the system root directory (usually /)
\\ --libc [file] Provide a file which specifies libc paths
\\
\\ --host-target [triple] Use the provided target as the host
\\ --host-cpu [cpu] Use the provided CPU as the host
\\ --host-dynamic-linker [path] Use the provided dynamic linker as the host
\\
\\ --system [pkgdir] Disable package fetching; enable all integrations
\\ -fsys=[name] Enable a system integration
\\ -fno-sys=[name] Disable a system integration
\\
\\ Available System Integrations: Enabled:
\\
);

View File

@ -1254,7 +1254,7 @@ pub fn standardOptimizeOption(b: *Build, options: StandardOptimizeOptionOptions)
if (b.option(
std.builtin.OptimizeMode,
"optimize",
"Prioritize performance, safety, or binary size (-O flag)",
"Prioritize performance, safety, or binary size",
)) |mode| {
return mode;
}

View File

@ -80,6 +80,15 @@ pub const JobQueue = struct {
thread_pool: *ThreadPool,
wait_group: WaitGroup = .{},
global_cache: Cache.Directory,
/// If true then, no fetching occurs, and:
/// * The `global_cache` directory is assumed to be the direct parent
/// directory of on-disk packages rather than having the "p/" directory
/// prefix inside of it.
/// * An error occurs if any non-lazy packages are not already present in
/// the package cache directory.
/// * Missing hash field causes an error, and no fetching occurs so it does
/// not print the correct hash like usual.
read_only: bool,
recursive: bool,
/// Dumps hash information to stdout which can be used to troubleshoot why
/// two hashes of the same package do not match.
@ -270,7 +279,8 @@ pub fn run(f: *Fetch) RunError!void {
// We want to fail unless the resolved relative path has a
// prefix of "p/$hash/".
const digest_len = @typeInfo(Manifest.MultiHashHexDigest).Array.len;
const expected_prefix = f.parent_package_root.sub_path[0 .. "p/".len + digest_len];
const prefix_len: usize = if (f.job_queue.read_only) 0 else "p/".len;
const expected_prefix = f.parent_package_root.sub_path[0 .. prefix_len + digest_len];
if (!std.mem.startsWith(u8, pkg_root.sub_path, expected_prefix)) {
return f.fail(
f.location_tok,
@ -311,7 +321,9 @@ pub fn run(f: *Fetch) RunError!void {
const s = fs.path.sep_str;
if (remote.hash) |expected_hash| {
const pkg_sub_path = "p" ++ s ++ expected_hash;
const prefixed_pkg_sub_path = "p" ++ s ++ expected_hash;
const prefix_len: usize = if (f.job_queue.read_only) "p/".len else 0;
const pkg_sub_path = prefixed_pkg_sub_path[prefix_len..];
if (cache_root.handle.access(pkg_sub_path, .{})) |_| {
f.package_root = .{
.root_dir = cache_root,
@ -322,7 +334,14 @@ pub fn run(f: *Fetch) RunError!void {
if (!f.job_queue.recursive) return;
return queueJobsForDeps(f);
} else |err| switch (err) {
error.FileNotFound => {},
error.FileNotFound => {
if (f.job_queue.read_only) return f.fail(
f.location_tok,
try eb.printString("package not found at '{}{s}'", .{
cache_root, pkg_sub_path,
}),
);
},
else => |e| {
try eb.addRootErrorMessage(.{
.msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{
@ -332,6 +351,12 @@ pub fn run(f: *Fetch) RunError!void {
return error.FetchFailed;
},
}
} else {
try eb.addRootErrorMessage(.{
.msg = try eb.addString("dependency is missing hash field"),
.src_loc = try f.srcLoc(f.location_tok),
});
return error.FetchFailed;
}
// Fetch and unpack the remote into a temporary directory.

View File

@ -5179,6 +5179,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
var verbose_cimport = false;
var verbose_llvm_cpu_features = false;
var fetch_only = false;
var system_pkg_dir_path: ?[]const u8 = null;
const argv_index_exe = child_argv.items.len;
_ = try child_argv.addOne();
@ -5235,6 +5236,12 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
reference_trace = 256;
} else if (mem.eql(u8, arg, "--fetch")) {
fetch_only = true;
} else if (mem.eql(u8, arg, "--system")) {
if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
i += 1;
system_pkg_dir_path = args[i];
try child_argv.append("--system");
continue;
} else if (mem.startsWith(u8, arg, "-freference-trace=")) {
const num = arg["-freference-trace=".len..];
reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
@ -5419,8 +5426,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
var http_client: std.http.Client = .{ .allocator = gpa };
defer http_client.deinit();
try http_client.loadDefaultProxies();
var progress: std.Progress = .{ .dont_print_on_dumb = true };
const root_prog_node = progress.start("Fetch Packages", 0);
defer root_prog_node.end();
@ -5429,12 +5434,28 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
.http_client = &http_client,
.thread_pool = &thread_pool,
.global_cache = global_cache_directory,
.read_only = false,
.recursive = true,
.debug_hash = false,
.work_around_btrfs_bug = work_around_btrfs_bug,
};
defer job_queue.deinit();
if (system_pkg_dir_path) |p| {
job_queue.global_cache = .{
.path = p,
.handle = fs.cwd().openDir(p, .{}) catch |err| {
fatal("unable to open system package directory '{s}': {s}", .{
p, @errorName(err),
});
},
};
job_queue.read_only = true;
cleanup_build_dir = job_queue.global_cache.handle;
} else {
try http_client.loadDefaultProxies();
}
try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);
try job_queue.table.ensureUnusedCapacity(gpa, 1);
@ -7363,6 +7384,7 @@ fn cmdFetch(
.thread_pool = &thread_pool,
.global_cache = global_cache_directory,
.recursive = false,
.read_only = false,
.debug_hash = debug_hash,
.work_around_btrfs_bug = work_around_btrfs_bug,
};