Skip to content

Commit 6d9ce40

Browse files
committed
generate buildpkgs.zig for each sub-package
1 parent a3dc9c0 commit 6d9ce40

File tree

11 files changed

+101
-72
lines changed

11 files changed

+101
-72
lines changed

src/Compilation.zig

Lines changed: 78 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,9 @@ emit_llvm_ir: ?EmitLoc,
137137
emit_analysis: ?EmitLoc,
138138
emit_docs: ?EmitLoc,
139139

140-
// true to generate the pkg_names array and hasPkg function in builtin.zig
141-
// should only be true when compiling build.zig
142-
enable_builtin_pkg_names: bool,
140+
/// enables the "buildpkgs" package that exposes what packages are available to the module.
141+
/// this should only be enabled for build.zig and its package dependencies.
142+
enable_buildpkgs: bool,
143143

144144
work_queue_wait_group: WaitGroup,
145145

@@ -507,7 +507,7 @@ pub const InitOptions = struct {
507507
test_filter: ?[]const u8 = null,
508508
test_name_prefix: ?[]const u8 = null,
509509
subsystem: ?std.Target.SubSystem = null,
510-
enable_builtin_pkg_names: ?bool = null,
510+
enable_buildpkgs: ?bool = false,
511511
};
512512

513513
fn addPackageTableToCacheHash(
@@ -909,6 +909,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
909909
artifact_sub_dir,
910910
};
911911

912+
if (options.enable_buildpkgs orelse false) {
913+
if (root_pkg.table.get("@build")) |build_pkg| {
914+
try addBuildpkgs(gpa, arena, zig_cache_artifact_directory, "buildpkgs", build_pkg);
915+
} else {
916+
fatal("enable_buildpkgs should only be enabled for build.zig", .{});
917+
}
918+
}
919+
912920
// TODO when we implement serialization and deserialization of incremental compilation metadata,
913921
// this is where we would load it. We have open a handle to the directory where
914922
// the output either already is, or will be.
@@ -1125,7 +1133,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
11251133
.test_evented_io = options.test_evented_io,
11261134
.debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
11271135
.work_queue_wait_group = undefined,
1128-
.enable_builtin_pkg_names = options.enable_builtin_pkg_names orelse false,
1136+
.enable_buildpkgs = options.enable_buildpkgs orelse false,
11291137
};
11301138
break :comp comp;
11311139
};
@@ -2791,7 +2799,7 @@ fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) !void {
27912799
const tracy = trace(@src());
27922800
defer tracy.end();
27932801

2794-
const source = try comp.generateBuiltinZigSource(comp.gpa, mod);
2802+
const source = try comp.generateBuiltinZigSource(comp.gpa);
27952803
defer comp.gpa.free(source);
27962804
try mod.zig_cache_artifact_directory.handle.writeFile("builtin.zig", source);
27972805
}
@@ -2803,7 +2811,7 @@ pub fn dump_argv(argv: []const []const u8) void {
28032811
std.debug.print("{s}\n", .{argv[argv.len - 1]});
28042812
}
28052813

2806-
pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator, optional_mod: ?*Module) ![]u8 {
2814+
pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {
28072815
const tracy = trace(@src());
28082816
defer tracy.end();
28092817

@@ -2993,59 +3001,76 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator, optio
29933001
}
29943002
}
29953003

