unionstd.Build.LazyPath[src]

A reference to an existing or future path.

Fields

src_path: struct {
    owner: *std.Build,
    sub_path: []const u8,
}

A source file path relative to build root.

generated: struct {
    file: *const GeneratedFile,

    /// 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 = "",
}
cwd_relative: []const u8

An absolute path or a path relative to the current working directory of the build runner process. This is uncommon but used for system environment paths such as --zig-lib-dir which ignore the file system path of build.zig and instead are relative to the directory from which zig build was invoked. Use of this tag indicates a dependency on the host system.

dependency: struct {
    dependency: *Dependency,
    sub_path: []const u8,
}

Functions

Functiondirname[src]

pub fn dirname(lazy_path: LazyPath) LazyPath

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.

Parameters

lazy_path: LazyPath

Source Code

Source code
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| .{
            .file = generated.file,
            .up = generated.up,
            .sub_path = sub_dirname,
        } else .{
            .file = generated.file,
            .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");
                }
            },
        },
        .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");
            },
        } },
    };
}

Functionpath[src]

pub fn path(lazy_path: LazyPath, b: *Build, sub_path: []const u8) LazyPath

Parameters

lazy_path: LazyPath
b: *Build
sub_path: []const u8

Source Code

Source code
pub fn path(lazy_path: LazyPath, b: *Build, sub_path: []const u8) LazyPath {
    return lazy_path.join(b.allocator, sub_path) catch @panic("OOM");
}

Functionjoin[src]

pub fn join(lazy_path: LazyPath, arena: Allocator, sub_path: []const u8) Allocator.Error!LazyPath

Parameters

lazy_path: LazyPath
arena: Allocator
sub_path: []const u8

Source Code

Source code
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 = .{
            .file = gen.file,
            .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 }),
        },
        .dependency => |dep| .{ .dependency = .{
            .dependency = dep.dependency,
            .sub_path = try fs.path.resolve(arena, &.{ dep.sub_path, sub_path }),
        } },
    };
}

FunctiongetDisplayName[src]

pub fn getDisplayName(lazy_path: LazyPath) []const u8

Returns a string that can be shown to represent the file source. Either returns the path, "generated", or "dependency".

Parameters

lazy_path: LazyPath

Source Code

Source code
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",
    };
}

FunctionaddStepDependencies[src]

pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void

Adds dependencies this file source implies to the given step.

Parameters

lazy_path: LazyPath
other_step: *Step

Source Code

Source code
pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void {
    switch (lazy_path) {
        .src_path, .cwd_relative, .dependency => {},
        .generated => |gen| other_step.dependOn(gen.file.step),
    }
}

FunctiongetPath[src]

pub fn getPath(lazy_path: LazyPath, src_builder: *Build) []const u8

Deprecated, see getPath3.

Parameters

lazy_path: LazyPath
src_builder: *Build

Source Code

Source code
pub fn getPath(lazy_path: LazyPath, src_builder: *Build) []const u8 {
    return getPath2(lazy_path, src_builder, null);
}

FunctiongetPath2[src]

