Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make contents of zig env available in build.zig #19932

Open
190n opened this issue May 10, 2024 · 2 comments
Open

Make contents of zig env available in build.zig #19932

190n opened this issue May 10, 2024 · 2 comments

Comments

@190n
Copy link
Contributor

190n commented May 10, 2024

My use case is automatically compiling C-backend-generated code from build.zig. In order to do this, you need to pass the directory containing zig.h with -I. This directory is available in zig env with the key lib_dir, but the information in zig env isn't directly available in build.zig.

The workaround I've found is to create a system command step that pipes zig env into jq, capture its stdout, and include a cat of the file its stdout goes to in my C compiler command: https://github.com/190n/zip8/blob/6443612ddd4e897c64ee51d9ca61ba3b854f30f5/build.zig#L126-L153. But this is inconvenient and it adds system dependencies. It'd be possible to parse this info with std.json, but since capturing the stdout of the command gives me a LazyPath I think I would have to write a custom build step to receive that filename, open it, and parse its contents. I imagine enough of the other info in zig env is also useful that this justifies having it immediately available in the build system.

@ehaas
Copy link
Sponsor Contributor

ehaas commented May 10, 2024

If you want to do it in pure Zig today:

//! Step for determining the zig lib dir and various subdirectories via `zig env`

const std = @import("std");
const Step = std.Build.Step;
const ZigLibDir = @This();
const LazyPath = std.Build.LazyPath;

step: Step,
/// path to zig's lib directory
lib_dir: std.Build.GeneratedFile,
/// path to compiler-rt directory
compiler_rt: std.Build.GeneratedFile,
/// path to directory which has zig.h
include: std.Build.GeneratedFile,

pub fn create(owner: *std.Build) !*ZigLibDir {
    const self = try owner.allocator.create(ZigLibDir);
    const name = "zig lib dir";
    self.* = .{
        .step = Step.init(.{
            .id = .custom,
            .name = name,
            .owner = owner,
            .makeFn = make,
        }),
        .lib_dir = .{ .step = &self.step },
        .compiler_rt = .{ .step = &self.step },
        .include = .{ .step = &self.step },
    };
    return self;
}

const ZigEnv = struct {
    lib_dir: []const u8,
};

fn make(step: *Step, prog_node: *std.Progress.Node) !void {
    _ = prog_node;

    const b = step.owner;
    const self = @fieldParentPtr(ZigLibDir, "step", step);

    const zig_env_args: [2][]const u8 = .{ b.graph.zig_exe, "env" };
    var out_code: u8 = undefined;
    const zig_env = try b.runAllowFail(&zig_env_args, &out_code, .Ignore);

    const parsed_str = try std.json.parseFromSlice(ZigEnv, b.allocator, zig_env, .{ .ignore_unknown_fields = true });
    defer parsed_str.deinit();

    self.lib_dir.path = parsed_str.value.lib_dir;
    self.compiler_rt.path = try std.fs.path.join(b.allocator, &[_][]const u8{ parsed_str.value.lib_dir, "compiler_rt.zig" });
    self.include.path = try std.fs.path.join(b.allocator, &[_][]const u8{ parsed_str.value.lib_dir, "include" });
}

pub fn getLibPath(self: *ZigLibDir) std.Build.LazyPath {
    return .{ .generated = &self.lib_dir };
}

pub fn getCompilerRTPath(self: *ZigLibDir) std.Build.LazyPath {
    return .{ .generated = &self.compiler_rt };
}

pub fn getIncludePath(self: *ZigLibDir) std.Build.LazyPath {
    return .{ .generated = &self.include };
}

For a full example - clone this repo: https://github.com/Vexu/arocc and check out commit 47e12cfeb4ff0186db61ec1aa2173ffa8e75dafc (that's a commit prior to my removing the step, as it was no longer relevant) and look at ZigLibDir.zig and how it's used in build.zig

@190n
Copy link
Contributor Author

190n commented May 10, 2024

Thanks for the code, I might refer back here if I do ever want to customize the build system more deeply. But I hope it's also clear from that example why I think it'll be convenient to have this information built-in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants