Shared state among all Build instances. Settings that are here rather than in Build are not configurable per-package.
pub const Graph = struct
pub const Graph = struct {
io: Io,
/// Process lifetime.
arena: Allocator,
system_integration_options: std.array_hash_map.String(SystemLibraryMode) = .empty,
system_package_mode: bool = false,
zig_exe: []const u8,
environ_map: process.Environ.Map,
needed_lazy_dependencies: std.array_hash_map.String(void) = .empty,
/// Information about the native target. Computed before build() is invoked.
host: ResolvedTarget,
dependency_cache: InitializedDepMap = .empty,
allow_so_scripts: ?bool = null,
time_report: bool = false,
verbose: bool = false,
/// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also
/// respects the '--color' flag.
stderr_mode: ?Io.Terminal.Mode = null,
release_mode: ReleaseMode = .off,
/// Indexes correspond to `Configuration.GeneratedFileIndex`.
generated_files: std.ArrayList(*Step),
wip_configuration: Configuration.Wip,
cache_poison: CachePoison = .pure,
/// Observing this data causes cache poisoning. See `CachePoison`.
search_prefixes: std.ArrayList([]const u8) = .empty,
/// Populated by calling one of:
/// * `dependOnFileContents`
/// * `dependOnFileMetadata`
/// * `dependOnDirectory`
configure_dependencies: ArrayList(ConfigureDependency) = .empty,
/// If the cache is poisoned means that the **configure logic** had side
/// effects, or otherwise did something that could not be tracked by the
/// cache system.
///
/// This is not to be confused with whether individual steps may have side
/// effects when being evaluated; it has to do with the logic inside build.zig
/// itself. For example, a `Run` step that prints "hello world" has side
/// effects *at make time* and therefore does not warrant setting this flag,
/// while checking for the existence of `scdoc` *at configure time* in order to
/// choose the default value for a configuration option does.
///
/// Keeping the cache pure will make `zig build` faster, bypassing the
/// configurer process when identical configuration would be generated.
///
/// When the cache is poisoned, the maker process will delete the build
/// configuration file upon ingesting it since it cannot be reused.
pub const CachePoison = enum {
pure,
poisoned,
/// Indicates the user would like to see a stack trace if the cache
/// would become poisoned.
disallowed,
/// Indicates the user would like to ignore the cache being poisoned
/// and cache anyway, opting into cache hits on stale configuration.
ignored,
};
pub fn addGeneratedFile(graph: *Graph, owner: *Step) Configuration.GeneratedFileIndex {
graph.generated_files.append(graph.arena, owner) catch @panic("OOM");
return @fromBackingInt(@intCast(graph.generated_files.items.len - 1));
}
pub fn dupeString(graph: *const Graph, bytes: []const u8) []const u8 {
return graph.arena.dupe(u8, bytes) catch @panic("OOM");
}
pub fn dupePath(graph: *const Graph, bytes: []const u8) []const u8 {
return dupePathInner(graph.arena, bytes);
}
fn dupePathInner(arena: Allocator, bytes: []const u8) []const u8 {
if (builtin.os.tag != .windows) return arena.dupe(u8, bytes) catch @panic("OOM");
const the_copy = arena.dupe(u8, bytes) catch @panic("OOM");
mem.replaceScalar(u8, the_copy, '/', '\\');
return the_copy;
}
pub fn dupeStrings(graph: *const Graph, strings: []const []const u8) []const []const u8 {
const array = graph.alloc([]const u8, strings.len);
for (array, strings) |*dest, source| dest.* = dupeString(graph, source);
return array;
}
/// An absolute path or a path relative to the current working directory of
/// the build runner process.
///
/// Use of this function indicates a dependency on the host system.
pub fn cwdRelativePath(graph: *Graph, sub_path: []const u8) LazyPath {
return @This().path(graph, .cwd, sub_path);
}
/// A path whose components and contents are known at some point during
/// `Step` resolution, relative to the provided base directory.
pub fn path(graph: *Graph, base: Configuration.LazyPath.Relative.Base, sub_path: []const u8) LazyPath {
assert(base != .build_root);
return .{ .relative = .{
.base = base,
.sub_path = @This().dupePath(graph, sub_path),
} };
}
/// Allocates using the global process arena, failing the build on
/// allocation failure.
pub fn alloc(graph: *const Graph, comptime T: type, n: usize) []T {
return graph.arena.allocAdvancedWithRetAddr(T, null, n, @returnAddress()) catch @panic("OOM");
}
/// Allocates using the global process arena, failing the build on
/// allocation failure.
pub fn create(graph: *const Graph, comptime T: type) *T {
return @ptrCast(graph.arena.allocBytesAligned(.of(T), @sizeOf(T), @returnAddress()) catch @panic("OOM"));
}
pub fn addBytesList(graph: *Graph, bytes_list: []const []const u8) []const Configuration.Bytes {
const result = graph.alloc(Configuration.Bytes, bytes_list.len);
for (result, bytes_list) |*d, s| d.* = addBytes(graph, s);
return result;
}
pub fn addBytes(graph: *Graph, bytes: []const u8) Configuration.Bytes {
const wc = &graph.wip_configuration;
return wc.addBytes(bytes) catch @panic("OOM");
}
pub fn addString(graph: *Graph, bytes: []const u8) Configuration.String {
const wc = &graph.wip_configuration;
return wc.addString(bytes) catch @panic("OOM");
}
/// Indicates that the **configure logic** had side effects, or otherwise
/// did something that could not be tracked by the cache system.
///
/// See `CachePoison` documentation for more details.
///
/// As an alternative to calling this function, consider these APIs instead:
/// * `dependOnFileContents`
pub fn poisonCache(graph: *Graph) void {
switch (graph.cache_poison) {
.pure => graph.cache_poison = .poisoned,
.poisoned => return,
.disallowed => @panic("cache poisoned"),
.ignored => log.warn("ignoring cache poisoning", .{}),
}
}
}