A reference to an existing or future path.
pub const LazyPath = union(enum)
pub const LazyPath = union(enum) {
/// A source file path relative to build root.
src_path: struct {
owner: *std.Build,
sub_path: []const u8,
},
generated: struct {
index: Configuration.GeneratedFileIndex,
/// The number of parent directories to go up.
/// 0 means the generated file itself.
/// 1 means the directory of the generated file.
/// 2 means the parent of that directory, and so on.
up: usize = 0,
/// Applied after `up`.
sub_path: []const u8 = "",
},
/// Deprecated; call `Graph.cwdRelativePath` instead.
cwd_relative: []const u8,
dependency: struct {
dependency: *Dependency,
sub_path: []const u8,
},
relative: struct {
base: Configuration.LazyPath.Relative.Base,
sub_path: []const u8 = "",
pub fn eql(a: @This(), b: @This()) bool {
return a.base == b.base and mem.eql(u8, a.sub_path, b.sub_path);
}
},
/// Path to the Zig executable being used to execute "zig build".
pub const zig_exe: LazyPath = .{ .relative = .{ .base = .zig_exe } };
/// Path to the "lib/" directory from the Zig installation being used to
/// execute "zig build".
pub const zig_lib: LazyPath = .{ .relative = .{ .base = .zig_lib } };
/// Path to the project's local cache directory (usually called ".zig-cache").
pub const cache_root: LazyPath = .{ .relative = .{ .base = .local_cache } };
/// Returns a lazy path referring to the directory containing this path.
///
/// The dirname is not allowed to escape the logical root for underlying
/// path. For example, if the path is relative to the build root, the
/// dirname is not allowed to traverse outside of the build root.
/// Similarly, if the path is a generated file inside zig-cache, the
/// dirname is not allowed to traverse outside of zig-cache.
pub fn dirname(lazy_path: LazyPath) LazyPath {
return switch (lazy_path) {
.src_path => |sp| .{ .src_path = .{
.owner = sp.owner,
.sub_path = dirnameAllowEmpty(sp.sub_path) orelse {
dumpBadDirnameHelp(null, null, "dirname() attempted to traverse outside the build root\n", .{}) catch {};
@panic("misconfigured build script");
},
} },
.generated => |generated| .{ .generated = if (dirnameAllowEmpty(generated.sub_path)) |sub_dirname| .{
.index = generated.index,
.up = generated.up,
.sub_path = sub_dirname,
} else .{
.index = generated.index,
.up = generated.up + 1,
.sub_path = "",
} },
.cwd_relative => |rel_path| .{
.cwd_relative = dirnameAllowEmpty(rel_path) orelse {
// If we get null, it means one of two things:
// - rel_path was absolute, and is now root
// - rel_path was relative, and is now ""
// In either case, the build script tried to go too far
// and we should panic.
if (fs.path.isAbsolute(rel_path)) {
dumpBadDirnameHelp(null, null,
\\dirname() attempted to traverse outside the root.
\\No more directories left to go up.
\\
, .{}) catch {};
@panic("misconfigured build script");
} else {
dumpBadDirnameHelp(null, null,
\\dirname() attempted to traverse outside the current working directory.
\\
, .{}) catch {};
@panic("misconfigured build script");
}
},
},
.relative => |r| .{ .relative = .{
.base = r.base,
.sub_path = dirnameAllowEmpty(r.sub_path) orelse {
dumpBadDirnameHelp(null, null, "dirname() attempted to traverse outside the base path\n", .{}) catch {};
@panic("misconfigured build script");
},
} },
.dependency => |dep| .{ .dependency = .{
.dependency = dep.dependency,
.sub_path = dirnameAllowEmpty(dep.sub_path) orelse {
dumpBadDirnameHelp(null, null,
\\dirname() attempted to traverse outside the dependency root.
\\
, .{}) catch {};
@panic("misconfigured build script");
},
} },
};
}
pub fn path(lazy_path: LazyPath, b: *Build, sub_path: []const u8) LazyPath {
const graph = b.graph;
const arena = graph.arena;
return lazy_path.join(arena, sub_path) catch @panic("OOM");
}
pub fn join(lazy_path: LazyPath, arena: Allocator, sub_path: []const u8) Allocator.Error!LazyPath {
return switch (lazy_path) {
.src_path => |src| .{ .src_path = .{
.owner = src.owner,
.sub_path = try fs.path.resolve(arena, &.{ src.sub_path, sub_path }),
} },
.generated => |gen| .{ .generated = .{
.index = gen.index,
.up = gen.up,
.sub_path = try fs.path.resolve(arena, &.{ gen.sub_path, sub_path }),
} },
.cwd_relative => |cwd_relative| .{
.cwd_relative = try fs.path.resolve(arena, &.{ cwd_relative, sub_path }),
},
.relative => |r| .{ .relative = .{
.base = r.base,
.sub_path = try fs.path.resolve(arena, &.{ r.sub_path, sub_path }),
} },
.dependency => |dep| .{ .dependency = .{
.dependency = dep.dependency,
.sub_path = try fs.path.resolve(arena, &.{ dep.sub_path, sub_path }),
} },
};
}
/// Deprecated, use `format` instead.
pub fn getDisplayName(lazy_path: LazyPath) []const u8 {
return switch (lazy_path) {
.src_path => |sp| sp.sub_path,
.cwd_relative => |p| p,
.generated => "generated",
.dependency => "dependency",
.relative => |r| @tagName(r.base),
};
}
pub fn format(lp: LazyPath, w: *Io.Writer) Io.Writer.Error!void {
switch (lp) {
.src_path => |sp| try w.writeAll(sp.sub_path),
.cwd_relative => |p| try w.writeAll(p),
.generated => try w.writeAll("generated"),
.dependency => try w.writeAll("dependency"),
.relative => |r| try w.print("{t} {s}", .{ r.base, r.sub_path }),
}
}
/// Adds dependencies this file source implies to the given step.
pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void {
switch (lazy_path) {
.src_path, .cwd_relative, .relative, .dependency => {},
.generated => |gen| {
const graph = other_step.owner.graph;
const generated_owner_step = graph.generated_files.items[@backingInt(gen.index)];
other_step.dependOn(generated_owner_step);
},
}
}
/// Copies the internal strings.
///
/// The `graph` parameter is only used for the global arena allocator.
pub fn dupe(lazy_path: LazyPath, graph: *const Graph) LazyPath {
return dupeInner(lazy_path, graph.arena);
}
/// Copies the slice of paths and all internal strings.
///
/// The `graph` parameter is only used for the global arena allocator.
pub fn dupeList(lazy_paths: []const LazyPath, graph: *const Graph) []const LazyPath {
const arena = graph.arena;
const result = graph.alloc(LazyPath, lazy_paths.len);
for (result, lazy_paths) |*d, s| d.* = dupeInner(s, arena);
return result;
}
fn dupeInner(lazy_path: LazyPath, arena: Allocator) LazyPath {
return switch (lazy_path) {
.src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } },
.cwd_relative => |p| .{ .cwd_relative = Graph.dupePathInner(arena, p) },
.relative => |r| .{ .relative = r },
.generated => |gen| .{ .generated = .{
.index = gen.index,
.up = gen.up,
.sub_path = Graph.dupePathInner(arena, gen.sub_path),
} },
.dependency => |dep| .{ .dependency = .{
.dependency = dep.dependency,
.sub_path = Graph.dupePathInner(arena, dep.sub_path),
} },
};
}
}