2996-
if (comp.enable_builtin_pkg_names) {
2997-
try buffer.writer().writeAll(
2998-
\\
2999-
\\pub const pkg_names = &[_][]const u8 {
3000-
\\
3001-
);
3002-
if (optional_mod) |mod| {
3003-
// TODO: this isn't right, each package should have it's
3004-
// own set of sub-packages
3005-
try recursiveWritePackageNames(buffer.writer(), mod.root_pkg);
3006-
}
3007-
try buffer.writer().writeAll(
3008-
\\};
3009-
\\
3010-
\\// using .Inline to force this to be comptime
3011-
\\pub fn hasPkg(comptime name: []const u8) callconv(.Inline) bool {
3012-
\\ if (!isComptime()) {
3013-
\\ @compileError("builtin.hasPkg MUST be called with comptime");
3014-
\\ }
3015-
\\ inline for (pkg_names) |has_name| {
3016-
\\ if (@import("std").mem.eql(u8, name, has_name)) return true;
3017-
\\ }
3018-
\\ return false;
3019-
\\}
3020-
\\
3021-
\\// A temporary workaround until https://github.com/ziglang/zig/issues/425
3022-
\\// is implemented and the callconv(.Inline) on the `hasPkg` function forces
3023-
\\// it to be comptime
3024-
\\fn isComptime() bool {
3025-
\\ var t: bool = true;
3026-
\\ const x = if (t) @as(u7, 0) else @as(u8, 0);
3027-
\\ return @TypeOf(x) == u7;
3028-
\\}
3029-
\\
3030-
);
3031-
} else {
3032-
try buffer.writer().writeAll(
3033-
\\
3034-
\\pub const pkg_names = @compileError("builtin.pkg_names is only available in build.zig");
3035-
\\pub const hasPkg = @compileError("builtin.hasPkg is only available in build.zig");
3036-
\\
3037-
);
3004+
return buffer.toOwnedSlice();
3005+
}
3006+
3007+
fn addBuildpkgs(gpa: *Allocator, arena: *Allocator, dir: Directory, name: []const u8, pkg: *Package) anyerror!void {
3008+
var pkg_dir = Directory {
3009+
.path = try dir.join(gpa, &[_][]const u8 { name }),
3010+
.handle = try dir.handle.makeOpenPath(name, .{}),
3011+
};
3012+
defer pkg_dir.handle.close();
3013+
var sub_pkg_it = pkg.table.iterator();
3014+
while (sub_pkg_it.next()) |sub_pkg| {
3015+
try addBuildpkgs(gpa, arena, pkg_dir, sub_pkg.key, sub_pkg.value);
30383016
}
30393017

3040-
return buffer.toOwnedSlice();
3018+
const source = try generateBuildpkgsZigSource(gpa, pkg);
3019+
defer gpa.free(source);
3020+
try pkg_dir.handle.writeFile("buildpkgs.zig", source);
3021+
3022+
try pkg.table.put(arena, "buildpkgs", Package.create(gpa, pkg_dir.path, "buildpkgs.zig") catch |err| {
3023+
fatal("Failed to create buildpkgs Package at path {s}: {s}", .{ pkg_dir.path, @errorName(err) });
3024+
});
30413025
}
30423026

3043-
fn recursiveWritePackageNames(writer: anytype, pkg: *const Package) anyerror!void {
3027+
pub fn generateBuildpkgsZigSource(allocator: *Allocator, pkg: *const Package) ![]u8 {
3028+
const tracy = trace(@src());
3029+
defer tracy.end();
3030+
3031+
var buffer = std.ArrayList(u8).init(allocator);
3032+
defer buffer.deinit();
3033+
3034+
try buffer.writer().writeAll(
3035+
\\
3036+
\\pub const names = &[_][]const u8 {
3037+
\\
3038+
);
3039+
//std.log.info("writePackageNames: begin (path={s}, dir={s})", .{
3040+
// pkg.root_src_path,
3041+
// if (pkg.root_src_directory.path) |p| p else "<none>",
3042+
//});
30443043
var pkg_it = pkg.table.iterator();
30453044
while (pkg_it.next()) |sub_pkg| {
3046-
try writer.print(" \"{s}\",\n", .{sub_pkg.key});
3047-
try recursiveWritePackageNames(writer, sub_pkg.value);
3045+
//std.log.info("writePackageNames: name={s}", .{sub_pkg.key});
3046+
try buffer.writer().print(" \"{s}\",\n", .{sub_pkg.key});
30483047
}
3048+
try buffer.writer().writeAll(
3049+
\\};
3050+
\\
3051+
\\// using .Inline to force this to be comptime
3052+
\\pub fn has(comptime name: []const u8) callconv(.Inline) bool {
3053+
\\ if (!isComptime()) {
3054+
\\ @compileError("buildpkgs.has MUST be called with comptime");
3055+
\\ }
3056+
\\ inline for (names) |has_name| {
3057+
\\ if (@import("std").mem.eql(u8, name, has_name)) return true;
3058+
\\ }
3059+
\\ return false;
3060+
\\}
3061+
\\
3062+
\\// A temporary workaround until https://github.com/ziglang/zig/issues/425
3063+
\\// is implemented and the callconv(.Inline) on the `has` function forces
3064+
\\// it to be comptime
3065+
\\fn isComptime() bool {
3066+
\\ var t: bool = true;
3067+
\\ const x = if (t) @as(u7, 0) else @as(u8, 0);
3068+
\\ return @TypeOf(x) == u7;
3069+
\\}
3070+
\\
3071+
);
3072+
3073+
return buffer.toOwnedSlice();
30493074
}
30503075

30513076
pub fn updateSubCompilation(sub_compilation: *Compilation) !void {

src/main.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,7 +1900,7 @@ fn buildOutputType(
19001900
defer if (!comp_destroyed) comp.destroy();
19011901

19021902
if (show_builtin) {
1903-
return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena, null));
1903+
return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));
19041904
}
19051905
if (arg_mode == .translate_c) {
19061906
return cmdTranslateC(comp, arena, have_enable_cache);
@@ -2596,7 +2596,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
25962596
.optimize_mode = .Debug,
25972597
.self_exe_path = self_exe_path,
25982598
.thread_pool = &thread_pool,
2599-
.enable_builtin_pkg_names = true,
2599+
.enable_buildpkgs = true,
26002600
}) catch |err| {
26012601
fatal("unable to create compilation: {s}", .{@errorName(err)});
26022602
};

