Skip to content

Commit 9e11727

Browse files
authored
Merge pull request #23340 from castholm/pass-null-to-b-dependency
Add support for passing null, string literals, enum lists and more to `b.dependency()`
2 parents 869ef00 + ca57115 commit 9e11727

File tree

11 files changed

+411
-85
lines changed

11 files changed

+411
-85
lines changed

lib/std/Build.zig

Lines changed: 151 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -408,104 +408,179 @@ fn createChildOnly(
408408
return child;
409409
}
410410

411-
fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap {
412-
var user_input_options = UserInputOptionsMap.init(allocator);
411+
fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap {
412+
var map = UserInputOptionsMap.init(arena);
413413
inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
414-
const v = @field(args, field.name);
415-
const T = @TypeOf(v);
416-
switch (T) {
417-
Target.Query => {
418-
user_input_options.put(field.name, .{
419-
.name = field.name,
420-
.value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") },
421-
.used = false,
422-
}) catch @panic("OOM");
423-
user_input_options.put("cpu", .{
424-
.name = "cpu",
425-
.value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") },
426-
.used = false,
427-
}) catch @panic("OOM");
428-
},
429-
ResolvedTarget => {
430-
user_input_options.put(field.name, .{
431-
.name = field.name,
432-
.value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") },
433-
.used = false,
434-
}) catch @panic("OOM");
435-
user_input_options.put("cpu", .{
436-
.name = "cpu",
437-
.value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") },
438-
.used = false,
439-
}) catch @panic("OOM");
440-
},
441-
LazyPath => {
442-
user_input_options.put(field.name, .{
414+
if (field.type == @Type(.null)) continue;
415+
addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name));
416+
}
417+
return map;
418+
}
419+
420+
fn addUserInputOptionFromArg(
421+
arena: Allocator,
422+
map: *UserInputOptionsMap,
423+
field: std.builtin.Type.StructField,
424+
comptime T: type,
425+
/// If null, the value won't be added, but `T` will still be type-checked.
426+
maybe_value: ?T,
427+
) void {
428+
switch (T) {
429+
Target.Query => return if (maybe_value) |v| {
430+
map.put(field.name, .{
431+
.name = field.name,
432+
.value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") },
433+
.used = false,
434+
}) catch @panic("OOM");
435+
map.put("cpu", .{
436+
.name = "cpu",
437+
.value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") },
438+
.used = false,
439+
}) catch @panic("OOM");
440+
},
441+
ResolvedTarget => return if (maybe_value) |v| {
442+
map.put(field.name, .{
443+
.name = field.name,
444+
.value = .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") },
445+
.used = false,
446+
}) catch @panic("OOM");
447+
map.put("cpu", .{
448+
.name = "cpu",
449+
.value = .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") },
450+
.used = false,
451+
}) catch @panic("OOM");
452+
},
453+
std.zig.BuildId => return if (maybe_value) |v| {
454+
map.put(field.name, .{
455+
.name = field.name,
456+
.value = .{ .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM") },
457+
.used = false,
458+
}) catch @panic("OOM");
459+
},
460+
LazyPath => return if (maybe_value) |v| {
461+
map.put(field.name, .{
462+
.name = field.name,
463+
.value = .{ .lazy_path = v.dupeInner(arena) },
464+
.used = false,
465+
}) catch @panic("OOM");
466+
},
467+
[]const LazyPath => return if (maybe_value) |v| {
468+
var list = ArrayList(LazyPath).initCapacity(arena, v.len) catch @panic("OOM");
469+
for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(arena));
470+
map.put(field.name, .{
471+
.name = field.name,
472+
.value = .{ .lazy_path_list = list },
473+
.used = false,
474+
}) catch @panic("OOM");
475+
},
476+
[]const u8 => return if (maybe_value) |v| {
477+
map.put(field.name, .{
478+
.name = field.name,
479+
.value = .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") },
480+
.used = false,
481+
}) catch @panic("OOM");
482+
},
483+
[]const []const u8 => return if (maybe_value) |v| {
484+
var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
485+
for (v) |s| list.appendAssumeCapacity(arena.dupe(u8, s) catch @panic("OOM"));
486+
map.put(field.name, .{
487+
.name = field.name,
488+
.value = .{ .list = list },
489+
.used = false,
490+
}) catch @panic("OOM");
491+
},
492+
else => switch (@typeInfo(T)) {
493+
.bool => return if (maybe_value) |v| {
494+
map.put(field.name, .{
443495
.name = field.name,
444-
.value = .{ .lazy_path = v.dupeInner(allocator) },
496+
.value = .{ .scalar = if (v) "true" else "false" },
445497
.used = false,
446498
}) catch @panic("OOM");
447499
},
448-
[]const LazyPath => {
449-
var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");
450-
for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
451-
user_input_options.put(field.name, .{
500+
.@"enum", .enum_literal => return if (maybe_value) |v| {
501+
map.put(field.name, .{
452502
.name = field.name,
453-
.value = .{ .lazy_path_list = list },
503+
.value = .{ .scalar = @tagName(v) },
454504
.used = false,
455505
}) catch @panic("OOM");
456506
},
457-
[]const u8 => {
458-
user_input_options.put(field.name, .{
507+
.comptime_int, .int => return if (maybe_value) |v| {
508+
map.put(field.name, .{
459509
.name = field.name,
460-
.value = .{ .scalar = v },
510+
.value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") },
461511
.used = false,
462512
}) catch @panic("OOM");
463513
},
464-
[]const []const u8 => {
465-
var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM");
466-
list.appendSliceAssumeCapacity(v);
467-
468-
user_input_options.put(field.name, .{
514+
.comptime_float, .float => return if (maybe_value) |v| {
515+
map.put(field.name, .{
469516
.name = field.name,
470-
.value = .{ .list = list },
517+
.value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") },
471518
.used = false,
472519
}) catch @panic("OOM");
473520
},
474-
else => switch (@typeInfo(T)) {
475-
.bool => {
476-
user_input_options.put(field.name, .{
477-
.name = field.name,
478-
.value = .{ .scalar = if (v) "true" else "false" },
479-
.used = false,
480-
}) catch @panic("OOM");
481-
},
482-
.@"enum", .enum_literal => {
483-
user_input_options.put(field.name, .{
484-
.name = field.name,
485-
.value = .{ .scalar = @tagName(v) },
486-
.used = false,
487-
}) catch @panic("OOM");
521+
.pointer => |ptr_info| switch (ptr_info.size) {
522+
.one => switch (@typeInfo(ptr_info.child)) {
523+
.array => |array_info| {
524+
comptime var slice_info = ptr_info;
525+
slice_info.size = .slice;
526+
slice_info.is_const = true;
527+
slice_info.child = array_info.child;
528+
slice_info.sentinel_ptr = null;
529+
addUserInputOptionFromArg(
530+
arena,
531+
map,
532+
field,
533+
@Type(.{ .pointer = slice_info }),
534+
maybe_value orelse null,
535+
);
536+
return;
537+
},
538+
else => {},
488539
},
489-
.comptime_int, .int => {
490-
user_input_options.put(field.name, .{
491-
.name = field.name,
492-
.value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") },
493-
.used = false,
494-
}) catch @panic("OOM");
540+
.slice => switch (@typeInfo(ptr_info.child)) {
541+
.@"enum" => return if (maybe_value) |v| {
542+
var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
543+
for (v) |tag| list.appendAssumeCapacity(@tagName(tag));
544+
map.put(field.name, .{
545+
.name = field.name,
546+
.value = .{ .list = list },
547+
.used = false,
548+
}) catch @panic("OOM");
549+
},
550+
else => {
551+
comptime var slice_info = ptr_info;
552+
slice_info.is_const = true;
553+
slice_info.sentinel_ptr = null;
554+
addUserInputOptionFromArg(
555+
arena,
556+
map,
557+
field,
558+
@Type(.{ .pointer = slice_info }),
559+
maybe_value orelse null,
560+
);
561+
return;
562+
},
495563
},
496-
.comptime_float, .float => {
497-
user_input_options.put(field.name, .{
498-
.name = field.name,
499-
.value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") },
500-
.used = false,
501-
}) catch @panic("OOM");
564+
else => {},
565+
},
566+
.null => unreachable,
567+
.optional => |info| switch (@typeInfo(info.child)) {
568+
.optional => {},
569+
else => {
570+
addUserInputOptionFromArg(
571+
arena,
572+
map,
573+
field,
574+
info.child,
575+
maybe_value orelse null,
576+
);
577+
return;
502578
},
503-
else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
504579
},
505-
}
580+
else => {},
581+
},
506582
}
507-
508-
return user_input_options;
583+
@compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type));
509584
}
510585

511586
const OrderedUserValue = union(enum) {

lib/std/Io/Writer.zig

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,17 +1564,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)
15641564
}
15651565

15661566
pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
1567-
if (std.math.signbit(value)) try w.writeByte('-');
1568-
if (std.math.isNan(value)) return w.writeAll(switch (case) {
1567+
const v = switch (@TypeOf(value)) {
1568+
// comptime_float internally is a f128; this preserves precision.
1569+
comptime_float => @as(f128, value),
1570+
else => value,
1571+
};
1572+
1573+
if (std.math.signbit(v)) try w.writeByte('-');
1574+
if (std.math.isNan(v)) return w.writeAll(switch (case) {
15691575
.lower => "nan",
15701576
.upper => "NAN",
15711577
});
1572-
if (std.math.isInf(value)) return w.writeAll(switch (case) {
1578+
if (std.math.isInf(v)) return w.writeAll(switch (case) {
15731579
.lower => "inf",
15741580
.upper => "INF",
15751581
});
15761582

1577-
const T = @TypeOf(value);
1583+
const T = @TypeOf(v);
15781584
const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
15791585

15801586
const mantissa_bits = std.math.floatMantissaBits(T);
@@ -1584,7 +1590,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi
15841590
const exponent_mask = (1 << exponent_bits) - 1;
15851591
const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15861592

1587-
const as_bits: TU = @bitCast(value);
1593+
const as_bits: TU = @bitCast(v);
15881594
var mantissa = as_bits & mantissa_mask;
15891595
var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
15901596

lib/std/zig.zig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {
321321
try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));
322322
try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));
323323
}
324+
325+
pub fn format(id: BuildId, writer: *std.io.Writer) std.io.Writer.Error!void {
326+
switch (id) {
327+
.none, .fast, .uuid, .sha1, .md5 => {
328+
try writer.writeAll(@tagName(id));
329+
},
330+
.hexstring => |hs| {
331+
try writer.print("0x{x}", .{hs.toSlice()});
332+
},
333+
}
334+
}
335+
336+
test format {
337+
try std.testing.expectFmt("none", "{f}", .{@as(BuildId, .none)});
338+
try std.testing.expectFmt("fast", "{f}", .{@as(BuildId, .fast)});
339+
try std.testing.expectFmt("uuid", "{f}", .{@as(BuildId, .uuid)});
340+
try std.testing.expectFmt("sha1", "{f}", .{@as(BuildId, .sha1)});
341+
try std.testing.expectFmt("md5", "{f}", .{@as(BuildId, .md5)});
342+
try std.testing.expectFmt("0x", "{f}", .{BuildId.initHexString("")});
343+
try std.testing.expectFmt("0x1234cdef", "{f}", .{BuildId.initHexString("\x12\x34\xcd\xef")});
344+
}
324345
};
325346

326347
pub const LtoMode = enum { none, full, thin };

test/link/build.zig.zon

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.{
2-
.name = "link_test_cases",
2+
.name = .link_test_cases,
3+
.fingerprint = 0x404f657576fec9f2,
34
.version = "0.0.0",
45
.dependencies = .{
56
.bss = .{

test/standalone/build.zig.zon

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.{
22
.name = .standalone_test_cases,
3-
.fingerprint = 0xc0dbdf9c818957be,
3+
.fingerprint = 0xc0dbdf9c3b92810b,
44
.version = "0.0.0",
55
.dependencies = .{
66
.simple = .{
@@ -181,6 +181,9 @@
181181
.install_headers = .{
182182
.path = "install_headers",
183183
},
184+
.dependency_options = .{
185+
.path = "dependency_options",
186+
},
184187
.dependencyFromBuildZig = .{
185188
.path = "dependencyFromBuildZig",
186189
},

test/standalone/dependencyFromBuildZig/build.zig.zon

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.{
2-
.name = "dependencyFromBuildZig",
2+
.name = .dependencyFromBuildZig,
3+
.fingerprint = 0xfd939a1eb8169080,
34
.version = "0.0.0",
45
.dependencies = .{
56
.other = .{

test/standalone/dependencyFromBuildZig/other/build.zig.zon

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.{
2-
.name = "other",
2+
.name = .other,
3+
.fingerprint = 0xd9583520a2405f6c,
34
.version = "0.0.0",
45
.dependencies = .{},
56
.paths = .{""},

0 commit comments

Comments
 (0)