Merge pull request #14571 from ziglang/more-build-zig
std.Build.ConfigHeaderStep: support sentinel-terminated strings
This commit is contained in:
@@ -216,6 +216,9 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/atomic/stack.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/base64.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/buf_map.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/Build.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/Build/Cache.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/Build/Cache/DepTokenizer.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/c.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
|
||||
@@ -523,9 +526,7 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Air.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/AstGen.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Cache.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Compilation.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/DepTokenizer.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Liveness.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Module.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Package.zig"
|
||||
|
||||
10
build.zig
10
build.zig
@@ -40,15 +40,11 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
docgen_exe.single_threaded = single_threaded;
|
||||
|
||||
const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
|
||||
const langref_out_path = fs.path.join(
|
||||
b.allocator,
|
||||
&[_][]const u8{ b.cache_root, "langref.html" },
|
||||
) catch unreachable;
|
||||
const langref_out_path = try b.cache_root.join(b.allocator, &.{"langref.html"});
|
||||
const docgen_cmd = docgen_exe.run();
|
||||
docgen_cmd.addArgs(&[_][]const u8{
|
||||
"--zig",
|
||||
rel_zig_exe,
|
||||
b.zig_exe,
|
||||
"doc" ++ fs.path.sep_str ++ "langref.html.in",
|
||||
langref_out_path,
|
||||
});
|
||||
@@ -215,7 +211,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
var code: u8 = undefined;
|
||||
const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
|
||||
"git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags",
|
||||
"git", "-C", b.build_root.path orelse ".", "describe", "--match", "*.*.*", "--tags",
|
||||
}, &code, .Ignore) catch {
|
||||
break :v version_string;
|
||||
};
|
||||
|
||||
@@ -43,13 +43,40 @@ pub fn main() !void {
|
||||
|
||||
const host = try std.zig.system.NativeTargetInfo.detect(.{});
|
||||
|
||||
const build_root_directory: std.Build.Cache.Directory = .{
|
||||
.path = build_root,
|
||||
.handle = try std.fs.cwd().openDir(build_root, .{}),
|
||||
};
|
||||
|
||||
const local_cache_directory: std.Build.Cache.Directory = .{
|
||||
.path = cache_root,
|
||||
.handle = try std.fs.cwd().makeOpenPath(cache_root, .{}),
|
||||
};
|
||||
|
||||
const global_cache_directory: std.Build.Cache.Directory = .{
|
||||
.path = global_cache_root,
|
||||
.handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
|
||||
};
|
||||
|
||||
var cache: std.Build.Cache = .{
|
||||
.gpa = allocator,
|
||||
.manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
|
||||
};
|
||||
cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
|
||||
cache.addPrefix(build_root_directory);
|
||||
cache.addPrefix(local_cache_directory);
|
||||
cache.addPrefix(global_cache_directory);
|
||||
|
||||
//cache.hash.addBytes(builtin.zig_version);
|
||||
|
||||
const builder = try std.Build.create(
|
||||
allocator,
|
||||
zig_exe,
|
||||
build_root,
|
||||
cache_root,
|
||||
global_cache_root,
|
||||
build_root_directory,
|
||||
local_cache_directory,
|
||||
global_cache_directory,
|
||||
host,
|
||||
&cache,
|
||||
);
|
||||
defer builder.destroy();
|
||||
|
||||
@@ -138,7 +165,7 @@ pub fn main() !void {
|
||||
return usageAndErr(builder, false, stderr_stream);
|
||||
};
|
||||
} else if (mem.eql(u8, arg, "--zig-lib-dir")) {
|
||||
builder.override_lib_dir = nextArg(args, &arg_idx) orelse {
|
||||
builder.zig_lib_dir = nextArg(args, &arg_idx) orelse {
|
||||
std.debug.print("Expected argument after --zig-lib-dir\n\n", .{});
|
||||
return usageAndErr(builder, false, stderr_stream);
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ const NativeTargetInfo = std.zig.system.NativeTargetInfo;
|
||||
const Sha256 = std.crypto.hash.sha2.Sha256;
|
||||
const Build = @This();
|
||||
|
||||
pub const Cache = @import("Build/Cache.zig");
|
||||
|
||||
/// deprecated: use `CompileStep`.
|
||||
pub const LibExeObjStep = CompileStep;
|
||||
/// deprecated: use `Build`.
|
||||
@@ -77,11 +79,12 @@ search_prefixes: ArrayList([]const u8),
|
||||
libc_file: ?[]const u8 = null,
|
||||
installed_files: ArrayList(InstalledFile),
|
||||
/// Path to the directory containing build.zig.
|
||||
build_root: []const u8,
|
||||
cache_root: []const u8,
|
||||
global_cache_root: []const u8,
|
||||
/// zig lib dir
|
||||
override_lib_dir: ?[]const u8,
|
||||
build_root: Cache.Directory,
|
||||
cache_root: Cache.Directory,
|
||||
global_cache_root: Cache.Directory,
|
||||
cache: *Cache,
|
||||
/// If non-null, overrides the default zig lib dir.
|
||||
zig_lib_dir: ?[]const u8,
|
||||
vcpkg_root: VcpkgRoot = .unattempted,
|
||||
pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,
|
||||
args: ?[][]const u8 = null,
|
||||
@@ -185,10 +188,11 @@ pub const DirList = struct {
|
||||
pub fn create(
|
||||
allocator: Allocator,
|
||||
zig_exe: []const u8,
|
||||
build_root: []const u8,
|
||||
cache_root: []const u8,
|
||||
global_cache_root: []const u8,
|
||||
build_root: Cache.Directory,
|
||||
cache_root: Cache.Directory,
|
||||
global_cache_root: Cache.Directory,
|
||||
host: NativeTargetInfo,
|
||||
cache: *Cache,
|
||||
) !*Build {
|
||||
const env_map = try allocator.create(EnvMap);
|
||||
env_map.* = try process.getEnvMap(allocator);
|
||||
@@ -197,8 +201,9 @@ pub fn create(
|
||||
self.* = Build{
|
||||
.zig_exe = zig_exe,
|
||||
.build_root = build_root,
|
||||
.cache_root = try fs.path.relative(allocator, build_root, cache_root),
|
||||
.cache_root = cache_root,
|
||||
.global_cache_root = global_cache_root,
|
||||
.cache = cache,
|
||||
.verbose = false,
|
||||
.verbose_link = false,
|
||||
.verbose_cc = false,
|
||||
@@ -230,7 +235,7 @@ pub fn create(
|
||||
.step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
|
||||
.description = "Remove build artifacts from prefix path",
|
||||
},
|
||||
.override_lib_dir = null,
|
||||
.zig_lib_dir = null,
|
||||
.install_path = undefined,
|
||||
.args = null,
|
||||
.host = host,
|
||||
@@ -245,7 +250,7 @@ pub fn create(
|
||||
fn createChild(
|
||||
parent: *Build,
|
||||
dep_name: []const u8,
|
||||
build_root: []const u8,
|
||||
build_root: Cache.Directory,
|
||||
args: anytype,
|
||||
) !*Build {
|
||||
const child = try createChildOnly(parent, dep_name, build_root);
|
||||
@@ -253,7 +258,7 @@ fn createChild(
|
||||
return child;
|
||||
}
|
||||
|
||||
fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: []const u8) !*Build {
|
||||
fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Directory) !*Build {
|
||||
const allocator = parent.allocator;
|
||||
const child = try allocator.create(Build);
|
||||
child.* = .{
|
||||
@@ -297,7 +302,8 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: []const u8)
|
||||
.build_root = build_root,
|
||||
.cache_root = parent.cache_root,
|
||||
.global_cache_root = parent.global_cache_root,
|
||||
.override_lib_dir = parent.override_lib_dir,
|
||||
.cache = parent.cache,
|
||||
.zig_lib_dir = parent.zig_lib_dir,
|
||||
.debug_log_scopes = parent.debug_log_scopes,
|
||||
.debug_compile_errors = parent.debug_compile_errors,
|
||||
.enable_darling = parent.enable_darling,
|
||||
@@ -348,7 +354,7 @@ fn applyArgs(b: *Build, args: anytype) !void {
|
||||
.used = false,
|
||||
});
|
||||
},
|
||||
.Enum => {
|
||||
.Enum, .EnumLiteral => {
|
||||
try b.user_input_options.put(field.name, .{
|
||||
.name = field.name,
|
||||
.value = .{ .scalar = @tagName(v) },
|
||||
@@ -379,7 +385,7 @@ fn applyArgs(b: *Build, args: anytype) !void {
|
||||
_ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch
|
||||
unreachable;
|
||||
|
||||
const install_prefix = b.pathJoin(&.{ b.cache_root, "i", &hash_basename });
|
||||
const install_prefix = try b.cache_root.join(b.allocator, &.{ "i", &hash_basename });
|
||||
b.resolveInstallPrefix(install_prefix, .{});
|
||||
}
|
||||
|
||||
@@ -396,7 +402,7 @@ pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list:
|
||||
self.install_path = self.pathJoin(&.{ dest_dir, self.install_prefix });
|
||||
} else {
|
||||
self.install_prefix = install_prefix orelse
|
||||
(self.pathJoin(&.{ self.build_root, "zig-out" }));
|
||||
(self.build_root.join(self.allocator, &.{"zig-out"}) catch @panic("unhandled error"));
|
||||
self.install_path = self.install_prefix;
|
||||
}
|
||||
|
||||
@@ -599,6 +605,28 @@ pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep {
|
||||
return run_step;
|
||||
}
|
||||
|
||||
/// Creates a `RunStep` with an executable built with `addExecutable`.
|
||||
/// Add command line arguments with methods of `RunStep`.
|
||||
pub fn addRunArtifact(b: *Build, exe: *CompileStep) *RunStep {
|
||||
assert(exe.kind == .exe or exe.kind == .test_exe);
|
||||
|
||||
// It doesn't have to be native. We catch that if you actually try to run it.
|
||||
// Consider that this is declarative; the run step may not be run unless a user
|
||||
// option is supplied.
|
||||
const run_step = RunStep.create(b, b.fmt("run {s}", .{exe.step.name}));
|
||||
run_step.addArtifactArg(exe);
|
||||
|
||||
if (exe.kind == .test_exe) {
|
||||
run_step.addArg(b.zig_exe);
|
||||
}
|
||||
|
||||
if (exe.vcpkg_bin_path) |path| {
|
||||
run_step.addPathDir(path);
|
||||
}
|
||||
|
||||
return run_step;
|
||||
}
|
||||
|
||||
/// Using the `values` provided, produces a C header file, possibly based on a
|
||||
/// template input file (e.g. config.h.in).
|
||||
/// When an input template file is provided, this function will fail the build
|
||||
@@ -674,8 +702,6 @@ pub fn addTranslateC(self: *Build, options: TranslateCStep.Options) *TranslateCS
|
||||
}
|
||||
|
||||
pub fn make(self: *Build, step_names: []const []const u8) !void {
|
||||
try self.makePath(self.cache_root);
|
||||
|
||||
var wanted_steps = ArrayList(*Step).init(self.allocator);
|
||||
defer wanted_steps.deinit();
|
||||
|
||||
@@ -1201,13 +1227,6 @@ pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn makePath(self: *Build, path: []const u8) !void {
|
||||
fs.cwd().makePath(self.pathFromRoot(path)) catch |err| {
|
||||
log.err("Unable to create path {s}: {s}", .{ path, @errorName(err) });
|
||||
return err;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn installArtifact(self: *Build, artifact: *CompileStep) void {
|
||||
self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
|
||||
}
|
||||
@@ -1322,8 +1341,8 @@ pub fn truncateFile(self: *Build, dest_path: []const u8) !void {
|
||||
src_file.close();
|
||||
}
|
||||
|
||||
pub fn pathFromRoot(self: *Build, rel_path: []const u8) []u8 {
|
||||
return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch @panic("OOM");
|
||||
pub fn pathFromRoot(b: *Build, p: []const u8) []u8 {
|
||||
return fs.path.resolve(b.allocator, &.{ b.build_root.path orelse ".", p }) catch @panic("OOM");
|
||||
}
|
||||
|
||||
pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 {
|
||||
@@ -1544,10 +1563,19 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
|
||||
fn dependencyInner(
|
||||
b: *Build,
|
||||
name: []const u8,
|
||||
build_root: []const u8,
|
||||
build_root_string: []const u8,
|
||||
comptime build_zig: type,
|
||||
args: anytype,
|
||||
) *Dependency {
|
||||
const build_root: std.Build.Cache.Directory = .{
|
||||
.path = build_root_string,
|
||||
.handle = std.fs.cwd().openDir(build_root_string, .{}) catch |err| {
|
||||
std.debug.print("unable to open '{s}': {s}\n", .{
|
||||
build_root_string, @errorName(err),
|
||||
});
|
||||
std.process.exit(1);
|
||||
},
|
||||
};
|
||||
const sub_builder = b.createChild(name, build_root, args) catch @panic("unhandled error");
|
||||
sub_builder.runBuild(build_zig) catch @panic("unhandled error");
|
||||
|
||||
@@ -1568,26 +1596,6 @@ pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void {
|
||||
}
|
||||
}
|
||||
|
||||
test "builder.findProgram compiles" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const host = try NativeTargetInfo.detect(.{});
|
||||
|
||||
const builder = try Build.create(
|
||||
arena.allocator(),
|
||||
"zig",
|
||||
"zig-cache",
|
||||
"zig-cache",
|
||||
"zig-cache",
|
||||
host,
|
||||
);
|
||||
defer builder.destroy();
|
||||
_ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
|
||||
}
|
||||
|
||||
pub const Module = struct {
|
||||
builder: *Build,
|
||||
/// This could either be a generated file, in which case the module
|
||||
@@ -1616,7 +1624,6 @@ pub const GeneratedFile = struct {
|
||||
};
|
||||
|
||||
/// A file source is a reference to an existing or future file.
|
||||
///
|
||||
pub const FileSource = union(enum) {
|
||||
/// A plain file path, relative to build root or absolute.
|
||||
path: []const u8,
|
||||
|
||||
@@ -2,6 +2,45 @@
|
||||
//! This is not a general-purpose cache. It is designed to be fast and simple,
|
||||
//! not to withstand attacks using specially-crafted input.
|
||||
|
||||
pub const Directory = struct {
|
||||
/// This field is redundant for operations that can act on the open directory handle
|
||||
/// directly, but it is needed when passing the directory to a child process.
|
||||
/// `null` means cwd.
|
||||
path: ?[]const u8,
|
||||
handle: std.fs.Dir,
|
||||
|
||||
pub fn join(self: Directory, allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (self.path) |p| {
|
||||
// TODO clean way to do this with only 1 allocation
|
||||
const part2 = try std.fs.path.join(allocator, paths);
|
||||
defer allocator.free(part2);
|
||||
return std.fs.path.join(allocator, &[_][]const u8{ p, part2 });
|
||||
} else {
|
||||
return std.fs.path.join(allocator, paths);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) ![:0]u8 {
|
||||
if (self.path) |p| {
|
||||
// TODO clean way to do this with only 1 allocation
|
||||
const part2 = try std.fs.path.join(allocator, paths);
|
||||
defer allocator.free(part2);
|
||||
return std.fs.path.joinZ(allocator, &[_][]const u8{ p, part2 });
|
||||
} else {
|
||||
return std.fs.path.joinZ(allocator, paths);
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not the handle should be closed, or the path should be freed
|
||||
/// is determined by usage, however this function is provided for convenience
|
||||
/// if it happens to be what the caller needs.
|
||||
pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
|
||||
self.handle.close();
|
||||
if (self.path) |p| gpa.free(p);
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
gpa: Allocator,
|
||||
manifest_dir: fs.Dir,
|
||||
hash: HashHelper = .{},
|
||||
@@ -14,9 +53,11 @@ mutex: std.Thread.Mutex = .{},
|
||||
/// are replaced with single-character indicators. This is not to save
|
||||
/// space but to eliminate absolute file paths. This improves portability
|
||||
/// and usefulness of the cache for advanced use cases.
|
||||
prefixes_buffer: [3]Compilation.Directory = undefined,
|
||||
prefixes_buffer: [4]Directory = undefined,
|
||||
prefixes_len: usize = 0,
|
||||
|
||||
pub const DepTokenizer = @import("Cache/DepTokenizer.zig");
|
||||
|
||||
const Cache = @This();
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
@@ -27,13 +68,9 @@ const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const fmt = std.fmt;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const log = std.log.scoped(.cache);
|
||||
|
||||
pub fn addPrefix(cache: *Cache, directory: Compilation.Directory) void {
|
||||
if (directory.path) |p| {
|
||||
log.debug("Cache.addPrefix {d} {s}", .{ cache.prefixes_len, p });
|
||||
}
|
||||
pub fn addPrefix(cache: *Cache, directory: Directory) void {
|
||||
cache.prefixes_buffer[cache.prefixes_len] = directory;
|
||||
cache.prefixes_len += 1;
|
||||
}
|
||||
@@ -49,7 +86,7 @@ pub fn obtain(cache: *Cache) Manifest {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prefixes(cache: *const Cache) []const Compilation.Directory {
|
||||
pub fn prefixes(cache: *const Cache) []const Directory {
|
||||
return cache.prefixes_buffer[0..cache.prefixes_len];
|
||||
}
|
||||
|
||||
@@ -80,8 +117,6 @@ fn findPrefixResolved(cache: *const Cache, resolved_path: []u8) !PrefixedPath {
|
||||
.prefix = @intCast(u8, i),
|
||||
.sub_path = sub_path,
|
||||
};
|
||||
} else {
|
||||
log.debug("'{s}' does not start with '{s}'", .{ resolved_path, p });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,8 +170,6 @@ pub const File = struct {
|
||||
pub const HashHelper = struct {
|
||||
hasher: Hasher = hasher_init,
|
||||
|
||||
const EmitLoc = Compilation.EmitLoc;
|
||||
|
||||
/// Record a slice of bytes as an dependency of the process being cached
|
||||
pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {
|
||||
hh.hasher.update(mem.asBytes(&bytes.len));
|
||||
@@ -148,15 +181,6 @@ pub const HashHelper = struct {
|
||||
hh.addBytes(optional_bytes orelse return);
|
||||
}
|
||||
|
||||
pub fn addEmitLoc(hh: *HashHelper, emit_loc: EmitLoc) void {
|
||||
hh.addBytes(emit_loc.basename);
|
||||
}
|
||||
|
||||
pub fn addOptionalEmitLoc(hh: *HashHelper, optional_emit_loc: ?EmitLoc) void {
|
||||
hh.add(optional_emit_loc != null);
|
||||
hh.addEmitLoc(optional_emit_loc orelse return);
|
||||
}
|
||||
|
||||
pub fn addListOfBytes(hh: *HashHelper, list_of_bytes: []const []const u8) void {
|
||||
hh.add(list_of_bytes.len);
|
||||
for (list_of_bytes) |bytes| hh.addBytes(bytes);
|
||||
@@ -290,10 +314,6 @@ pub const Manifest = struct {
|
||||
const prefixed_path = try self.cache.findPrefix(file_path);
|
||||
errdefer gpa.free(prefixed_path.sub_path);
|
||||
|
||||
log.debug("Manifest.addFile {s} -> {d} {s}", .{
|
||||
file_path, prefixed_path.prefix, prefixed_path.sub_path,
|
||||
});
|
||||
|
||||
self.files.addOneAssumeCapacity().* = .{
|
||||
.prefixed_path = prefixed_path,
|
||||
.contents = null,
|
||||
@@ -308,24 +328,6 @@ pub const Manifest = struct {
|
||||
return self.files.items.len - 1;
|
||||
}
|
||||
|
||||
pub fn hashCSource(self: *Manifest, c_source: Compilation.CSourceFile) !void {
|
||||
_ = try self.addFile(c_source.src_path, null);
|
||||
// Hash the extra flags, with special care to call addFile for file parameters.
|
||||
// TODO this logic can likely be improved by utilizing clang_options_data.zig.
|
||||
const file_args = [_][]const u8{"-include"};
|
||||
var arg_i: usize = 0;
|
||||
while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
|
||||
const arg = c_source.extra_flags[arg_i];
|
||||
self.hash.addBytes(arg);
|
||||
for (file_args) |file_arg| {
|
||||
if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
|
||||
arg_i += 1;
|
||||
_ = try self.addFile(c_source.extra_flags[arg_i], null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
|
||||
self.hash.add(optional_file_path != null);
|
||||
const file_path = optional_file_path orelse return;
|
||||
@@ -676,10 +678,6 @@ pub const Manifest = struct {
|
||||
const prefixed_path = try self.cache.findPrefix(file_path);
|
||||
errdefer gpa.free(prefixed_path.sub_path);
|
||||
|
||||
log.debug("Manifest.addFilePostFetch {s} -> {d} {s}", .{
|
||||
file_path, prefixed_path.prefix, prefixed_path.sub_path,
|
||||
});
|
||||
|
||||
const new_ch_file = try self.files.addOne(gpa);
|
||||
new_ch_file.* = .{
|
||||
.prefixed_path = prefixed_path,
|
||||
@@ -706,10 +704,6 @@ pub const Manifest = struct {
|
||||
const prefixed_path = try self.cache.findPrefix(file_path);
|
||||
errdefer gpa.free(prefixed_path.sub_path);
|
||||
|
||||
log.debug("Manifest.addFilePost {s} -> {d} {s}", .{
|
||||
file_path, prefixed_path.prefix, prefixed_path.sub_path,
|
||||
});
|
||||
|
||||
const new_ch_file = try self.files.addOne(gpa);
|
||||
new_ch_file.* = .{
|
||||
.prefixed_path = prefixed_path,
|
||||
@@ -737,15 +731,9 @@ pub const Manifest = struct {
|
||||
const ch_file = try self.files.addOne(gpa);
|
||||
errdefer self.files.shrinkRetainingCapacity(self.files.items.len - 1);
|
||||
|
||||
log.debug("Manifest.addFilePostContents resolved_path={s}", .{resolved_path});
|
||||
|
||||
const prefixed_path = try self.cache.findPrefixResolved(resolved_path);
|
||||
errdefer gpa.free(prefixed_path.sub_path);
|
||||
|
||||
log.debug("Manifest.addFilePostContents -> {d} {s}", .{
|
||||
prefixed_path.prefix, prefixed_path.sub_path,
|
||||
});
|
||||
|
||||
ch_file.* = .{
|
||||
.prefixed_path = prefixed_path,
|
||||
.max_file_size = null,
|
||||
@@ -778,7 +766,7 @@ pub const Manifest = struct {
|
||||
var error_buf = std.ArrayList(u8).init(self.cache.gpa);
|
||||
defer error_buf.deinit();
|
||||
|
||||
var it: @import("DepTokenizer.zig") = .{ .bytes = dep_file_contents };
|
||||
var it: DepTokenizer = .{ .bytes = dep_file_contents };
|
||||
|
||||
// Skip first token: target.
|
||||
switch (it.next() orelse return) { // Empty dep file OK.
|
||||
@@ -83,7 +83,7 @@ max_memory: ?u64 = null,
|
||||
shared_memory: bool = false,
|
||||
global_base: ?u64 = null,
|
||||
c_std: std.Build.CStd,
|
||||
override_lib_dir: ?[]const u8,
|
||||
zig_lib_dir: ?[]const u8,
|
||||
main_pkg_path: ?[]const u8,
|
||||
exec_cmd_args: ?[]const ?[]const u8,
|
||||
name_prefix: []const u8,
|
||||
@@ -344,7 +344,7 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep {
|
||||
.installed_headers = ArrayList(*Step).init(builder.allocator),
|
||||
.object_src = undefined,
|
||||
.c_std = std.Build.CStd.C99,
|
||||
.override_lib_dir = null,
|
||||
.zig_lib_dir = null,
|
||||
.main_pkg_path = null,
|
||||
.exec_cmd_args = null,
|
||||
.name_prefix = "",
|
||||
@@ -506,26 +506,11 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {
|
||||
a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
|
||||
}
|
||||
|
||||
/// Creates a `RunStep` with an executable built with `addExecutable`.
|
||||
/// Add command line arguments with `addArg`.
|
||||
/// Deprecated: use `std.Build.addRunArtifact`
|
||||
/// This function will run in the context of the package that created the executable,
|
||||
/// which is undesirable when running an executable provided by a dependency package.
|
||||
pub fn run(exe: *CompileStep) *RunStep {
|
||||
assert(exe.kind == .exe or exe.kind == .test_exe);
|
||||
|
||||
// It doesn't have to be native. We catch that if you actually try to run it.
|
||||
// Consider that this is declarative; the run step may not be run unless a user
|
||||
// option is supplied.
|
||||
const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}));
|
||||
run_step.addArtifactArg(exe);
|
||||
|
||||
if (exe.kind == .test_exe) {
|
||||
run_step.addArg(exe.builder.zig_exe);
|
||||
}
|
||||
|
||||
if (exe.vcpkg_bin_path) |path| {
|
||||
run_step.addPathDir(path);
|
||||
}
|
||||
|
||||
return run_step;
|
||||
return exe.builder.addRunArtifact(exe);
|
||||
}
|
||||
|
||||
/// Creates an `EmulatableRunStep` with an executable built with `addExecutable`.
|
||||
@@ -872,7 +857,7 @@ pub fn setVerboseCC(self: *CompileStep, value: bool) void {
|
||||
}
|
||||
|
||||
pub fn overrideZigLibDir(self: *CompileStep, dir_path: []const u8) void {
|
||||
self.override_lib_dir = self.builder.dupePath(dir_path);
|
||||
self.zig_lib_dir = self.builder.dupePath(dir_path);
|
||||
}
|
||||
|
||||
pub fn setMainPkgPath(self: *CompileStep, dir_path: []const u8) void {
|
||||
@@ -1365,10 +1350,10 @@ fn make(step: *Step) !void {
|
||||
}
|
||||
|
||||
try zig_args.append("--cache-dir");
|
||||
try zig_args.append(builder.pathFromRoot(builder.cache_root));
|
||||
try zig_args.append(builder.cache_root.path orelse ".");
|
||||
|
||||
try zig_args.append("--global-cache-dir");
|
||||
try zig_args.append(builder.pathFromRoot(builder.global_cache_root));
|
||||
try zig_args.append(builder.global_cache_root.path orelse ".");
|
||||
|
||||
try zig_args.append("--name");
|
||||
try zig_args.append(self.name);
|
||||
@@ -1718,12 +1703,12 @@ fn make(step: *Step) !void {
|
||||
try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
|
||||
try addFlag(&zig_args, "build-id", self.build_id);
|
||||
|
||||
if (self.override_lib_dir) |dir| {
|
||||
if (self.zig_lib_dir) |dir| {
|
||||
try zig_args.append("--zig-lib-dir");
|
||||
try zig_args.append(builder.pathFromRoot(dir));
|
||||
} else if (builder.override_lib_dir) |dir| {
|
||||
} else if (builder.zig_lib_dir) |dir| {
|
||||
try zig_args.append("--zig-lib-dir");
|
||||
try zig_args.append(builder.pathFromRoot(dir));
|
||||
try zig_args.append(dir);
|
||||
}
|
||||
|
||||
if (self.main_pkg_path) |dir| {
|
||||
@@ -1760,23 +1745,15 @@ fn make(step: *Step) !void {
|
||||
args_length += arg.len + 1; // +1 to account for null terminator
|
||||
}
|
||||
if (args_length >= 30 * 1024) {
|
||||
const args_dir = try fs.path.join(
|
||||
builder.allocator,
|
||||
&[_][]const u8{ builder.pathFromRoot("zig-cache"), "args" },
|
||||
);
|
||||
try std.fs.cwd().makePath(args_dir);
|
||||
|
||||
var args_arena = std.heap.ArenaAllocator.init(builder.allocator);
|
||||
defer args_arena.deinit();
|
||||
try builder.cache_root.handle.makePath("args");
|
||||
|
||||
const args_to_escape = zig_args.items[2..];
|
||||
var escaped_args = try ArrayList([]const u8).initCapacity(args_arena.allocator(), args_to_escape.len);
|
||||
|
||||
var escaped_args = try ArrayList([]const u8).initCapacity(builder.allocator, args_to_escape.len);
|
||||
arg_blk: for (args_to_escape) |arg| {
|
||||
for (arg) |c, arg_idx| {
|
||||
if (c == '\\' or c == '"') {
|
||||
// Slow path for arguments that need to be escaped. We'll need to allocate and copy
|
||||
var escaped = try ArrayList(u8).initCapacity(args_arena.allocator(), arg.len + 1);
|
||||
var escaped = try ArrayList(u8).initCapacity(builder.allocator, arg.len + 1);
|
||||
const writer = escaped.writer();
|
||||
try writer.writeAll(arg[0..arg_idx]);
|
||||
for (arg[arg_idx..]) |to_escape| {
|
||||
@@ -1804,11 +1781,16 @@ fn make(step: *Step) !void {
|
||||
.{std.fmt.fmtSliceHexLower(&args_hash)},
|
||||
);
|
||||
|
||||
const args_file = try fs.path.join(builder.allocator, &[_][]const u8{ args_dir, args_hex_hash[0..] });
|
||||
try std.fs.cwd().writeFile(args_file, args);
|
||||
const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash;
|
||||
try builder.cache_root.handle.writeFile(args_file, args);
|
||||
|
||||
const resolved_args_file = try mem.concat(builder.allocator, u8, &.{
|
||||
"@",
|
||||
try builder.cache_root.join(builder.allocator, &.{args_file}),
|
||||
});
|
||||
|
||||
zig_args.shrinkRetainingCapacity(2);
|
||||
try zig_args.append(try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "@", args_file }));
|
||||
try zig_args.append(resolved_args_file);
|
||||
}
|
||||
|
||||
const output_dir_nl = try builder.execFromStep(zig_args.items, &self.step);
|
||||
|
||||
@@ -13,11 +13,13 @@ pub const Style = union(enum) {
|
||||
cmake: std.Build.FileSource,
|
||||
/// Instead of starting with an input file, start with nothing.
|
||||
blank,
|
||||
/// Start with nothing, like blank, and output a nasm .asm file.
|
||||
nasm,
|
||||
|
||||
pub fn getFileSource(style: Style) ?std.Build.FileSource {
|
||||
switch (style) {
|
||||
.autoconf, .cmake => |s| return s,
|
||||
.blank => return null,
|
||||
.blank, .nasm => return null,
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -84,6 +86,10 @@ pub fn addValues(self: *ConfigHeaderStep, values: anytype) void {
|
||||
return addValuesInner(self, values) catch @panic("OOM");
|
||||
}
|
||||
|
||||
pub fn getFileSource(self: *ConfigHeaderStep) std.Build.FileSource {
|
||||
return .{ .generated = &self.output_file };
|
||||
}
|
||||
|
||||
fn addValuesInner(self: *ConfigHeaderStep, values: anytype) !void {
|
||||
inline for (@typeInfo(@TypeOf(values)).Struct.fields) |field| {
|
||||
try putValue(self, field.name, field.type, @field(values, field.name));
|
||||
@@ -125,6 +131,12 @@ fn putValue(self: *ConfigHeaderStep, field_name: []const u8, comptime T: type, v
|
||||
return;
|
||||
}
|
||||
},
|
||||
.Int => {
|
||||
if (ptr.size == .Slice and ptr.child == u8) {
|
||||
try self.values.put(field_name, .{ .string = v });
|
||||
return;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
@@ -158,22 +170,31 @@ fn make(step: *Step) !void {
|
||||
var output = std.ArrayList(u8).init(gpa);
|
||||
defer output.deinit();
|
||||
|
||||
try output.appendSlice("/* This file was generated by ConfigHeaderStep using the Zig Build System. */\n");
|
||||
const header_text = "This file was generated by ConfigHeaderStep using the Zig Build System.";
|
||||
const c_generated_line = "/* " ++ header_text ++ " */\n";
|
||||
const asm_generated_line = "; " ++ header_text ++ "\n";
|
||||
|
||||
switch (self.style) {
|
||||
.autoconf => |file_source| {
|
||||
try output.appendSlice(c_generated_line);
|
||||
const src_path = file_source.getPath(self.builder);
|
||||
const contents = try std.fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);
|
||||
try render_autoconf(contents, &output, self.values, src_path);
|
||||
},
|
||||
.cmake => |file_source| {
|
||||
try output.appendSlice(c_generated_line);
|
||||
const src_path = file_source.getPath(self.builder);
|
||||
const contents = try std.fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);
|
||||
try render_cmake(contents, &output, self.values, src_path);
|
||||
},
|
||||
.blank => {
|
||||
try output.appendSlice(c_generated_line);
|
||||
try render_blank(&output, self.values, self.include_path);
|
||||
},
|
||||
.nasm => {
|
||||
try output.appendSlice(asm_generated_line);
|
||||
try render_nasm(&output, self.values);
|
||||
},
|
||||
}
|
||||
|
||||
hash.update(output.items);
|
||||
@@ -187,9 +208,7 @@ fn make(step: *Step) !void {
|
||||
.{std.fmt.fmtSliceHexLower(&digest)},
|
||||
) catch unreachable;
|
||||
|
||||
const output_dir = try std.fs.path.join(gpa, &[_][]const u8{
|
||||
self.builder.cache_root, "o", &hash_basename,
|
||||
});
|
||||
const output_dir = try self.builder.cache_root.join(gpa, &.{ "o", &hash_basename });
|
||||
|
||||
// If output_path has directory parts, deal with them. Example:
|
||||
// output_dir is zig-cache/o/HASH
|
||||
@@ -247,7 +266,7 @@ fn render_autoconf(
|
||||
any_errors = true;
|
||||
continue;
|
||||
};
|
||||
try renderValue(output, name, kv.value);
|
||||
try renderValueC(output, name, kv.value);
|
||||
}
|
||||
|
||||
for (values_copy.keys()) |name| {
|
||||
@@ -298,7 +317,7 @@ fn render_cmake(
|
||||
any_errors = true;
|
||||
continue;
|
||||
};
|
||||
try renderValue(output, name, kv.value);
|
||||
try renderValueC(output, name, kv.value);
|
||||
}
|
||||
|
||||
for (values_copy.keys()) |name| {
|
||||
@@ -332,7 +351,7 @@ fn render_blank(
|
||||
|
||||
const values = defines.values();
|
||||
for (defines.keys()) |name, i| {
|
||||
try renderValue(output, name, values[i]);
|
||||
try renderValueC(output, name, values[i]);
|
||||
}
|
||||
|
||||
try output.appendSlice("#endif /* ");
|
||||
@@ -340,7 +359,14 @@ fn render_blank(
|
||||
try output.appendSlice(" */\n");
|
||||
}
|
||||
|
||||
fn renderValue(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
|
||||
fn render_nasm(output: *std.ArrayList(u8), defines: std.StringArrayHashMap(Value)) !void {
|
||||
const values = defines.values();
|
||||
for (defines.keys()) |name, i| {
|
||||
try renderValueNasm(output, name, values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fn renderValueC(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
|
||||
switch (value) {
|
||||
.undef => {
|
||||
try output.appendSlice("/* #undef ");
|
||||
@@ -370,3 +396,33 @@ fn renderValue(output: *std.ArrayList(u8), name: []const u8, value: Value) !void
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
|
||||
switch (value) {
|
||||
.undef => {
|
||||
try output.appendSlice("; %undef ");
|
||||
try output.appendSlice(name);
|
||||
try output.appendSlice("\n");
|
||||
},
|
||||
.defined => {
|
||||
try output.appendSlice("%define ");
|
||||
try output.appendSlice(name);
|
||||
try output.appendSlice("\n");
|
||||
},
|
||||
.boolean => |b| {
|
||||
try output.appendSlice("%define ");
|
||||
try output.appendSlice(name);
|
||||
try output.appendSlice(if (b) " 1\n" else " 0\n");
|
||||
},
|
||||
.int => |i| {
|
||||
try output.writer().print("%define {s} {d}\n", .{ name, i });
|
||||
},
|
||||
.ident => |ident| {
|
||||
try output.writer().print("%define {s} {s}\n", .{ name, ident });
|
||||
},
|
||||
.string => |string| {
|
||||
// TODO: use nasm-specific escaping instead of zig string literals
|
||||
try output.writer().print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) });
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,26 +234,20 @@ fn make(step: *Step) !void {
|
||||
);
|
||||
}
|
||||
|
||||
const options_directory = self.builder.pathFromRoot(
|
||||
try fs.path.join(
|
||||
self.builder.allocator,
|
||||
&[_][]const u8{ self.builder.cache_root, "options" },
|
||||
),
|
||||
);
|
||||
var options_dir = try self.builder.cache_root.handle.makeOpenPath("options", .{});
|
||||
defer options_dir.close();
|
||||
|
||||
try fs.cwd().makePath(options_directory);
|
||||
const basename = self.hashContentsToFileName();
|
||||
|
||||
const options_file = try fs.path.join(
|
||||
self.builder.allocator,
|
||||
&[_][]const u8{ options_directory, &self.hashContentsToFileName() },
|
||||
);
|
||||
try options_dir.writeFile(&basename, self.contents.items);
|
||||
|
||||
try fs.cwd().writeFile(options_file, self.contents.items);
|
||||
|
||||
self.generated_file.path = options_file;
|
||||
self.generated_file.path = try self.builder.cache_root.join(self.builder.allocator, &.{
|
||||
"options", &basename,
|
||||
});
|
||||
}
|
||||
|
||||
fn hashContentsToFileName(self: *OptionsStep) [64]u8 {
|
||||
// TODO update to use the cache system instead of this
|
||||
// This implementation is copied from `WriteFileStep.make`
|
||||
|
||||
var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
|
||||
@@ -289,13 +283,19 @@ test "OptionsStep" {
|
||||
|
||||
const host = try std.zig.system.NativeTargetInfo.detect(.{});
|
||||
|
||||
var cache: std.Build.Cache = .{
|
||||
.gpa = arena.allocator(),
|
||||
.manifest_dir = std.fs.cwd(),
|
||||
};
|
||||
|
||||
var builder = try std.Build.create(
|
||||
arena.allocator(),
|
||||
"test",
|
||||
"test",
|
||||
"test",
|
||||
"test",
|
||||
.{ .path = "test", .handle = std.fs.cwd() },
|
||||
.{ .path = "test", .handle = std.fs.cwd() },
|
||||
.{ .path = "test", .handle = std.fs.cwd() },
|
||||
host,
|
||||
&cache,
|
||||
);
|
||||
defer builder.destroy();
|
||||
|
||||
|
||||
@@ -39,6 +39,14 @@ expected_exit_code: ?u8 = 0,
|
||||
|
||||
/// Print the command before running it
|
||||
print: bool,
|
||||
/// Controls whether execution is skipped if the output file is up-to-date.
|
||||
/// The default is to always run if there is no output file, and to skip
|
||||
/// running if all output files are up-to-date.
|
||||
condition: enum { output_outdated, always } = .output_outdated,
|
||||
|
||||
/// Additional file paths relative to build.zig that, when modified, indicate
|
||||
/// that the RunStep should be re-executed.
|
||||
extra_file_dependencies: []const []const u8 = &.{},
|
||||
|
||||
pub const StdIoAction = union(enum) {
|
||||
inherit,
|
||||
@@ -51,6 +59,12 @@ pub const Arg = union(enum) {
|
||||
artifact: *CompileStep,
|
||||
file_source: std.Build.FileSource,
|
||||
bytes: []u8,
|
||||
output: Output,
|
||||
|
||||
pub const Output = struct {
|
||||
generated_file: *std.Build.GeneratedFile,
|
||||
basename: []const u8,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn create(builder: *std.Build, name: []const u8) *RunStep {
|
||||
@@ -71,6 +85,20 @@ pub fn addArtifactArg(self: *RunStep, artifact: *CompileStep) void {
|
||||
self.step.dependOn(&artifact.step);
|
||||
}
|
||||
|
||||
/// This provides file path as a command line argument to the command being
|
||||
/// run, and returns a FileSource which can be used as inputs to other APIs
|
||||
/// throughout the build system.
|
||||
pub fn addOutputFileArg(rs: *RunStep, basename: []const u8) std.Build.FileSource {
|
||||
const generated_file = rs.builder.allocator.create(std.Build.GeneratedFile) catch @panic("OOM");
|
||||
generated_file.* = .{ .step = &rs.step };
|
||||
rs.argv.append(.{ .output = .{
|
||||
.generated_file = generated_file,
|
||||
.basename = rs.builder.dupe(basename),
|
||||
} }) catch @panic("OOM");
|
||||
|
||||
return .{ .generated = generated_file };
|
||||
}
|
||||
|
||||
pub fn addFileSourceArg(self: *RunStep, file_source: std.Build.FileSource) void {
|
||||
self.argv.append(Arg{
|
||||
.file_source = file_source.dupe(self.builder),
|
||||
@@ -159,22 +187,102 @@ fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo {
|
||||
};
|
||||
}
|
||||
|
||||
fn needOutputCheck(self: RunStep) bool {
|
||||
if (self.extra_file_dependencies.len > 0) return true;
|
||||
|
||||
for (self.argv.items) |arg| switch (arg) {
|
||||
.output => return true,
|
||||
else => continue,
|
||||
};
|
||||
|
||||
return switch (self.condition) {
|
||||
.always => false,
|
||||
.output_outdated => true,
|
||||
};
|
||||
}
|
||||
|
||||
fn make(step: *Step) !void {
|
||||
const self = @fieldParentPtr(RunStep, "step", step);
|
||||
const need_output_check = self.needOutputCheck();
|
||||
|
||||
var argv_list = ArrayList([]const u8).init(self.builder.allocator);
|
||||
var output_placeholders = ArrayList(struct {
|
||||
index: usize,
|
||||
output: Arg.Output,
|
||||
}).init(self.builder.allocator);
|
||||
|
||||
var man = self.builder.cache.obtain();
|
||||
defer man.deinit();
|
||||
|
||||
for (self.argv.items) |arg| {
|
||||
switch (arg) {
|
||||
.bytes => |bytes| try argv_list.append(bytes),
|
||||
.file_source => |file| try argv_list.append(file.getPath(self.builder)),
|
||||
.bytes => |bytes| {
|
||||
try argv_list.append(bytes);
|
||||
man.hash.addBytes(bytes);
|
||||
},
|
||||
.file_source => |file| {
|
||||
const file_path = file.getPath(self.builder);
|
||||
try argv_list.append(file_path);
|
||||
_ = try man.addFile(file_path, null);
|
||||
},
|
||||
.artifact => |artifact| {
|
||||
if (artifact.target.isWindows()) {
|
||||
// On Windows we don't have rpaths so we have to add .dll search paths to PATH
|
||||
self.addPathForDynLibs(artifact);
|
||||
}
|
||||
const executable_path = artifact.installed_path orelse artifact.getOutputSource().getPath(self.builder);
|
||||
try argv_list.append(executable_path);
|
||||
const file_path = artifact.installed_path orelse
|
||||
artifact.getOutputSource().getPath(self.builder);
|
||||
|
||||
try argv_list.append(file_path);
|
||||
|
||||
_ = try man.addFile(file_path, null);
|
||||
},
|
||||
.output => |output| {
|
||||
man.hash.addBytes(output.basename);
|
||||
// Add a placeholder into the argument list because we need the
|
||||
// manifest hash to be updated with all arguments before the
|
||||
// object directory is computed.
|
||||
try argv_list.append("");
|
||||
try output_placeholders.append(.{
|
||||
.index = argv_list.items.len - 1,
|
||||
.output = output,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (need_output_check) {
|
||||
for (self.extra_file_dependencies) |file_path| {
|
||||
_ = try man.addFile(self.builder.pathFromRoot(file_path), null);
|
||||
}
|
||||
|
||||
if (man.hit() catch |err| failWithCacheError(man, err)) {
|
||||
// cache hit, skip running command
|
||||
const digest = man.final();
|
||||
for (output_placeholders.items) |placeholder| {
|
||||
placeholder.output.generated_file.path = try self.builder.cache_root.join(
|
||||
self.builder.allocator,
|
||||
&.{ "o", &digest, placeholder.output.basename },
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const digest = man.final();
|
||||
|
||||
for (output_placeholders.items) |placeholder| {
|
||||
const output_path = try self.builder.cache_root.join(
|
||||
self.builder.allocator,
|
||||
&.{ "o", &digest, placeholder.output.basename },
|
||||
);
|
||||
const output_dir = fs.path.dirname(output_path).?;
|
||||
fs.cwd().makePath(output_dir) catch |err| {
|
||||
std.debug.print("unable to make path {s}: {s}\n", .{ output_dir, @errorName(err) });
|
||||
return err;
|
||||
};
|
||||
|
||||
placeholder.output.generated_file.path = output_path;
|
||||
argv_list.items[placeholder.index] = output_path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +297,10 @@ fn make(step: *Step) !void {
|
||||
self.cwd,
|
||||
self.print,
|
||||
);
|
||||
|
||||
if (need_output_check) {
|
||||
try man.writeManifest();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn runCommand(
|
||||
@@ -202,11 +314,13 @@ pub fn runCommand(
|
||||
maybe_cwd: ?[]const u8,
|
||||
print: bool,
|
||||
) !void {
|
||||
const cwd = if (maybe_cwd) |cwd| builder.pathFromRoot(cwd) else builder.build_root;
|
||||
const cwd = if (maybe_cwd) |cwd| builder.pathFromRoot(cwd) else builder.build_root.path;
|
||||
|
||||
if (!std.process.can_spawn) {
|
||||
const cmd = try std.mem.join(builder.allocator, " ", argv);
|
||||
std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
|
||||
std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
|
||||
@tagName(builtin.os.tag), cmd,
|
||||
});
|
||||
builder.allocator.free(cmd);
|
||||
return ExecError.ExecNotSupported;
|
||||
}
|
||||
@@ -347,6 +461,19 @@ pub fn runCommand(
|
||||
}
|
||||
}
|
||||
|
||||
fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
|
||||
const i = man.failed_file_index orelse failWithSimpleError(err);
|
||||
const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
|
||||
const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
|
||||
std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
fn failWithSimpleError(err: anyerror) noreturn {
|
||||
std.debug.print("{s}\n", .{@errorName(err)});
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
|
||||
if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd});
|
||||
for (argv) |arg| {
|
||||
|
||||
@@ -85,8 +85,8 @@ fn make(step: *Step) !void {
|
||||
.{std.fmt.fmtSliceHexLower(&digest)},
|
||||
) catch unreachable;
|
||||
|
||||
const output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{
|
||||
self.builder.cache_root, "o", &hash_basename,
|
||||
const output_dir = try self.builder.cache_root.join(self.builder.allocator, &.{
|
||||
"o", &hash_basename,
|
||||
});
|
||||
var dir = fs.cwd().makeOpenPath(output_dir, .{}) catch |err| {
|
||||
std.debug.print("unable to make path {s}: {s}\n", .{ output_dir, @errorName(err) });
|
||||
|
||||
@@ -26,7 +26,7 @@ const wasi_libc = @import("wasi_libc.zig");
|
||||
const fatal = @import("main.zig").fatal;
|
||||
const clangMain = @import("main.zig").clangMain;
|
||||
const Module = @import("Module.zig");
|
||||
const Cache = @import("Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const translate_c = @import("translate_c.zig");
|
||||
const clang = @import("clang.zig");
|
||||
const c_codegen = @import("codegen/c.zig");
|
||||
@@ -807,44 +807,7 @@ pub const AllErrors = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Directory = struct {
|
||||
/// This field is redundant for operations that can act on the open directory handle
|
||||
/// directly, but it is needed when passing the directory to a child process.
|
||||
/// `null` means cwd.
|
||||
path: ?[]const u8,
|
||||
handle: std.fs.Dir,
|
||||
|
||||
pub fn join(self: Directory, allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (self.path) |p| {
|
||||
// TODO clean way to do this with only 1 allocation
|
||||
const part2 = try std.fs.path.join(allocator, paths);
|
||||
defer allocator.free(part2);
|
||||
return std.fs.path.join(allocator, &[_][]const u8{ p, part2 });
|
||||
} else {
|
||||
return std.fs.path.join(allocator, paths);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) ![:0]u8 {
|
||||
if (self.path) |p| {
|
||||
// TODO clean way to do this with only 1 allocation
|
||||
const part2 = try std.fs.path.join(allocator, paths);
|
||||
defer allocator.free(part2);
|
||||
return std.fs.path.joinZ(allocator, &[_][]const u8{ p, part2 });
|
||||
} else {
|
||||
return std.fs.path.joinZ(allocator, paths);
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not the handle should be closed, or the path should be freed
|
||||
/// is determined by usage, however this function is provided for convenience
|
||||
/// if it happens to be what the caller needs.
|
||||
pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
|
||||
self.handle.close();
|
||||
if (self.path) |p| gpa.free(p);
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
pub const Directory = Cache.Directory;
|
||||
|
||||
pub const EmitLoc = struct {
|
||||
/// If this is `null` it means the file will be output to the cache directory.
|
||||
@@ -854,6 +817,35 @@ pub const EmitLoc = struct {
|
||||
basename: []const u8,
|
||||
};
|
||||
|
||||
pub const cache_helpers = struct {
|
||||
pub fn addEmitLoc(hh: *Cache.HashHelper, emit_loc: EmitLoc) void {
|
||||
hh.addBytes(emit_loc.basename);
|
||||
}
|
||||
|
||||
pub fn addOptionalEmitLoc(hh: *Cache.HashHelper, optional_emit_loc: ?EmitLoc) void {
|
||||
hh.add(optional_emit_loc != null);
|
||||
addEmitLoc(hh, optional_emit_loc orelse return);
|
||||
}
|
||||
|
||||
pub fn hashCSource(self: *Cache.Manifest, c_source: Compilation.CSourceFile) !void {
|
||||
_ = try self.addFile(c_source.src_path, null);
|
||||
// Hash the extra flags, with special care to call addFile for file parameters.
|
||||
// TODO this logic can likely be improved by utilizing clang_options_data.zig.
|
||||
const file_args = [_][]const u8{"-include"};
|
||||
var arg_i: usize = 0;
|
||||
while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
|
||||
const arg = c_source.extra_flags[arg_i];
|
||||
self.hash.addBytes(arg);
|
||||
for (file_args) |file_arg| {
|
||||
if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
|
||||
arg_i += 1;
|
||||
_ = try self.addFile(c_source.extra_flags[arg_i], null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const ClangPreprocessorMode = enum {
|
||||
no,
|
||||
/// This means we are doing `zig cc -E -o <path>`.
|
||||
@@ -1523,8 +1515,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
||||
cache.hash.add(link_libunwind);
|
||||
cache.hash.add(options.output_mode);
|
||||
cache.hash.add(options.machine_code_model);
|
||||
cache.hash.addOptionalEmitLoc(options.emit_bin);
|
||||
cache.hash.addOptionalEmitLoc(options.emit_implib);
|
||||
cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin);
|
||||
cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib);
|
||||
cache.hash.addBytes(options.root_name);
|
||||
if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model);
|
||||
// TODO audit this and make sure everything is in it
|
||||
@@ -2638,11 +2630,11 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
|
||||
man.hash.addListOfBytes(key.src.extra_flags);
|
||||
}
|
||||
|
||||
man.hash.addOptionalEmitLoc(comp.emit_asm);
|
||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
|
||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
|
||||
man.hash.addOptionalEmitLoc(comp.emit_analysis);
|
||||
man.hash.addOptionalEmitLoc(comp.emit_docs);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_analysis);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_docs);
|
||||
|
||||
man.hash.addListOfBytes(comp.clang_argv);
|
||||
|
||||
@@ -3961,11 +3953,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
|
||||
defer man.deinit();
|
||||
|
||||
man.hash.add(comp.clang_preprocessor_mode);
|
||||
man.hash.addOptionalEmitLoc(comp.emit_asm);
|
||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
|
||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
|
||||
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
|
||||
|
||||
try man.hashCSource(c_object.src);
|
||||
try cache_helpers.hashCSource(&man, c_object.src);
|
||||
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
|
||||
defer arena_allocator.deinit();
|
||||
|
||||
@@ -16,7 +16,7 @@ const Ast = std.zig.Ast;
|
||||
|
||||
const Module = @This();
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const Cache = @import("Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const Value = @import("value.zig").Value;
|
||||
const Type = @import("type.zig").Type;
|
||||
const TypedValue = @import("TypedValue.zig");
|
||||
|
||||
@@ -13,7 +13,7 @@ const Compilation = @import("Compilation.zig");
|
||||
const Module = @import("Module.zig");
|
||||
const ThreadPool = @import("ThreadPool.zig");
|
||||
const WaitGroup = @import("WaitGroup.zig");
|
||||
const Cache = @import("Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const build_options = @import("build_options");
|
||||
const Manifest = @import("Manifest.zig");
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const target_util = @import("target.zig");
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const build_options = @import("build_options");
|
||||
const trace = @import("tracy.zig").trace;
|
||||
const Cache = @import("Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const Package = @import("Package.zig");
|
||||
|
||||
pub const Lib = struct {
|
||||
|
||||
@@ -10,7 +10,7 @@ const wasi_libc = @import("wasi_libc.zig");
|
||||
|
||||
const Air = @import("Air.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Cache = @import("Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
const Liveness = @import("Liveness.zig");
|
||||
|
||||
@@ -5,6 +5,7 @@ const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const mem = std.mem;
|
||||
const Cache = std.Build.Cache;
|
||||
|
||||
const mingw = @import("../../mingw.zig");
|
||||
const link = @import("../../link.zig");
|
||||
@@ -13,7 +14,6 @@ const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
const Cache = @import("../../Cache.zig");
|
||||
const Coff = @import("../Coff.zig");
|
||||
const Compilation = @import("../../Compilation.zig");
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ const trace = @import("../tracy.zig").trace;
|
||||
const Air = @import("../Air.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
pub const Atom = @import("Elf/Atom.zig");
|
||||
const Cache = @import("../Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const Dwarf = @import("Dwarf.zig");
|
||||
const File = link.File;
|
||||
|
||||
@@ -28,7 +28,7 @@ const Air = @import("../Air.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const Archive = @import("MachO/Archive.zig");
|
||||
pub const Atom = @import("MachO/Atom.zig");
|
||||
const Cache = @import("../Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const CodeSignature = @import("MachO/CodeSignature.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const Dwarf = File.Dwarf;
|
||||
|
||||
@@ -20,7 +20,7 @@ const trace = @import("../../tracy.zig").trace;
|
||||
const Allocator = mem.Allocator;
|
||||
const Archive = @import("Archive.zig");
|
||||
const Atom = @import("ZldAtom.zig");
|
||||
const Cache = @import("../../Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const CodeSignature = @import("CodeSignature.zig");
|
||||
const Compilation = @import("../../Compilation.zig");
|
||||
const DwarfInfo = @import("DwarfInfo.zig");
|
||||
|
||||
@@ -20,7 +20,7 @@ const lldMain = @import("../main.zig").lldMain;
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const build_options = @import("build_options");
|
||||
const wasi_libc = @import("../wasi_libc.zig");
|
||||
const Cache = @import("../Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const Type = @import("../type.zig").Type;
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
||||
|
||||
@@ -20,7 +20,7 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
const wasi_libc = @import("wasi_libc.zig");
|
||||
const translate_c = @import("translate_c.zig");
|
||||
const clang = @import("clang.zig");
|
||||
const Cache = @import("Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const target_util = @import("target.zig");
|
||||
const ThreadPool = @import("ThreadPool.zig");
|
||||
const crash_report = @import("crash_report.zig");
|
||||
@@ -3615,7 +3615,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
|
||||
defer if (enable_cache) man.deinit();
|
||||
|
||||
man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
|
||||
man.hashCSource(c_source_file) catch |err| {
|
||||
Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| {
|
||||
fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ const log = std.log.scoped(.mingw);
|
||||
const builtin = @import("builtin");
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const build_options = @import("build_options");
|
||||
const Cache = @import("Cache.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
|
||||
pub const CRTFile = enum {
|
||||
crt2_o,
|
||||
|
||||
@@ -570,7 +570,7 @@ pub fn addCliTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []co
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.addArgs(&[_][]const u8{
|
||||
fs.realpathAlloc(b.allocator, b.zig_exe) catch unreachable,
|
||||
b.pathFromRoot(b.cache_root),
|
||||
b.pathFromRoot(b.cache_root.path orelse "."),
|
||||
});
|
||||
|
||||
step.dependOn(&run_cmd.step);
|
||||
@@ -1059,7 +1059,7 @@ pub const StandaloneContext = struct {
|
||||
}
|
||||
|
||||
var zig_args = ArrayList([]const u8).init(b.allocator);
|
||||
const rel_zig_exe = fs.path.relative(b.allocator, b.build_root, b.zig_exe) catch unreachable;
|
||||
const rel_zig_exe = fs.path.relative(b.allocator, b.build_root.path orelse ".", b.zig_exe) catch unreachable;
|
||||
zig_args.append(rel_zig_exe) catch unreachable;
|
||||
zig_args.append("build") catch unreachable;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user