test/standalone.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
1717
cases.addBuildFile("test/standalone/issue_794/build.zig");
1818
cases.addBuildFile("test/standalone/issue_5825/build.zig");
1919
cases.addBuildFile("test/standalone/pkg_import/build.zig");
20-
cases.addBuildFile("test/standalone/build_zig_pkgs/build.zig");
20+
cases.addBuildFile("test/standalone/buildpkgs/build.zig");
2121
cases.addBuildFile("test/standalone/use_alias/build.zig");
2222
cases.addBuildFile("test/standalone/brace_expansion/build.zig");
2323
cases.addBuildFile("test/standalone/empty_env/build.zig");

test/standalone/build_zig_pkgs/calling-haspkg-outside-build.zig

Lines changed: 0 additions & 5 deletions
This file was deleted.

test/standalone/build_zig_pkgs/RunStep.zig renamed to test/standalone/buildpkgs/RunStep.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub const Options = struct {
88
expect: enum { fail, pass },
99
outputs: []const []const u8,
1010
args: []const []const u8,
11+
cwd: ?[]const u8 = null,
1112
};
1213

1314
step: Step,
@@ -26,6 +27,7 @@ fn make(step: *Step) !void {
2627
const self = @fieldParentPtr(RunStep, "step", step);
2728
const child = try std.ChildProcess.init(self.opt.args, std.heap.page_allocator);
2829
defer child.deinit();
30+
child.cwd = self.opt.cwd;
2931
child.stderr_behavior = .Pipe;
3032
try child.spawn();
3133
const stderr = try child.stderr.?.reader().readAllAlloc(self.builder.allocator, std.math.maxInt(usize));

test/standalone/build_zig_pkgs/android/build.zig renamed to test/standalone/buildpkgs/android/build.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const std = @import("std");
22
const Builder = std.build.Builder;
3+
const buildpkgs = @import("buildpkgs");
34

45
pub const Options = struct {
56
fastcompress: bool,
@@ -14,7 +15,7 @@ pub fn getApkOptions(b: *Builder) Options {
1415
pub fn makeApk(b: *Builder, options: Options) !void {
1516
// android has its own optional dependency
1617
if (options.fastcompress) {
17-
if (comptime std.builtin.hasPkg("fastcompressor")) {
18+
if (comptime buildpkgs.has("fastcompressor")) {
1819
const fastcompressor = @import("fastcompressor");
1920
std.log.info("we have and need the 'fastcompressor' package", .{});
2021
fastcompressor.doTheThing();

test/standalone/build_zig_pkgs/app-that-might-use-android/build.zig renamed to test/standalone/buildpkgs/app-that-might-use-android/build.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
const std = @import("std");
22
const Builder = std.build.Builder;
3+
const buildpkgs = @import("buildpkgs");
34

45
pub fn build(b: *Builder) !void {
56
if (b.option(bool, "android", "build for android") orelse false) {
6-
if (comptime @import("std").builtin.hasPkg("androidbuild")) {
7+
if (comptime buildpkgs.has("androidbuild")) {
78
std.log.info("we have and need the 'androidbuild' package", .{});
89
const androidbuild = @import("androidbuild");
910
const options = androidbuild.getApkOptions(b);

test/standalone/build_zig_pkgs/build.zig renamed to test/standalone/buildpkgs/build.zig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub fn build(b: *Builder) !void {
8585
});
8686
try addRunStep(b, test_step, .{
8787
.expect = .fail,
88-
.outputs = &[_][]const u8 { "builtin.hasPkg MUST be called with comptime" },
88+
.outputs = &[_][]const u8 { "buildpkgs.has MUST be called with comptime" },
8989
.args = try std.mem.dupe(b.allocator, []const u8, &[_][]const u8 {
9090
b.zig_exe,
9191
"build",
@@ -94,17 +94,18 @@ pub fn build(b: *Builder) !void {
9494
});
9595
try addRunStep(b, test_step, .{
9696
.expect = .fail,
97-
.outputs = &[_][]const u8 { "builtin.hasPkg is only available in build.zig" },
97+
.outputs = &[_][]const u8 { "unable to find 'buildpkgs'" },
9898
.args = try std.mem.dupe(b.allocator, []const u8, &[_][]const u8 {
9999
b.zig_exe,
100100
"build-exe",
101-
"calling-haspkg-outside-build.zig"
101+
"import-buildpkgs-outside-build.zig",
102102
}),
103103
});
104104
}
105105

106106
fn addRunStep(b: *Builder, test_step: *std.build.Step, opt: RunStep.Options) !void {
107107
const run = try b.allocator.create(RunStep);
108108
run.* = RunStep.init(b, opt);
109+
run.opt.cwd = b.build_root;
109110
test_step.dependOn(&run.step);
110111
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
21
pub fn doTheThing() void {
32
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub fn main() void {
2+
if (@import("buildpkgs").has("foo")) {
3+
@compileError("calling buildpkgs.has outside of build.zig should be a compile error");
4+
}
5+
}

test/standalone/build_zig_pkgs/missing-comptime/build.zig renamed to test/standalone/buildpkgs/missing-comptime/build.zig

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
//! Currently the user MUST specify comptime when calling builtin.hasPkg
1+
//! Currently the user MUST specify comptime when calling "buildpkgs.has"
22
//! until https://github.com/ziglang/zig/issues/425 is implemented.
3-
//! This build.zig file tries to call builtin.hasPkg without comptime and the
3+
//! This build.zig file tries to call "buildpkgs.has" without comptime and the
44
//! test is to make sure it produces a compile error.
55
//!
6-
//! Note that the reason why "hasPkg" must be evaluated at comptime is
6+
//! Note that the reason why "buildpkgs.has" must be evaluated at comptime is
77
//! because it will always surround an @import statement. The problem is
88
//! that if they forget to add "comptime" to their call, then their build.zig
99
//! file will "sometimes work" so long as they are building with the necessary
1010
//! packages configured, but then it will fail once the @import is missing
11-
//! which defeats the whole purpose of providing "hasPkg" in the first place.
11+
//! which defeats the whole purpose of providing "buildpkgs.has" in the first place.
1212
//!
1313
const Builder = @import("std").build.Builder;
1414

1515
pub fn build(b: *Builder) void {
1616
// This should be a compile error because it's not marked as comptime
17-
if (@import("std").builtin.hasPkg("androidbuild")) {
17+
if (@import("buildpkgs").has("androidbuild")) {
1818
const androidbuild = @import("androidbuild");
1919
androidbuild.makeApk(b);
2020
}

0 commit comments

Comments
 (0)