2023-03-20 09:23:10 +01:00
|
|
|
const std = @import("std");
|
2022-12-09 23:06:23 -07:00
|
|
|
const mem = std.mem;
|
|
|
|
|
const fs = std.fs;
|
2023-01-31 00:19:51 -07:00
|
|
|
const Step = std.Build.Step;
|
2023-07-19 10:49:34 +02:00
|
|
|
const LazyPath = std.Build.LazyPath;
|
2024-05-04 14:29:17 -04:00
|
|
|
const InstallDir = @This();
|
2022-12-09 23:06:23 -07:00
|
|
|
|
|
|
|
|
step: Step,
|
|
|
|
|
options: Options,
|
|
|
|
|
|
2024-05-04 14:29:17 -04:00
|
|
|
pub const base_id: Step.Id = .install_dir;
|
2022-12-09 23:06:23 -07:00
|
|
|
|
|
|
|
|
pub const Options = struct {
|
2023-07-19 10:49:34 +02:00
|
|
|
source_dir: LazyPath,
|
2024-05-04 14:29:17 -04:00
|
|
|
install_dir: std.Build.InstallDir,
|
2022-12-09 23:06:23 -07:00
|
|
|
install_subdir: []const u8,
|
|
|
|
|
/// File paths which end in any of these suffixes will be excluded
|
|
|
|
|
/// from being installed.
|
|
|
|
|
exclude_extensions: []const []const u8 = &.{},
|
2023-09-30 00:50:37 +02:00
|
|
|
/// Only file paths which end in any of these suffixes will be included
|
|
|
|
|
/// in installation. `null` means all suffixes are valid for this option.
|
|
|
|
|
/// `exclude_extensions` take precedence over `include_extensions`
|
|
|
|
|
include_extensions: ?[]const []const u8 = null,
|
2022-12-09 23:06:23 -07:00
|
|
|
/// File paths which end in any of these suffixes will result in
|
|
|
|
|
/// empty files being installed. This is mainly intended for large
|
|
|
|
|
/// test.zig files in order to prevent needless installation bloat.
|
|
|
|
|
/// However if the files were not present at all, then
|
|
|
|
|
/// `@import("test.zig")` would be a compile error.
|
|
|
|
|
blank_extensions: []const []const u8 = &.{},
|
|
|
|
|
|
2024-05-04 14:29:17 -04:00
|
|
|
fn dupe(opts: Options, b: *std.Build) Options {
|
2022-12-09 23:06:23 -07:00
|
|
|
return .{
|
2024-05-04 14:29:17 -04:00
|
|
|
.source_dir = opts.source_dir.dupe(b),
|
|
|
|
|
.install_dir = opts.install_dir.dupe(b),
|
|
|
|
|
.install_subdir = b.dupe(opts.install_subdir),
|
|
|
|
|
.exclude_extensions = b.dupeStrings(opts.exclude_extensions),
|
|
|
|
|
.include_extensions = if (opts.include_extensions) |incs| b.dupeStrings(incs) else null,
|
|
|
|
|
.blank_extensions = b.dupeStrings(opts.blank_extensions),
|
2022-12-09 23:06:23 -07:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-04 14:29:17 -04:00
|
|
|
pub fn create(owner: *std.Build, options: Options) *InstallDir {
|
|
|
|
|
const install_dir = owner.allocator.create(InstallDir) catch @panic("OOM");
|
|
|
|
|
install_dir.* = .{
|
zig build: many enhancements related to parallel building
Rework std.Build.Step to have an `owner: *Build` field. This
simplified the implementation of installation steps, as well as provided
some much-needed common API for the new parallelized build system.
--verbose is now defined very concretely: it prints to stderr just
before spawning a child process.
Child process execution is updated to conform to the new
parallel-friendly make() function semantics.
DRY up the failWithCacheError handling code. It now integrates properly
with the step graph instead of incorrectly dumping to stderr and calling
process exit.
In the main CLI, fix `zig fmt` crash when there are no errors and stdin
is used.
Deleted steps:
* EmulatableRunStep - this entire thing can be removed in favor of a
flag added to std.Build.RunStep called `skip_foreign_checks`.
* LogStep - this doesn't really fit with a multi-threaded build runner
and is effectively superseded by the new build summary output.
build runner:
* add -fsummary and -fno-summary to override the default behavior,
which is to print a summary if any of the build steps fail.
* print the dep prefix when emitting error messages for steps.
std.Build.FmtStep:
* This step now supports exclude paths as well as a check flag.
* The check flag decides between two modes, modify mode, and check
mode. These can be used to update source files in place, or to fail
the build, respectively.
Zig's own build.zig:
* The `test-fmt` step will do all the `zig fmt` checking that we expect
to be done. Since the `test` step depends on this one, we can simply
remove the explicit call to `zig fmt` in the CI.
* The new `fmt` step will actually perform `zig fmt` and update source
files in place.
std.Build.RunStep:
* expose max_stdio_size is a field (previously an unchangeable
hard-coded value).
* rework the API. Instead of configuring each stream independently,
there is a `stdio` field where you can choose between
`infer_from_args`, `inherit`, or `check`. These determine whether the
RunStep is considered to have side-effects or not. The previous
field, `condition` is gone.
* when stdio mode is set to `check` there is a slice of any number of
checks to make, which include things like exit code, stderr matching,
or stdout matching.
* remove the ill-defined `print` field.
* when adding an output arg, it takes the opportunity to give itself a
better name.
* The flag `skip_foreign_checks` is added. If this is true, a RunStep
which is configured to check the output of the executed binary will
not fail the build if the binary cannot be executed due to being for
a foreign binary to the host system which is running the build graph.
Command-line arguments such as -fqemu and -fwasmtime may affect
whether a binary is detected as foreign, as well as system
configuration such as Rosetta (macOS) and binfmt_misc (Linux).
- This makes EmulatableRunStep no longer needed.
* Fix the child process handling to properly integrate with the new
bulid API and to avoid deadlocks in stdout/stderr streams by polling
if necessary.
std.Build.RemoveDirStep now uses the open build_root directory handle
instead of an absolute path.
2023-03-01 22:56:37 -07:00
|
|
|
.step = Step.init(.{
|
2024-05-04 14:29:17 -04:00
|
|
|
.id = base_id,
|
2023-06-25 23:35:38 -04:00
|
|
|
.name = owner.fmt("install {s}/", .{options.source_dir.getDisplayName()}),
|
zig build: many enhancements related to parallel building
Rework std.Build.Step to have an `owner: *Build` field. This
simplified the implementation of installation steps, as well as provided
some much-needed common API for the new parallelized build system.
--verbose is now defined very concretely: it prints to stderr just
before spawning a child process.
Child process execution is updated to conform to the new
parallel-friendly make() function semantics.
DRY up the failWithCacheError handling code. It now integrates properly
with the step graph instead of incorrectly dumping to stderr and calling
process exit.
In the main CLI, fix `zig fmt` crash when there are no errors and stdin
is used.
Deleted steps:
* EmulatableRunStep - this entire thing can be removed in favor of a
flag added to std.Build.RunStep called `skip_foreign_checks`.
* LogStep - this doesn't really fit with a multi-threaded build runner
and is effectively superseded by the new build summary output.
build runner:
* add -fsummary and -fno-summary to override the default behavior,
which is to print a summary if any of the build steps fail.
* print the dep prefix when emitting error messages for steps.
std.Build.FmtStep:
* This step now supports exclude paths as well as a check flag.
* The check flag decides between two modes, modify mode, and check
mode. These can be used to update source files in place, or to fail
the build, respectively.
Zig's own build.zig:
* The `test-fmt` step will do all the `zig fmt` checking that we expect
to be done. Since the `test` step depends on this one, we can simply
remove the explicit call to `zig fmt` in the CI.
* The new `fmt` step will actually perform `zig fmt` and update source
files in place.
std.Build.RunStep:
* expose max_stdio_size is a field (previously an unchangeable
hard-coded value).
* rework the API. Instead of configuring each stream independently,
there is a `stdio` field where you can choose between
`infer_from_args`, `inherit`, or `check`. These determine whether the
RunStep is considered to have side-effects or not. The previous
field, `condition` is gone.
* when stdio mode is set to `check` there is a slice of any number of
checks to make, which include things like exit code, stderr matching,
or stdout matching.
* remove the ill-defined `print` field.
* when adding an output arg, it takes the opportunity to give itself a
better name.
* The flag `skip_foreign_checks` is added. If this is true, a RunStep
which is configured to check the output of the executed binary will
not fail the build if the binary cannot be executed due to being for
a foreign binary to the host system which is running the build graph.
Command-line arguments such as -fqemu and -fwasmtime may affect
whether a binary is detected as foreign, as well as system
configuration such as Rosetta (macOS) and binfmt_misc (Linux).
- This makes EmulatableRunStep no longer needed.
* Fix the child process handling to properly integrate with the new
bulid API and to avoid deadlocks in stdout/stderr streams by polling
if necessary.
std.Build.RemoveDirStep now uses the open build_root directory handle
instead of an absolute path.
2023-03-01 22:56:37 -07:00
|
|
|
.owner = owner,
|
2023-02-14 12:47:45 -07:00
|
|
|
.makeFn = make,
|
|
|
|
|
}),
|
zig build: many enhancements related to parallel building
Rework std.Build.Step to have an `owner: *Build` field. This
simplified the implementation of installation steps, as well as provided
some much-needed common API for the new parallelized build system.
--verbose is now defined very concretely: it prints to stderr just
before spawning a child process.
Child process execution is updated to conform to the new
parallel-friendly make() function semantics.
DRY up the failWithCacheError handling code. It now integrates properly
with the step graph instead of incorrectly dumping to stderr and calling
process exit.
In the main CLI, fix `zig fmt` crash when there are no errors and stdin
is used.
Deleted steps:
* EmulatableRunStep - this entire thing can be removed in favor of a
flag added to std.Build.RunStep called `skip_foreign_checks`.
* LogStep - this doesn't really fit with a multi-threaded build runner
and is effectively superseded by the new build summary output.
build runner:
* add -fsummary and -fno-summary to override the default behavior,
which is to print a summary if any of the build steps fail.
* print the dep prefix when emitting error messages for steps.
std.Build.FmtStep:
* This step now supports exclude paths as well as a check flag.
* The check flag decides between two modes, modify mode, and check
mode. These can be used to update source files in place, or to fail
the build, respectively.
Zig's own build.zig:
* The `test-fmt` step will do all the `zig fmt` checking that we expect
to be done. Since the `test` step depends on this one, we can simply
remove the explicit call to `zig fmt` in the CI.
* The new `fmt` step will actually perform `zig fmt` and update source
files in place.
std.Build.RunStep:
* expose max_stdio_size is a field (previously an unchangeable
hard-coded value).
* rework the API. Instead of configuring each stream independently,
there is a `stdio` field where you can choose between
`infer_from_args`, `inherit`, or `check`. These determine whether the
RunStep is considered to have side-effects or not. The previous
field, `condition` is gone.
* when stdio mode is set to `check` there is a slice of any number of
checks to make, which include things like exit code, stderr matching,
or stdout matching.
* remove the ill-defined `print` field.
* when adding an output arg, it takes the opportunity to give itself a
better name.
* The flag `skip_foreign_checks` is added. If this is true, a RunStep
which is configured to check the output of the executed binary will
not fail the build if the binary cannot be executed due to being for
a foreign binary to the host system which is running the build graph.
Command-line arguments such as -fqemu and -fwasmtime may affect
whether a binary is detected as foreign, as well as system
configuration such as Rosetta (macOS) and binfmt_misc (Linux).
- This makes EmulatableRunStep no longer needed.
* Fix the child process handling to properly integrate with the new
bulid API and to avoid deadlocks in stdout/stderr streams by polling
if necessary.
std.Build.RemoveDirStep now uses the open build_root directory handle
instead of an absolute path.
2023-03-01 22:56:37 -07:00
|
|
|
.options = options.dupe(owner),
|
2022-12-09 23:06:23 -07:00
|
|
|
};
|
2024-05-04 14:29:17 -04:00
|
|
|
options.source_dir.addStepDependencies(&install_dir.step);
|
|
|
|
|
return install_dir;
|
2022-12-09 23:06:23 -07:00
|
|
|
}
|
|
|
|
|
|
2024-07-14 19:48:08 -07:00
|
|
|
fn make(step: *Step, options: Step.MakeOptions) !void {
|
|
|
|
|
_ = options;
|
2024-03-02 23:32:01 +01:00
|
|
|
const b = step.owner;
|
2024-05-04 14:29:17 -04:00
|
|
|
const install_dir: *InstallDir = @fieldParentPtr("step", step);
|
2024-07-09 23:15:22 -07:00
|
|
|
step.clearWatchInputs();
|
2024-03-02 23:32:01 +01:00
|
|
|
const arena = b.allocator;
|
2024-05-04 14:29:17 -04:00
|
|
|
const dest_prefix = b.getInstallPath(install_dir.options.install_dir, install_dir.options.install_subdir);
|
2024-07-09 23:15:22 -07:00
|
|
|
const src_dir_path = install_dir.options.source_dir.getPath3(b, step);
|
2024-07-10 15:09:46 -07:00
|
|
|
const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir);
|
|
|
|
|
var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
|
2024-07-09 23:15:22 -07:00
|
|
|
return step.fail("unable to open source directory '{}': {s}", .{
|
|
|
|
|
src_dir_path, @errorName(err),
|
2023-01-24 17:24:16 -07:00
|
|
|
});
|
|
|
|
|
};
|
2022-12-09 23:06:23 -07:00
|
|
|
defer src_dir.close();
|
2023-03-03 17:49:14 -07:00
|
|
|
var it = try src_dir.walk(arena);
|
|
|
|
|
var all_cached = true;
|
2022-12-09 23:06:23 -07:00
|
|
|
next_entry: while (try it.next()) |entry| {
|
2024-05-04 14:29:17 -04:00
|
|
|
for (install_dir.options.exclude_extensions) |ext| {
|
2022-12-09 23:06:23 -07:00
|
|
|
if (mem.endsWith(u8, entry.path, ext)) {
|
|
|
|
|
continue :next_entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-04 14:29:17 -04:00
|
|
|
if (install_dir.options.include_extensions) |incs| {
|
2023-09-30 00:50:37 +02:00
|
|
|
var found = false;
|
|
|
|
|
for (incs) |inc| {
|
|
|
|
|
if (mem.endsWith(u8, entry.path, inc)) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found) continue :next_entry;
|
|
|
|
|
}
|
2022-12-09 23:06:23 -07:00
|
|
|
|
2023-03-03 17:49:14 -07:00
|
|
|
// relative to src build root
|
2024-07-09 23:15:22 -07:00
|
|
|
const src_sub_path = try src_dir_path.join(arena, entry.path);
|
2024-05-04 14:29:17 -04:00
|
|
|
const dest_path = b.pathJoin(&.{ dest_prefix, entry.path });
|
2023-03-03 17:49:14 -07:00
|
|
|
const cwd = fs.cwd();
|
2022-12-09 23:06:23 -07:00
|
|
|
|
|
|
|
|
switch (entry.kind) {
|
2024-07-09 23:15:22 -07:00
|
|
|
.directory => {
|
2024-07-10 15:09:46 -07:00
|
|
|
if (need_derived_inputs) try step.addDirectoryWatchInputFromPath(src_sub_path);
|
2024-07-09 23:15:22 -07:00
|
|
|
try cwd.makePath(dest_path);
|
2024-07-10 00:42:41 -07:00
|
|
|
// TODO: set result_cached=false if the directory did not already exist.
|
2024-07-09 23:15:22 -07:00
|
|
|
},
|
2023-05-20 23:06:42 +01:00
|
|
|
.file => {
|
2024-05-04 14:29:17 -04:00
|
|
|
for (install_dir.options.blank_extensions) |ext| {
|
2022-12-09 23:06:23 -07:00
|
|
|
if (mem.endsWith(u8, entry.path, ext)) {
|
2024-03-02 23:32:01 +01:00
|
|
|
try b.truncateFile(dest_path);
|
2022-12-09 23:06:23 -07:00
|
|
|
continue :next_entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-05 16:11:04 -07:00
|
|
|
const prev_status = fs.Dir.updateFile(
|
2024-07-09 23:15:22 -07:00
|
|
|
src_sub_path.root_dir.handle,
|
|
|
|
|
src_sub_path.sub_path,
|
2023-03-03 17:49:14 -07:00
|
|
|
cwd,
|
|
|
|
|
dest_path,
|
|
|
|
|
.{},
|
2023-03-05 16:11:04 -07:00
|
|
|
) catch |err| {
|
2024-07-09 23:15:22 -07:00
|
|
|
return step.fail("unable to update file from '{}' to '{s}': {s}", .{
|
|
|
|
|
src_sub_path, dest_path, @errorName(err),
|
2023-03-05 16:11:04 -07:00
|
|
|
});
|
|
|
|
|
};
|
2023-03-03 17:49:14 -07:00
|
|
|
all_cached = all_cached and prev_status == .fresh;
|
2022-12-09 23:06:23 -07:00
|
|
|
},
|
|
|
|
|
else => continue,
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-03 17:49:14 -07:00
|
|
|
|
|
|
|
|
step.result_cached = all_cached;
|
2022-12-09 23:06:23 -07:00
|
|
|
}
|