pub fn getPath2(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8

Deprecated, see getPath3.

Parameters

lazy_path: LazyPath
src_builder: *Build
asking_step: ?*Step

Source Code

Source code
pub fn getPath2(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 {
    const p = getPath3(lazy_path, src_builder, asking_step);
    return src_builder.pathResolve(&.{ p.root_dir.path orelse ".", p.sub_path });
}

FunctiongetPath3[src]

pub fn getPath3(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) Cache.Path

Intended to be used during the make phase only.

asking_step is only used for debugging purposes; it's the step being run that is asking for the path.

Parameters

lazy_path: LazyPath
src_builder: *Build
asking_step: ?*Step

Source Code

Source code
pub fn getPath3(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) Cache.Path {
    switch (lazy_path) {
        .src_path => |sp| return .{
            .root_dir = sp.owner.build_root,
            .sub_path = sp.sub_path,
        },
        .cwd_relative => |sub_path| return .{
            .root_dir = Cache.Directory.cwd(),
            .sub_path = sub_path,
        },
        .generated => |gen| {
            // TODO make gen.file.path not be absolute and use that as the
            // basis for not traversing up too many directories.

            var file_path: Cache.Path = .{
                .root_dir = Cache.Directory.cwd(),
                .sub_path = gen.file.path orelse {
                    std.debug.lockStdErr();
                    const stderr = std.io.getStdErr();
                    dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {};
                    std.debug.unlockStdErr();
                    @panic("misconfigured build script");
                },
            };

            if (gen.up > 0) {
                const cache_root_path = src_builder.cache_root.path orelse
                    (src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM"));

                for (0..gen.up) |_| {
                    if (mem.eql(u8, file_path.sub_path, cache_root_path)) {
                        // If we hit the cache root and there's still more to go,
                        // the script attempted to go too far.
                        dumpBadDirnameHelp(gen.file.step, asking_step,
                            \\dirname() attempted to traverse outside the cache root.
                            \\This is not allowed.
                            \\
                        , .{}) catch {};
                        @panic("misconfigured build script");
                    }

                    // path is absolute.
                    // dirname will return null only if we're at root.
                    // Typically, we'll stop well before that at the cache root.
                    file_path.sub_path = fs.path.dirname(file_path.sub_path) orelse {
                        dumpBadDirnameHelp(gen.file.step, asking_step,
                            \\dirname() reached root.
                            \\No more directories left to go up.
                            \\
                        , .{}) catch {};
                        @panic("misconfigured build script");
                    };
                }
            }

            return file_path.join(src_builder.allocator, gen.sub_path) catch @panic("OOM");
        },
        .dependency => |dep| return .{
            .root_dir = dep.dependency.builder.build_root,
            .sub_path = dep.sub_path,
        },
    }
}

Functiondupe[src]

pub fn dupe(lazy_path: LazyPath, b: *Build) LazyPath

Copies the internal strings.

The b parameter is only used for its allocator. All *Build instances share the same allocator.

Parameters

lazy_path: LazyPath
b: *Build

Source Code

Source code
pub fn dupe(lazy_path: LazyPath, b: *Build) LazyPath {
    return lazy_path.dupeInner(b.allocator);
}

Source Code

Source code
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 {
        file: *const GeneratedFile,

        /// 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 = "",
    },

    /// An absolute path or a path relative to the current working directory of
    /// the build runner process.
    /// This is uncommon but used for system environment paths such as `--zig-lib-dir` which
    /// ignore the file system path of build.zig and instead are relative to the directory from
    /// which `zig build` was invoked.
    /// Use of this tag indicates a dependency on the host system.
    cwd_relative: []const u8,

    dependency: struct {
        dependency: *Dependency,
        sub_path: []const u8,
    },

    /// 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| .{
                .file = generated.file,
                .up = generated.up,
                .sub_path = sub_dirname,
            } else .{
                .file = generated.file,
                .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");
                    }
                },
            },
            .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 {
        return lazy_path.join(b.allocator, 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 = .{
                .file = gen.file,
                .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 }),
            },
            .dependency => |dep| .{ .dependency = .{
                .dependency = dep.dependency,
                .sub_path = try fs.path.resolve(arena, &.{ dep.sub_path, sub_path }),
            } },
        };
    }

    /// Returns a string that can be shown to represent the file source.
    /// Either returns the path, `"generated"`, or `"dependency"`.
    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",
        };
    }

    /// 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, .dependency => {},
            .generated => |gen| other_step.dependOn(gen.file.step),
        }
    }

    /// Deprecated, see `getPath3`.
    pub fn getPath(lazy_path: LazyPath, src_builder: *Build) []const u8 {
        return getPath2(lazy_path, src_builder, null);
    }

    /// Deprecated, see `getPath3`.
    pub fn getPath2(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 {
        const p = getPath3(lazy_path, src_builder, asking_step);
        return src_builder.pathResolve(&.{ p.root_dir.path orelse ".", p.sub_path });
    }

    /// Intended to be used during the make phase only.
    ///
    /// `asking_step` is only used for debugging purposes; it's the step being
    /// run that is asking for the path.
    pub fn getPath3(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) Cache.Path {
        switch (lazy_path) {
            .src_path => |sp| return .{
                .root_dir = sp.owner.build_root,
                .sub_path = sp.sub_path,
            },
            .cwd_relative => |sub_path| return .{
                .root_dir = Cache.Directory.cwd(),
                .sub_path = sub_path,
            },
            .generated => |gen| {
                // TODO make gen.file.path not be absolute and use that as the
                // basis for not traversing up too many directories.

                var file_path: Cache.Path = .{
                    .root_dir = Cache.Directory.cwd(),
                    .sub_path = gen.file.path orelse {
                        std.debug.lockStdErr();
                        const stderr = std.io.getStdErr();
                        dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {};
                        std.debug.unlockStdErr();
                        @panic("misconfigured build script");
                    },
                };

                if (gen.up > 0) {
                    const cache_root_path = src_builder.cache_root.path orelse
                        (src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM"));

                    for (0..gen.up) |_| {
                        if (mem.eql(u8, file_path.sub_path, cache_root_path)) {
                            // If we hit the cache root and there's still more to go,
                            // the script attempted to go too far.
                            dumpBadDirnameHelp(gen.file.step, asking_step,
                                \\dirname() attempted to traverse outside the cache root.
                                \\This is not allowed.
                                \\
                            , .{}) catch {};
                            @panic("misconfigured build script");
                        }

                        // path is absolute.
                        // dirname will return null only if we're at root.
                        // Typically, we'll stop well before that at the cache root.
                        file_path.sub_path = fs.path.dirname(file_path.sub_path) orelse {
                            dumpBadDirnameHelp(gen.file.step, asking_step,
                                \\dirname() reached root.
                                \\No more directories left to go up.
                                \\
                            , .{}) catch {};
                            @panic("misconfigured build script");
                        };
                    }
                }

                return file_path.join(src_builder.allocator, gen.sub_path) catch @panic("OOM");
            },
            .dependency => |dep| return .{
                .root_dir = dep.dependency.builder.build_root,
                .sub_path = dep.sub_path,
            },
        }
    }

    /// Copies the internal strings.
    ///
    /// The `b` parameter is only used for its allocator. All *Build instances
    /// share the same allocator.
    pub fn dupe(lazy_path: LazyPath, b: *Build) LazyPath {
        return lazy_path.dupeInner(b.allocator);
    }

    fn dupeInner(lazy_path: LazyPath, allocator: std.mem.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 = dupePathInner(allocator, p) },
            .generated => |gen| .{ .generated = .{
                .file = gen.file,
                .up = gen.up,
                .sub_path = dupePathInner(allocator, gen.sub_path),
            } },
            .dependency => |dep| .{ .dependency = dep },
        };
    }
}