Skip to content

Commit

Permalink
zig build: add standardTargetOptions and deprecate setTarget
Browse files Browse the repository at this point in the history
in favor of setTheTarget
  • Loading branch information
andrewrk committed Jul 9, 2019
1 parent 0389462 commit ae2345b
Showing 1 changed file with 200 additions and 40 deletions.
240 changes: 200 additions & 40 deletions std/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,12 @@ pub const Builder = struct {
switch (builtin.os) {
.windows => {},
else => {
const triple = (CrossTarget{
.arch = builtin.arch,
.os = builtin.os,
.abi = builtin.abi,
const triple = (Target{
.Cross = CrossTarget{
.arch = builtin.arch,
.os = builtin.os,
.abi = builtin.abi,
},
}).linuxTriple(self.allocator);

// TODO: $ ld --verbose | grep SEARCH_DIR
Expand Down Expand Up @@ -507,6 +509,26 @@ pub const Builder = struct {
return mode;
}

/// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets.
pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target {
if (supported_targets) |target_list| {
// TODO detect multiple args and emit an error message
// there's probably a better way to collect the target
for (target_list) |targ| {
const targ_str = targ.zigTriple(self.allocator) catch unreachable;
const targ_desc = targ.allocDescription(self.allocator) catch unreachable;
const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false;
if (this_targ_opt) {
return targ;
}
}
return Target.Native;
} else {
const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native;
return Target.parse(target_str) catch unreachable; // TODO better error message for bad target
}
}

pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
const gop = try self.user_input_options.getOrPut(name);
if (!gop.found_existing) {
Expand Down Expand Up @@ -858,67 +880,193 @@ pub const Builder = struct {
}
};

const Version = struct {
pub const Version = struct {
major: u32,
minor: u32,
patch: u32,
};

const CrossTarget = struct {
pub const CrossTarget = struct {
arch: builtin.Arch,
os: builtin.Os,
abi: builtin.Abi,
};

pub const Target = union(enum) {
Native: void,
Cross: CrossTarget,

pub fn zigTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 {
pub fn zigTriple(self: Target, allocator: *Allocator) ![]u8 {
return std.fmt.allocPrint(
allocator,
"{}{}-{}-{}",
@tagName(cross_target.arch),
Target.archSubArchName(cross_target.arch),
@tagName(cross_target.os),
@tagName(cross_target.abi),
) catch unreachable;
@tagName(self.getArch()),
Target.archSubArchName(self.getArch()),
@tagName(self.getOs()),
@tagName(self.getAbi()),
);
}

pub fn allocDescription(self: Target, allocator: *Allocator) ![]u8 {
// TODO is there anything else worthy of the description that is not
// already captured in the triple?
return self.zigTriple(allocator);
}

pub fn linuxTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 {
pub fn zigTripleNoSubArch(self: Target, allocator: *Allocator) ![]u8 {
return std.fmt.allocPrint(
allocator,
"{}-{}-{}",
@tagName(cross_target.arch),
@tagName(cross_target.os),
@tagName(cross_target.abi),
) catch unreachable;
@tagName(self.getArch()),
@tagName(self.getOs()),
@tagName(self.getAbi()),
);
}
};

pub const Target = union(enum) {
Native: void,
Cross: CrossTarget,
pub fn linuxTriple(self: Target, allocator: *Allocator) ![]u8 {
return std.fmt.allocPrint(
allocator,
"{}-{}-{}",
@tagName(self.getArch()),
@tagName(self.getOs()),
@tagName(self.getAbi()),
);
}

pub fn parse(text: []const u8) !Target {
var it = mem.separate(text, "-");
const arch_name = it.next() orelse return error.MissingArchitecture;
const os_name = it.next() orelse return error.MissingOperatingSystem;
const abi_name = it.next();

var cross = CrossTarget{
.arch = try parseArchSub(arch_name),
.os = try parseOs(os_name),
.abi = undefined,
};
cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os);
return Target{ .Cross = cross };
}

pub fn defaultAbi(arch: builtin.Arch, target_os: builtin.Os) builtin.Abi {
switch (arch) {
.wasm32, .wasm64 => return .musl,
else => {},
}
switch (target_os) {
.freestanding,
.ananas,
.cloudabi,
.dragonfly,
.lv2,
.solaris,
.haiku,
.minix,
.rtems,
.nacl,
.cnk,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.zen,
.hermit,
=> return .eabi,
.openbsd,
.macosx,
.freebsd,
.ios,
.tvos,
.watchos,
.fuchsia,
.kfreebsd,
.netbsd,
.hurd,
=> return .gnu,
.windows,
.uefi,
=> return .msvc,
.linux,
.wasi,
=> return .musl,
}
}

pub const ParseArchSubError = error{
UnknownArchitecture,
UnknownSubArchitecture,
};

pub fn parseArchSub(text: []const u8) ParseArchSubError!builtin.Arch {
const info = @typeInfo(builtin.Arch);
inline for (info.Union.fields) |field| {
if (mem.eql(u8, text, field.name)) {
if (field.field_type == void) {
return (builtin.Arch)(@field(builtin.Arch, field.name));
} else {
const sub_info = @typeInfo(field.field_type);
inline for (sub_info.Enum.fields) |sub_field| {
const combined = field.name ++ sub_field.name;
if (mem.eql(u8, text, combined)) {
return @unionInit(builtin.Arch, field.name, @field(field.field_type, sub_field.name));
}
}
return error.UnknownSubArchitecture;
}
}
}
return error.UnknownArchitecture;
}

pub fn parseOs(text: []const u8) !builtin.Os {
const info = @typeInfo(builtin.Os);
inline for (info.Enum.fields) |field| {
if (mem.eql(u8, text, field.name)) {
return @field(builtin.Os, field.name);
}
}
return error.UnknownOperatingSystem;
}

pub fn parseAbi(text: []const u8) !builtin.Abi {
const info = @typeInfo(builtin.Abi);
inline for (info.Enum.fields) |field| {
if (mem.eql(u8, text, field.name)) {
return @field(builtin.Abi, field.name);
}
}
return error.UnknownApplicationBinaryInterface;
}

fn archSubArchName(arch: builtin.Arch) []const u8 {
return switch (arch) {
builtin.Arch.arm => |sub| @tagName(sub),
builtin.Arch.armeb => |sub| @tagName(sub),
builtin.Arch.thumb => |sub| @tagName(sub),
builtin.Arch.thumbeb => |sub| @tagName(sub),
builtin.Arch.aarch64 => |sub| @tagName(sub),
builtin.Arch.aarch64_be => |sub| @tagName(sub),
builtin.Arch.kalimba => |sub| @tagName(sub),
.arm => |sub| @tagName(sub),
.armeb => |sub| @tagName(sub),
.thumb => |sub| @tagName(sub),
.thumbeb => |sub| @tagName(sub),
.aarch64 => |sub| @tagName(sub),
.aarch64_be => |sub| @tagName(sub),
.kalimba => |sub| @tagName(sub),
else => "",
};
}

pub fn subArchName(self: Target) []const u8 {
switch (self) {
Target.Native => return archSubArchName(builtin.arch),
Target.Cross => |cross| return archSubArchName(cross.arch),
.Native => return archSubArchName(builtin.arch),
.Cross => |cross| return archSubArchName(cross.arch),
}
}

pub fn oFileExt(self: Target) []const u8 {
const abi = switch (self) {
Target.Native => builtin.abi,
Target.Cross => |t| t.abi,
.Native => builtin.abi,
.Cross => |t| t.abi,
};
return switch (abi) {
builtin.Abi.msvc => ".obj",
Expand All @@ -942,15 +1090,22 @@ pub const Target = union(enum) {

pub fn getOs(self: Target) builtin.Os {
return switch (self) {
Target.Native => builtin.os,
Target.Cross => |t| t.os,
.Native => builtin.os,
.Cross => |t| t.os,
};
}

pub fn getArch(self: Target) builtin.Arch {
switch (self) {
Target.Native => return builtin.arch,
Target.Cross => |t| return t.arch,
.Native => return builtin.arch,
.Cross => |t| return t.arch,
}
}

pub fn getAbi(self: Target) builtin.Abi {
switch (self) {
.Native => return builtin.abi,
.Cross => |t| return t.abi,
}
}

Expand Down Expand Up @@ -1206,19 +1361,24 @@ pub const LibExeObjStep = struct {
}
}

/// Deprecated. Use `setTheTarget`.
pub fn setTarget(
self: *LibExeObjStep,
target_arch: builtin.Arch,
target_os: builtin.Os,
target_abi: builtin.Abi,
) void {
self.target = Target{
return self.setTheTarget(Target{
.Cross = CrossTarget{
.arch = target_arch,
.os = target_os,
.abi = target_abi,
},
};
});
}

pub fn setTheTarget(self: *LibExeObjStep, target: Target) void {
self.target = target;
self.computeOutFileNames();
}

Expand Down Expand Up @@ -1595,9 +1755,9 @@ pub const LibExeObjStep = struct {

switch (self.target) {
Target.Native => {},
Target.Cross => |cross_target| {
Target.Cross => {
try zig_args.append("-target");
try zig_args.append(cross_target.zigTriple(builder.allocator));
try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
},
}

Expand Down

0 comments on commit ae2345b

Please sign in to comment.