Skip to content

Commit ae2345b

Browse files
committed
zig build: add standardTargetOptions and deprecate setTarget
in favor of setTheTarget
1 parent 0389462 commit ae2345b

File tree

1 file changed

+200
-40
lines changed

1 file changed

+200
-40
lines changed

std/build.zig

Lines changed: 200 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,12 @@ pub const Builder = struct {
380380
switch (builtin.os) {
381381
.windows => {},
382382
else => {
383-
const triple = (CrossTarget{
384-
.arch = builtin.arch,
385-
.os = builtin.os,
386-
.abi = builtin.abi,
383+
const triple = (Target{
384+
.Cross = CrossTarget{
385+
.arch = builtin.arch,
386+
.os = builtin.os,
387+
.abi = builtin.abi,
388+
},
387389
}).linuxTriple(self.allocator);
388390

389391
// TODO: $ ld --verbose | grep SEARCH_DIR
@@ -507,6 +509,26 @@ pub const Builder = struct {
507509
return mode;
508510
}
509511

512+
/// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets.
513+
pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target {
514+
if (supported_targets) |target_list| {
515+
// TODO detect multiple args and emit an error message
516+
// there's probably a better way to collect the target
517+
for (target_list) |targ| {
518+
const targ_str = targ.zigTriple(self.allocator) catch unreachable;
519+
const targ_desc = targ.allocDescription(self.allocator) catch unreachable;
520+
const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false;
521+
if (this_targ_opt) {
522+
return targ;
523+
}
524+
}
525+
return Target.Native;
526+
} else {
527+
const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native;
528+
return Target.parse(target_str) catch unreachable; // TODO better error message for bad target
529+
}
530+
}
531+
510532
pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
511533
const gop = try self.user_input_options.getOrPut(name);
512534
if (!gop.found_existing) {
@@ -858,67 +880,193 @@ pub const Builder = struct {
858880
}
859881
};
860882

861-
const Version = struct {
883+
pub const Version = struct {
862884
major: u32,
863885
minor: u32,
864886
patch: u32,
865887
};
866888

867-
const CrossTarget = struct {
889+
pub const CrossTarget = struct {
868890
arch: builtin.Arch,
869891
os: builtin.Os,
870892
abi: builtin.Abi,
893+
};
894+
895+
pub const Target = union(enum) {
896+
Native: void,
897+
Cross: CrossTarget,
871898

872-
pub fn zigTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 {
899+
pub fn zigTriple(self: Target, allocator: *Allocator) ![]u8 {
873900
return std.fmt.allocPrint(
874901
allocator,
875902
"{}{}-{}-{}",
876-
@tagName(cross_target.arch),
877-
Target.archSubArchName(cross_target.arch),
878-
@tagName(cross_target.os),
879-
@tagName(cross_target.abi),
880-
) catch unreachable;
903+
@tagName(self.getArch()),
904+
Target.archSubArchName(self.getArch()),
905+
@tagName(self.getOs()),
906+
@tagName(self.getAbi()),
907+
);
908+
}
909+
910+
pub fn allocDescription(self: Target, allocator: *Allocator) ![]u8 {
911+
// TODO is there anything else worthy of the description that is not
912+
// already captured in the triple?
913+
return self.zigTriple(allocator);
881914
}
882915

883-
pub fn linuxTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 {
916+
pub fn zigTripleNoSubArch(self: Target, allocator: *Allocator) ![]u8 {
884917
return std.fmt.allocPrint(
885918
allocator,
886919
"{}-{}-{}",
887-
@tagName(cross_target.arch),
888-
@tagName(cross_target.os),
889-
@tagName(cross_target.abi),
890-
) catch unreachable;
920+
@tagName(self.getArch()),
921+
@tagName(self.getOs()),
922+
@tagName(self.getAbi()),
923+
);
891924
}
892-
};
893925

894-
pub const Target = union(enum) {
895-
Native: void,
896-
Cross: CrossTarget,
926+
pub fn linuxTriple(self: Target, allocator: *Allocator) ![]u8 {
927+
return std.fmt.allocPrint(
928+
allocator,
929+
"{}-{}-{}",
930+
@tagName(self.getArch()),
931+
@tagName(self.getOs()),
932+
@tagName(self.getAbi()),
933+
);
934+
}
935+
936+
pub fn parse(text: []const u8) !Target {
937+
var it = mem.separate(text, "-");
938+
const arch_name = it.next() orelse return error.MissingArchitecture;
939+
const os_name = it.next() orelse return error.MissingOperatingSystem;
940+
const abi_name = it.next();
941+
942+
var cross = CrossTarget{
943+
.arch = try parseArchSub(arch_name),
944+
.os = try parseOs(os_name),
945+
.abi = undefined,
946+
};
947+
cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os);
948+
return Target{ .Cross = cross };
949+
}
950+
951+
pub fn defaultAbi(arch: builtin.Arch, target_os: builtin.Os) builtin.Abi {
952+
switch (arch) {
953+
.wasm32, .wasm64 => return .musl,
954+
else => {},
955+
}
956+
switch (target_os) {
957+
.freestanding,
958+
.ananas,
959+
.cloudabi,
960+
.dragonfly,
961+
.lv2,
962+
.solaris,
963+
.haiku,
964+
.minix,
965+
.rtems,
966+
.nacl,
967+
.cnk,
968+
.aix,
969+
.cuda,
970+
.nvcl,
971+
.amdhsa,
972+
.ps4,
973+
.elfiamcu,
974+
.mesa3d,
975+
.contiki,
976+
.amdpal,
977+
.zen,
978+
.hermit,
979+
=> return .eabi,
980+
.openbsd,
981+
.macosx,
982+
.freebsd,
983+
.ios,
984+
.tvos,
985+
.watchos,
986+
.fuchsia,
987+
.kfreebsd,
988+
.netbsd,
989+
.hurd,
990+
=> return .gnu,
991+
.windows,
992+
.uefi,
993+
=> return .msvc,
994+
.linux,
995+
.wasi,
996+
=> return .musl,
997+
}
998+
}
999+
1000+
pub const ParseArchSubError = error{
1001+
UnknownArchitecture,
1002+
UnknownSubArchitecture,
1003+
};
1004+
1005+
pub fn parseArchSub(text: []const u8) ParseArchSubError!builtin.Arch {
1006+
const info = @typeInfo(builtin.Arch);
1007+
inline for (info.Union.fields) |field| {
1008+
if (mem.eql(u8, text, field.name)) {
1009+
if (field.field_type == void) {
1010+
return (builtin.Arch)(@field(builtin.Arch, field.name));
1011+
} else {
1012+
const sub_info = @typeInfo(field.field_type);
1013+
inline for (sub_info.Enum.fields) |sub_field| {
1014+
const combined = field.name ++ sub_field.name;
1015+
if (mem.eql(u8, text, combined)) {
1016+
return @unionInit(builtin.Arch, field.name, @field(field.field_type, sub_field.name));
1017+
}
1018+
}
1019+
return error.UnknownSubArchitecture;
1020+
}
1021+
}
1022+
}
1023+
return error.UnknownArchitecture;
1024+
}
1025+
1026+
pub fn parseOs(text: []const u8) !builtin.Os {
1027+
const info = @typeInfo(builtin.Os);
1028+
inline for (info.Enum.fields) |field| {
1029+
if (mem.eql(u8, text, field.name)) {
1030+
return @field(builtin.Os, field.name);
1031+
}
1032+
}
1033+
return error.UnknownOperatingSystem;
1034+
}
1035+
1036+
pub fn parseAbi(text: []const u8) !builtin.Abi {
1037+
const info = @typeInfo(builtin.Abi);
1038+
inline for (info.Enum.fields) |field| {
1039+
if (mem.eql(u8, text, field.name)) {
1040+
return @field(builtin.Abi, field.name);
1041+
}
1042+
}
1043+
return error.UnknownApplicationBinaryInterface;
1044+
}
8971045

8981046
fn archSubArchName(arch: builtin.Arch) []const u8 {
8991047
return switch (arch) {
900-
builtin.Arch.arm => |sub| @tagName(sub),
901-
builtin.Arch.armeb => |sub| @tagName(sub),
902-
builtin.Arch.thumb => |sub| @tagName(sub),
903-
builtin.Arch.thumbeb => |sub| @tagName(sub),
904-
builtin.Arch.aarch64 => |sub| @tagName(sub),
905-
builtin.Arch.aarch64_be => |sub| @tagName(sub),
906-
builtin.Arch.kalimba => |sub| @tagName(sub),
1048+
.arm => |sub| @tagName(sub),
1049+
.armeb => |sub| @tagName(sub),
1050+
.thumb => |sub| @tagName(sub),
1051+
.thumbeb => |sub| @tagName(sub),
1052+
.aarch64 => |sub| @tagName(sub),
1053+
.aarch64_be => |sub| @tagName(sub),
1054+
.kalimba => |sub| @tagName(sub),
9071055
else => "",
9081056
};
9091057
}
9101058

9111059
pub fn subArchName(self: Target) []const u8 {
9121060
switch (self) {
913-
Target.Native => return archSubArchName(builtin.arch),
914-
Target.Cross => |cross| return archSubArchName(cross.arch),
1061+
.Native => return archSubArchName(builtin.arch),
1062+
.Cross => |cross| return archSubArchName(cross.arch),
9151063
}
9161064
}
9171065

9181066
pub fn oFileExt(self: Target) []const u8 {
9191067
const abi = switch (self) {
920-
Target.Native => builtin.abi,
921-
Target.Cross => |t| t.abi,
1068+
.Native => builtin.abi,
1069+
.Cross => |t| t.abi,
9221070
};
9231071
return switch (abi) {
9241072
builtin.Abi.msvc => ".obj",
@@ -942,15 +1090,22 @@ pub const Target = union(enum) {
9421090

9431091
pub fn getOs(self: Target) builtin.Os {
9441092
return switch (self) {
945-
Target.Native => builtin.os,
946-
Target.Cross => |t| t.os,
1093+
.Native => builtin.os,
1094+
.Cross => |t| t.os,
9471095
};
9481096
}
9491097

9501098
pub fn getArch(self: Target) builtin.Arch {
9511099
switch (self) {
952-
Target.Native => return builtin.arch,
953-
Target.Cross => |t| return t.arch,
1100+
.Native => return builtin.arch,
1101+
.Cross => |t| return t.arch,
1102+
}
1103+
}
1104+
1105+
pub fn getAbi(self: Target) builtin.Abi {
1106+
switch (self) {
1107+
.Native => return builtin.abi,
1108+
.Cross => |t| return t.abi,
9541109
}
9551110
}
9561111

@@ -1206,19 +1361,24 @@ pub const LibExeObjStep = struct {
12061361
}
12071362
}
12081363

1364+
/// Deprecated. Use `setTheTarget`.
12091365
pub fn setTarget(
12101366
self: *LibExeObjStep,
12111367
target_arch: builtin.Arch,
12121368
target_os: builtin.Os,
12131369
target_abi: builtin.Abi,
12141370
) void {
1215-
self.target = Target{
1371+
return self.setTheTarget(Target{
12161372
.Cross = CrossTarget{
12171373
.arch = target_arch,
12181374
.os = target_os,
12191375
.abi = target_abi,
12201376
},
1221-
};
1377+
});
1378+
}
1379+
1380+
pub fn setTheTarget(self: *LibExeObjStep, target: Target) void {
1381+
self.target = target;
12221382
self.computeOutFileNames();
12231383
}
12241384

@@ -1595,9 +1755,9 @@ pub const LibExeObjStep = struct {
15951755

15961756
switch (self.target) {
15971757
Target.Native => {},
1598-
Target.Cross => |cross_target| {
1758+
Target.Cross => {
15991759
try zig_args.append("-target");
1600-
try zig_args.append(cross_target.zigTriple(builder.allocator));
1760+
try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
16011761
},
16021762
}
16031763

0 commit comments

Comments
 (0)