authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-26 01:18:23-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-28 14:51:54-05:00
logdbe4d72bcfb20fc43713781679a0d23aea0a17d9
tree7ba5a5bc8683a089615d18ca9e5dcc73a2f0c899
parent87b9e744dda465ecf7663e2463066ea26a44e63a
signaturelock-open Commit is signed but in an unrecognized format.

separate std.Target and std.zig.CrossTarget

Zig now supports a more fine-grained sense of what is native and what is not. Some examples: This is now allowed: -target native Different OS but native CPU, default Windows C ABI: -target native-windows This could be useful for example when running in Wine. Different CPU but native OS, native C ABI. -target x86_64-native -mcpu=skylake Different C ABI but otherwise native target: -target native-native-musl -target native-native-gnu Lots of breaking changes to related std lib APIs. Calls to getOs() will need to be changed to getOsTag(). Calls to getArch() will need to be changed to getCpuArch(). Usage of Target.Cross and Target.Native need to be updated to use CrossTarget API. `std.build.Builder.standardTargetOptions` is changed to accept its parameters as a struct with default values. It now has the ability to specify a whitelist of targets allowed, as well as the default target. Rather than two different ways of collecting the target, it's now always a string that is validated, and prints helpful diagnostics for invalid targets. This feature should now be actually useful, and contributions welcome to further improve the user experience. `std.build.LibExeObjStep.setTheTarget` is removed. `std.build.LibExeObjStep.setTarget` is updated to take a CrossTarget parameter. `std.build.LibExeObjStep.setTargetGLibC` is removed. glibc versions are handled in the CrossTarget API and can be specified with the `-target` triple. `std.builtin.Version` gains a `format` method.

14 files changed, 1286 insertions(+), 937 deletions(-)

build.zig+1-1
......@@ -298,7 +298,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
298298 }
299299 dependOnLib(b, exe, ctx.llvm);
300300
301 if (exe.target.getOs() == .linux) {
301 if (exe.target.getOsTag() == .linux) {
302302 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
303303 \\Unable to determine path to libstdc++.a
304304 \\On Fedora, install libstdc++-static and try again.
doc/docgen.zig+2-2
......@@ -10,8 +10,8 @@ const testing = std.testing;
1010
1111const max_doc_file_size = 10 * 1024 * 1024;
1212
13const exe_ext = @as(std.build.Target, std.build.Target.Native).exeFileExt();
14const obj_ext = @as(std.build.Target, std.build.Target.Native).oFileExt();
13const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();
14const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt();
1515const tmp_dir_name = "docgen_tmp";
1616const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1717
lib/std/build.zig+108-190
......@@ -1,5 +1,5 @@
11const std = @import("std.zig");
2const builtin = @import("builtin");
2const builtin = std.builtin;
33const io = std.io;
44const fs = std.fs;
55const mem = std.mem;
......@@ -15,6 +15,7 @@ const BufSet = std.BufSet;
1515const BufMap = std.BufMap;
1616const fmt_lib = std.fmt;
1717const File = std.fs.File;
18const CrossTarget = std.zig.CrossTarget;
1819
1920pub const FmtStep = @import("build/fmt.zig").FmtStep;
2021pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;
......@@ -521,24 +522,77 @@ pub const Builder = struct {
521522 return mode;
522523 }
523524
524 /// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets.
525 pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target {
526 if (supported_targets) |target_list| {
527 // TODO detect multiple args and emit an error message
528 // there's probably a better way to collect the target
529 for (target_list) |targ| {
530 const targ_str = targ.zigTriple(self.allocator) catch unreachable;
531 const targ_desc = targ.allocDescription(self.allocator) catch unreachable;
532 const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false;
533 if (this_targ_opt) {
534 return targ;
525 pub const StandardTargetOptionsArgs = struct {
526 whitelist: ?[]const CrossTarget = null,
527
528 default_target: CrossTarget = .{},
529 };
530
531 /// Exposes standard `zig build` options for choosing a target.
532 pub fn standardTargetOptions(self: *Builder, args: StandardTargetOptionsArgs) CrossTarget {
533 const triple = self.option(
534 []const u8,
535 "target",
536 "The Arch, OS, and ABI to build for.",
537 ) orelse return args.default_target;
538
539 // TODO add cpu and features as part of the target triple
540
541 var diags: std.Target.ParseOptions.Diagnostics = .{};
542 const selected_target = CrossTarget.parse(.{
543 .arch_os_abi = triple,
544 .diagnostics = &diags,
545 }) catch |err| switch (err) {
546 error.UnknownCpuModel => {
547 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
548 diags.cpu_name.?,
549 @tagName(diags.arch.?),
550 });
551 for (diags.arch.?.allCpuModels()) |cpu| {
552 std.debug.warn(" {}\n", .{cpu.name});
553 }
554 process.exit(1);
555 },
556 error.UnknownCpuFeature => {
557 std.debug.warn(
558 \\Unknown CPU feature: '{}'
559 \\Available CPU features for architecture '{}':
560 \\
561 , .{
562 diags.unknown_feature_name,
563 @tagName(diags.arch.?),
564 });
565 for (diags.arch.?.allFeaturesList()) |feature| {
566 std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
567 }
568 process.exit(1);
569 },
570 else => |e| return e,
571 };
572
573 const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable;
574
575 if (args.whitelist) |list| whitelist_check: {
576 // Make sure it's a match of one of the list.
577 for (list) |t| {
578 const t_triple = t.zigTriple(self.allocator) catch unreachable;
579 if (mem.eql(u8, t_triple, selected_canonicalized_triple)) {
580 break :whitelist_check;
535581 }
536582 }
537 return Target.Native;
538 } else {
539 const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native;
540 return Target.parse(.{ .arch_os_abi = target_str }) catch unreachable; // TODO better error message for bad target
583 std.debug.warn("Chosen target '{}' does not match one of the supported targets:\n", .{
584 selected_canonicalized_triple,
585 });
586 for (list) |t| {
587 const t_triple = t.zigTriple(self.allocator) catch unreachable;
588 std.debug.warn(" {}\n", t_triple);
589 }
590 // TODO instead of process exit, return error and have a zig build flag implemented by
591 // the build runner that turns process exits into error return traces
592 process.exit(1);
541593 }
594
595 return selected_target;
542596 }
543597
544598 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
......@@ -796,7 +850,7 @@ pub const Builder = struct {
796850
797851 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
798852 // TODO report error for ambiguous situations
799 const exe_extension = (Target{ .Native = {} }).exeFileExt();
853 const exe_extension = @as(CrossTarget, .{}).exeFileExt();
800854 for (self.search_prefixes.toSliceConst()) |search_prefix| {
801855 for (names) |name| {
802856 if (fs.path.isAbsolute(name)) {
......@@ -978,111 +1032,11 @@ test "builder.findProgram compiles" {
9781032 _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
9791033}
9801034
981/// Deprecated. Use `builtin.Version`.
1035/// Deprecated. Use `std.builtin.Version`.
9821036pub const Version = builtin.Version;
9831037
984/// Deprecated. Use `std.Target`.
985pub const CrossTarget = std.Target;
986
987/// Wraps `std.Target` so that it can be annotated as "the native target" or an explicitly specified target.
988pub const Target = union(enum) {
989 Native,
990 Cross: std.Target,
991
992 pub fn getTarget(self: Target) std.Target {
993 return switch (self) {
994 .Native => std.Target.current,
995 .Cross => |t| t,
996 };
997 }
998
999 pub fn getOs(self: Target) std.Target.Os.Tag {
1000 return self.getTarget().os.tag;
1001 }
1002
1003 pub fn getCpu(self: Target) std.Target.Cpu {
1004 return self.getTarget().cpu;
1005 }
1006
1007 pub fn getAbi(self: Target) std.Target.Abi {
1008 return self.getTarget().abi;
1009 }
1010
1011 pub fn getArch(self: Target) std.Target.Cpu.Arch {
1012 return self.getCpu().arch;
1013 }
1014
1015 pub fn isFreeBSD(self: Target) bool {
1016 return self.getTarget().os.tag == .freebsd;
1017 }
1018
1019 pub fn isDarwin(self: Target) bool {
1020 return self.getTarget().os.tag.isDarwin();
1021 }
1022
1023 pub fn isNetBSD(self: Target) bool {
1024 return self.getTarget().os.tag == .netbsd;
1025 }
1026
1027 pub fn isUefi(self: Target) bool {
1028 return self.getTarget().os.tag == .uefi;
1029 }
1030
1031 pub fn isDragonFlyBSD(self: Target) bool {
1032 return self.getTarget().os.tag == .dragonfly;
1033 }
1034
1035 pub fn isLinux(self: Target) bool {
1036 return self.getTarget().os.tag == .linux;
1037 }
1038
1039 pub fn isWindows(self: Target) bool {
1040 return self.getTarget().os.tag == .windows;
1041 }
1042
1043 pub fn oFileExt(self: Target) []const u8 {
1044 return self.getTarget().oFileExt();
1045 }
1046
1047 pub fn exeFileExt(self: Target) []const u8 {
1048 return self.getTarget().exeFileExt();
1049 }
1050
1051 pub fn staticLibSuffix(self: Target) []const u8 {
1052 return self.getTarget().staticLibSuffix();
1053 }
1054
1055 pub fn libPrefix(self: Target) []const u8 {
1056 return self.getTarget().libPrefix();
1057 }
1058
1059 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
1060 return self.getTarget().zigTriple(allocator);
1061 }
1062
1063 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
1064 return self.getTarget().linuxTriple(allocator);
1065 }
1066
1067 pub fn wantSharedLibSymLinks(self: Target) bool {
1068 return self.getTarget().wantSharedLibSymLinks();
1069 }
1070
1071 pub fn vcpkgTriplet(self: Target, allocator: *mem.Allocator, linkage: std.build.VcpkgLinkage) ![]const u8 {
1072 return self.getTarget().vcpkgTriplet(allocator, linkage);
1073 }
1074
1075 pub fn getExternalExecutor(self: Target) std.Target.Executor {
1076 switch (self) {
1077 .Native => return .native,
1078 .Cross => |t| return t.getExternalExecutor(),
1079 }
1080 }
1081
1082 pub fn isGnuLibC(self: Target) bool {
1083 return self.getTarget().isGnuLibC();
1084 }
1085};
1038/// Deprecated. Use `std.zig.CrossTarget`.
1039pub const Target = std.zig.CrossTarget;
10861040
10871041pub const Pkg = struct {
10881042 name: []const u8,
......@@ -1135,7 +1089,7 @@ pub const LibExeObjStep = struct {
11351089 step: Step,
11361090 builder: *Builder,
11371091 name: []const u8,
1138 target: Target,
1092 target: CrossTarget = CrossTarget{},
11391093 linker_script: ?[]const u8 = null,
11401094 version_script: ?[]const u8 = null,
11411095 out_filename: []const u8,
......@@ -1188,7 +1142,6 @@ pub const LibExeObjStep = struct {
11881142 install_step: ?*InstallArtifactStep,
11891143
11901144 libc_file: ?[]const u8 = null,
1191 target_glibc: ?Version = null,
11921145
11931146 valgrind_support: ?bool = null,
11941147
......@@ -1288,7 +1241,6 @@ pub const LibExeObjStep = struct {
12881241 .kind = kind,
12891242 .root_src = root_src,
12901243 .name = name,
1291 .target = Target.Native,
12921244 .frameworks = BufSet.init(builder.allocator),
12931245 .step = Step.init(name, builder.allocator, make),
12941246 .version = ver,
......@@ -1379,36 +1331,11 @@ pub const LibExeObjStep = struct {
13791331 }
13801332 }
13811333
1382 /// Deprecated. Use `setTheTarget`.
1383 pub fn setTarget(
1384 self: *LibExeObjStep,
1385 target_arch: builtin.Arch,
1386 target_os: builtin.Os,
1387 target_abi: builtin.Abi,
1388 ) void {
1389 return self.setTheTarget(Target{
1390 .Cross = CrossTarget{
1391 .arch = target_arch,
1392 .os = target_os,
1393 .abi = target_abi,
1394 .cpu_features = target_arch.getBaselineCpuFeatures(),
1395 },
1396 });
1397 }
1398
1399 pub fn setTheTarget(self: *LibExeObjStep, target: Target) void {
1334 pub fn setTarget(self: *LibExeObjStep, target: CrossTarget) void {
14001335 self.target = target;
14011336 self.computeOutFileNames();
14021337 }
14031338
1404 pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void {
1405 self.target_glibc = Version{
1406 .major = major,
1407 .minor = minor,
1408 .patch = patch,
1409 };
1410 }
1411
14121339 pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
14131340 self.output_dir = self.builder.dupePath(dir);
14141341 }
......@@ -2002,47 +1929,41 @@ pub const LibExeObjStep = struct {
20021929 try zig_args.append(@tagName(self.code_model));
20031930 }
20041931
2005 switch (self.target) {
2006 .Native => {},
2007 .Cross => |cross| {
2008 try zig_args.append("-target");
2009 try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
1932 if (!self.target.isNative()) {
1933 try zig_args.append("-target");
1934 try zig_args.append(try self.target.zigTriple(builder.allocator));
20101935
2011 const all_features = self.target.getArch().allFeaturesList();
2012 var populated_cpu_features = cross.cpu.model.features;
2013 populated_cpu_features.populateDependencies(all_features);
1936 // TODO this logic can disappear if cpu model + features becomes part of the target triple
1937 const cross = self.target.toTarget();
1938 const all_features = cross.cpu.arch.allFeaturesList();
1939 var populated_cpu_features = cross.cpu.model.features;
1940 populated_cpu_features.populateDependencies(all_features);
20141941
2015 if (populated_cpu_features.eql(cross.cpu.features)) {
2016 // The CPU name alone is sufficient.
2017 // If it is the baseline CPU, no command line args are required.
2018 if (cross.cpu.model != std.Target.Cpu.baseline(self.target.getArch()).model) {
2019 try zig_args.append("-mcpu");
2020 try zig_args.append(cross.cpu.model.name);
2021 }
2022 } else {
2023 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
2024 try mcpu_buffer.append(cross.cpu.model.name);
2025
2026 for (all_features) |feature, i_usize| {
2027 const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
2028 const in_cpu_set = populated_cpu_features.isEnabled(i);
2029 const in_actual_set = cross.cpu.features.isEnabled(i);
2030 if (in_cpu_set and !in_actual_set) {
2031 try mcpu_buffer.appendByte('-');
2032 try mcpu_buffer.append(feature.name);
2033 } else if (!in_cpu_set and in_actual_set) {
2034 try mcpu_buffer.appendByte('+');
2035 try mcpu_buffer.append(feature.name);
2036 }
1942 if (populated_cpu_features.eql(cross.cpu.features)) {
1943 // The CPU name alone is sufficient.
1944 // If it is the baseline CPU, no command line args are required.
1945 if (cross.cpu.model != std.Target.Cpu.baseline(cross.cpu.arch).model) {
1946 try zig_args.append("-mcpu");
1947 try zig_args.append(cross.cpu.model.name);
1948 }
1949 } else {
1950 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
1951 try mcpu_buffer.append(cross.cpu.model.name);
1952
1953 for (all_features) |feature, i_usize| {
1954 const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
1955 const in_cpu_set = populated_cpu_features.isEnabled(i);
1956 const in_actual_set = cross.cpu.features.isEnabled(i);
1957 if (in_cpu_set and !in_actual_set) {
1958 try mcpu_buffer.appendByte('-');
1959 try mcpu_buffer.append(feature.name);
1960 } else if (!in_cpu_set and in_actual_set) {
1961 try mcpu_buffer.appendByte('+');
1962 try mcpu_buffer.append(feature.name);
20371963 }
2038 try zig_args.append(mcpu_buffer.toSliceConst());
20391964 }
2040 },
2041 }
2042
2043 if (self.target_glibc) |ver| {
2044 try zig_args.append("-target-glibc");
2045 try zig_args.append(builder.fmt("{}.{}.{}", .{ ver.major, ver.minor, ver.patch }));
1965 try zig_args.append(mcpu_buffer.toSliceConst());
1966 }
20461967 }
20471968
20481969 if (self.linker_script) |linker_script| {
......@@ -2517,10 +2438,7 @@ const VcpkgRootStatus = enum {
25172438 Found,
25182439};
25192440
2520pub const VcpkgLinkage = enum {
2521 Static,
2522 Dynamic,
2523};
2441pub const VcpkgLinkage = std.builtin.LinkMode;
25242442
25252443pub const InstallDir = enum {
25262444 Prefix,
lib/std/build/translate_c.zig+6-8
......@@ -7,6 +7,7 @@ const LibExeObjStep = build.LibExeObjStep;
77const CheckFileStep = build.CheckFileStep;
88const fs = std.fs;
99const mem = std.mem;
10const CrossTarget = std.zig.CrossTarget;
1011
1112pub const TranslateCStep = struct {
1213 step: Step,
......@@ -14,7 +15,7 @@ pub const TranslateCStep = struct {
1415 source: build.FileSource,
1516 output_dir: ?[]const u8,
1617 out_basename: []const u8,
17 target: build.Target = .Native,
18 target: CrossTarget = CrossTarget{},
1819
1920 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
2021 const self = builder.allocator.create(TranslateCStep) catch unreachable;
......@@ -39,7 +40,7 @@ pub const TranslateCStep = struct {
3940 ) catch unreachable;
4041 }
4142
42 pub fn setTarget(self: *TranslateCStep, target: build.Target) void {
43 pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
4344 self.target = target;
4445 }
4546
......@@ -63,12 +64,9 @@ pub const TranslateCStep = struct {
6364 try argv_list.append("--cache");
6465 try argv_list.append("on");
6566
66 switch (self.target) {
67 .Native => {},
68 .Cross => {
69 try argv_list.append("-target");
70 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
71 },
67 if (!self.target.isNative()) {
68 try argv_list.append("-target");
69 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
7270 }
7371
7472 try argv_list.append(self.source.getPath(self.builder));
lib/std/builtin.zig+23
......@@ -429,6 +429,29 @@ pub const Version = struct {
429429 .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
430430 };
431431 }
432
433 pub fn format(
434 self: Version,
435 comptime fmt: []const u8,
436 options: std.fmt.FormatOptions,
437 context: var,
438 comptime Error: type,
439 comptime output: fn (@TypeOf(context), []const u8) Error!void,
440 ) Error!void {
441 if (fmt.len == 0) {
442 if (self.patch == 0) {
443 if (self.minor == 0) {
444 return std.fmt.format(context, Error, output, "{}", .{self.major});
445 } else {
446 return std.fmt.format(context, Error, output, "{}.{}", .{ self.major, self.minor });
447 }
448 } else {
449 return std.fmt.format(context, Error, output, "{}.{}.{}", .{ self.major, self.minor, self.patch });
450 }
451 } else {
452 @compileError("Unknown format string: '" ++ fmt ++ "'");
453 }
454 }
432455};
433456
434457/// This data structure is used by the Zig language code generation and
lib/std/target.zig+186-499
......@@ -60,6 +60,16 @@ pub const Target = struct {
6060 else => false,
6161 };
6262 }
63
64 pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
65 if (tag.isDarwin()) {
66 return ".dylib";
67 }
68 switch (tag) {
69 .windows => return ".dll",
70 else => return ".so",
71 }
72 }
6373 };
6474
6575 /// Based on NTDDI version constants from
......@@ -210,64 +220,31 @@ pub const Target = struct {
210220 }
211221 };
212222
213 pub fn parse(text: []const u8) !Os {
214 var it = mem.separate(text, ".");
215 const os_name = it.next().?;
216 const tag = std.meta.stringToEnum(Tag, os_name) orelse return error.UnknownOperatingSystem;
217 const version_text = it.rest();
218 const S = struct {
219 fn parseNone(s: []const u8) !void {
220 if (s.len != 0) return error.InvalidOperatingSystemVersion;
221 }
222 fn parseSemVer(s: []const u8, d_range: Version.Range) !Version.Range {
223 if (s.len == 0) return d_range;
224 var range_it = mem.separate(s, "...");
225
226 const min_text = range_it.next().?;
227 const min_ver = Version.parse(min_text) catch |err| switch (err) {
228 error.Overflow => return error.InvalidOperatingSystemVersion,
229 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
230 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
231 };
232
233 const max_text = range_it.next() orelse return Version.Range{
234 .min = min_ver,
235 .max = d_range.max,
236 };
237 const max_ver = Version.parse(max_text) catch |err| switch (err) {
238 error.Overflow => return error.InvalidOperatingSystemVersion,
239 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
240 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
241 };
242
243 return Version.Range{ .min = min_ver, .max = max_ver };
244 }
245 fn parseWindows(s: []const u8, d_range: WindowsVersion.Range) !WindowsVersion.Range {
246 if (s.len == 0) return d_range;
247 var range_it = mem.separate(s, "...");
248
249 const min_text = range_it.next().?;
250 const min_ver = std.meta.stringToEnum(WindowsVersion, min_text) orelse
251 return error.InvalidOperatingSystemVersion;
223 pub fn defaultVersionRange(tag: Tag) Os {
224 return .{
225 .tag = tag,
226 .version_range = VersionRange.default(tag),
227 };
228 }
252229
253 const max_text = range_it.next() orelse return WindowsVersion.Range{
254 .min = min_ver,
255 .max = d_range.max,
256 };
257 const max_ver = std.meta.stringToEnum(WindowsVersion, max_text) orelse
258 return error.InvalidOperatingSystemVersion;
230 pub fn requiresLibC(os: Os) bool {
231 return switch (os.tag) {
232 .freebsd,
233 .netbsd,
234 .macosx,
235 .ios,
236 .tvos,
237 .watchos,
238 .dragonfly,
239 .openbsd,
240 => true,
259241
260 return WindowsVersion.Range{ .min = min_ver, .max = max_ver };
261 }
262 };
263 const d_range = VersionRange.default(tag);
264 switch (tag) {
242 .linux,
243 .windows,
265244 .freestanding,
266245 .ananas,
267246 .cloudabi,
268 .dragonfly,
269247 .fuchsia,
270 .ios,
271248 .kfreebsd,
272249 .lv2,
273250 .solaris,
......@@ -282,8 +259,6 @@ pub const Target = struct {
282259 .amdhsa,
283260 .ps4,
284261 .elfiamcu,
285 .tvos,
286 .watchos,
287262 .mesa3d,
288263 .contiki,
289264 .amdpal,
......@@ -293,41 +268,7 @@ pub const Target = struct {
293268 .emscripten,
294269 .uefi,
295270 .other,
296 => return Os{
297 .tag = tag,
298 .version_range = .{ .none = try S.parseNone(version_text) },
299 },
300
301 .freebsd,
302 .macosx,
303 .netbsd,
304 .openbsd,
305 => return Os{
306 .tag = tag,
307 .version_range = .{ .semver = try S.parseSemVer(version_text, d_range.semver) },
308 },
309
310 .linux => return Os{
311 .tag = tag,
312 .version_range = .{
313 .linux = .{
314 .range = try S.parseSemVer(version_text, d_range.linux.range),
315 .glibc = d_range.linux.glibc,
316 },
317 },
318 },
319
320 .windows => return Os{
321 .tag = tag,
322 .version_range = .{ .windows = try S.parseWindows(version_text, d_range.windows) },
323 },
324 }
325 }
326
327 pub fn defaultVersionRange(tag: Tag) Os {
328 return .{
329 .tag = tag,
330 .version_range = VersionRange.default(tag),
271 => false,
331272 };
332273 }
333274 };
......@@ -434,6 +375,13 @@ pub const Target = struct {
434375 else => false,
435376 };
436377 }
378
379 pub fn oFileExt(abi: Abi) [:0]const u8 {
380 return switch (abi) {
381 .msvc => ".obj",
382 else => ".o",
383 };
384 }
437385 };
438386
439387 pub const ObjectFormat = enum {
......@@ -500,6 +448,12 @@ pub const Target = struct {
500448 return Set{ .ints = [1]usize{0} ** usize_count };
501449 }
502450
451 pub fn isEmpty(set: Set) bool {
452 return for (set.ints) |x| {
453 if (x != 0) break false;
454 } else true;
455 }
456
503457 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
504458 const usize_index = arch_feature_index / @bitSizeOf(usize);
505459 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
......@@ -526,6 +480,15 @@ pub const Target = struct {
526480 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
527481 }
528482
483 /// Removes the specified feature but not its dependents.
484 pub fn removeFeatureSet(set: *Set, other_set: Set) void {
485 // TODO should be able to use binary not on @Vector type.
486 // https://github.com/ziglang/zig/issues/903
487 for (set.ints) |*int, i| {
488 int.* &= ~other_set.ints[i];
489 }
490 }
491
529492 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
530493 @setEvalBranchQuota(1000000);
531494
......@@ -663,7 +626,7 @@ pub const Target = struct {
663626 return cpu;
664627 }
665628 }
666 return error.UnknownCpu;
629 return error.UnknownCpuModel;
667630 }
668631
669632 pub fn toElfMachine(arch: Arch) std.elf.EM {
......@@ -779,6 +742,66 @@ pub const Target = struct {
779742 };
780743 }
781744
745 pub fn ptrBitWidth(arch: Arch) u32 {
746 switch (arch) {
747 .avr,
748 .msp430,
749 => return 16,
750
751 .arc,
752 .arm,
753 .armeb,
754 .hexagon,
755 .le32,
756 .mips,
757 .mipsel,
758 .powerpc,
759 .r600,
760 .riscv32,
761 .sparc,
762 .sparcel,
763 .tce,
764 .tcele,
765 .thumb,
766 .thumbeb,
767 .i386,
768 .xcore,
769 .nvptx,
770 .amdil,
771 .hsail,
772 .spir,
773 .kalimba,
774 .shave,
775 .lanai,
776 .wasm32,
777 .renderscript32,
778 .aarch64_32,
779 => return 32,
780
781 .aarch64,
782 .aarch64_be,
783 .mips64,
784 .mips64el,
785 .powerpc64,
786 .powerpc64le,
787 .riscv64,
788 .x86_64,
789 .nvptx64,
790 .le64,
791 .amdil64,
792 .hsail64,
793 .spir64,
794 .wasm64,
795 .renderscript64,
796 .amdgcn,
797 .bpfel,
798 .bpfeb,
799 .sparcv9,
800 .s390x,
801 => return 64,
802 }
803 }
804
782805 /// Returns a name that matches the lib/std/target/* directory name.
783806 pub fn genericName(arch: Arch) []const u8 {
784807 return switch (arch) {
......@@ -846,16 +869,6 @@ pub const Target = struct {
846869 else => &[0]*const Model{},
847870 };
848871 }
849
850 pub fn parse(text: []const u8) !Arch {
851 const info = @typeInfo(Arch);
852 inline for (info.Enum.fields) |field| {
853 if (mem.eql(u8, text, field.name)) {
854 return @as(Arch, @field(Arch, field.name));
855 }
856 }
857 return error.UnknownArchitecture;
858 }
859872 };
860873
861874 pub const Model = struct {
......@@ -872,41 +885,44 @@ pub const Target = struct {
872885 .features = features,
873886 };
874887 }
888
889 pub fn baseline(arch: Arch) *const Model {
890 const S = struct {
891 const generic_model = Model{
892 .name = "generic",
893 .llvm_name = null,
894 .features = Cpu.Feature.Set.empty,
895 };
896 };
897 return switch (arch) {
898 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
899 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
900 .avr => &avr.cpu.avr1,
901 .bpfel, .bpfeb => &bpf.cpu.generic,
902 .hexagon => &hexagon.cpu.generic,
903 .mips, .mipsel => &mips.cpu.mips32,
904 .mips64, .mips64el => &mips.cpu.mips64,
905 .msp430 => &msp430.cpu.generic,
906 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
907 .amdgcn => &amdgpu.cpu.generic,
908 .riscv32 => &riscv.cpu.baseline_rv32,
909 .riscv64 => &riscv.cpu.baseline_rv64,
910 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
911 .s390x => &systemz.cpu.generic,
912 .i386 => &x86.cpu.pentium4,
913 .x86_64 => &x86.cpu.x86_64,
914 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
915 .wasm32, .wasm64 => &wasm.cpu.generic,
916
917 else => &S.generic_model,
918 };
919 }
875920 };
876921
877922 /// The "default" set of CPU features for cross-compiling. A conservative set
878923 /// of features that is expected to be supported on most available hardware.
879924 pub fn baseline(arch: Arch) Cpu {
880 const S = struct {
881 const generic_model = Model{
882 .name = "generic",
883 .llvm_name = null,
884 .features = Cpu.Feature.Set.empty,
885 };
886 };
887 const model = switch (arch) {
888 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
889 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
890 .avr => &avr.cpu.avr1,
891 .bpfel, .bpfeb => &bpf.cpu.generic,
892 .hexagon => &hexagon.cpu.generic,
893 .mips, .mipsel => &mips.cpu.mips32,
894 .mips64, .mips64el => &mips.cpu.mips64,
895 .msp430 => &msp430.cpu.generic,
896 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
897 .amdgcn => &amdgpu.cpu.generic,
898 .riscv32 => &riscv.cpu.baseline_rv32,
899 .riscv64 => &riscv.cpu.baseline_rv64,
900 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
901 .s390x => &systemz.cpu.generic,
902 .i386 => &x86.cpu.pentium4,
903 .x86_64 => &x86.cpu.x86_64,
904 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
905 .wasm32, .wasm64 => &wasm.cpu.generic,
906
907 else => &S.generic_model,
908 };
909 return model.toCpu(arch);
925 return Model.baseline(arch).toCpu(arch);
910926 }
911927 };
912928
......@@ -918,239 +934,70 @@ pub const Target = struct {
918934
919935 pub const stack_align = 16;
920936
921 /// TODO add OS version ranges and glibc version
922 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
923 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
924 @tagName(self.cpu.arch),
925 @tagName(self.os.tag),
926 @tagName(self.abi),
927 });
937 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
938 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
928939 }
929940
930 /// Returned slice must be freed by the caller.
931 pub fn vcpkgTriplet(target: Target, allocator: *mem.Allocator, linkage: std.build.VcpkgLinkage) ![]const u8 {
932 const arch = switch (target.cpu.arch) {
933 .i386 => "x86",
934 .x86_64 => "x64",
935
936 .arm,
937 .armeb,
938 .thumb,
939 .thumbeb,
940 .aarch64_32,
941 => "arm",
942
943 .aarch64,
944 .aarch64_be,
945 => "arm64",
946
947 else => return error.VcpkgNoSuchArchitecture,
948 };
949
950 const os = switch (target.os) {
951 .windows => "windows",
952 .linux => "linux",
953 .macosx => "macos",
954 else => return error.VcpkgNoSuchOs,
955 };
956
957 if (linkage == .Static) {
958 return try mem.join(allocator, "-", &[_][]const u8{ arch, os, "static" });
959 } else {
960 return try mem.join(allocator, "-", &[_][]const u8{ arch, os });
961 }
941 pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![:0]u8 {
942 return std.fmt.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
962943 }
963944
964 pub fn allocDescription(self: Target, allocator: *mem.Allocator) ![]u8 {
965 // TODO is there anything else worthy of the description that is not
966 // already captured in the triple?
967 return self.zigTriple(allocator);
945 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
946 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
968947 }
969948
970 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
971 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
972 @tagName(self.cpu.arch),
973 @tagName(self.os.tag),
974 @tagName(self.abi),
975 });
949 pub fn oFileExt(self: Target) [:0]const u8 {
950 return self.abi.oFileExt();
976951 }
977952
978 pub const ParseOptions = struct {
979 /// This is sometimes called a "triple". It looks roughly like this:
980 /// riscv64-linux-gnu
981 /// The fields are, respectively:
982 /// * CPU Architecture
983 /// * Operating System
984 /// * C ABI (optional)
985 arch_os_abi: []const u8,
986
987 /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
988 /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
989 /// to remove from the set.
990 cpu_features: []const u8 = "baseline",
991
992 /// If this is provided, the function will populate some information about parsing failures,
993 /// so that user-friendly error messages can be delivered.
994 diagnostics: ?*Diagnostics = null,
995
996 pub const Diagnostics = struct {
997 /// If the architecture was determined, this will be populated.
998 arch: ?Cpu.Arch = null,
999
1000 /// If the OS was determined, this will be populated.
1001 os: ?Os = null,
1002
1003 /// If the ABI was determined, this will be populated.
1004 abi: ?Abi = null,
1005
1006 /// If the CPU name was determined, this will be populated.
1007 cpu_name: ?[]const u8 = null,
1008
1009 /// If error.UnknownCpuFeature is returned, this will be populated.
1010 unknown_feature_name: ?[]const u8 = null,
1011 };
1012 };
1013
1014 pub fn parse(args: ParseOptions) !Target {
1015 var dummy_diags: ParseOptions.Diagnostics = undefined;
1016 var diags = args.diagnostics orelse &dummy_diags;
1017
1018 var it = mem.separate(args.arch_os_abi, "-");
1019 const arch_name = it.next() orelse return error.MissingArchitecture;
1020 const arch = try Cpu.Arch.parse(arch_name);
1021 diags.arch = arch;
1022
1023 const os_name = it.next() orelse return error.MissingOperatingSystem;
1024 var os = try Os.parse(os_name);
1025 diags.os = os;
1026
1027 const opt_abi_text = it.next();
1028 const abi = if (opt_abi_text) |abi_text| blk: {
1029 var abi_it = mem.separate(abi_text, ".");
1030 const abi = std.meta.stringToEnum(Abi, abi_it.next().?) orelse
1031 return error.UnknownApplicationBinaryInterface;
1032 const abi_ver_text = abi_it.rest();
1033 if (abi_ver_text.len != 0) {
1034 if (os.tag == .linux and abi.isGnu()) {
1035 os.version_range.linux.glibc = Version.parse(abi_ver_text) catch |err| switch (err) {
1036 error.Overflow => return error.InvalidAbiVersion,
1037 error.InvalidCharacter => return error.InvalidAbiVersion,
1038 error.InvalidVersion => return error.InvalidAbiVersion,
1039 };
1040 } else {
1041 return error.InvalidAbiVersion;
1042 }
1043 }
1044 break :blk abi;
1045 } else Abi.default(arch, os);
1046 diags.abi = abi;
1047
1048 if (it.next() != null) return error.UnexpectedExtraField;
1049
1050 const all_features = arch.allFeaturesList();
1051 var index: usize = 0;
1052 while (index < args.cpu_features.len and
1053 args.cpu_features[index] != '+' and
1054 args.cpu_features[index] != '-')
1055 {
1056 index += 1;
953 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
954 switch (os_tag) {
955 .windows => return ".exe",
956 .uefi => return ".efi",
957 else => if (cpu_arch.isWasm()) {
958 return ".wasm";
959 } else {
960 return "";
961 },
1057962 }
1058 const cpu_name = args.cpu_features[0..index];
1059 diags.cpu_name = cpu_name;
1060
1061 const cpu: Cpu = if (mem.eql(u8, cpu_name, "baseline")) Cpu.baseline(arch) else blk: {
1062 const cpu_model = try arch.parseCpuModel(cpu_name);
1063
1064 var set = cpu_model.features;
1065 while (index < args.cpu_features.len) {
1066 const op = args.cpu_features[index];
1067 index += 1;
1068 const start = index;
1069 while (index < args.cpu_features.len and
1070 args.cpu_features[index] != '+' and
1071 args.cpu_features[index] != '-')
1072 {
1073 index += 1;
1074 }
1075 const feature_name = args.cpu_features[start..index];
1076 for (all_features) |feature, feat_index_usize| {
1077 const feat_index = @intCast(Cpu.Feature.Set.Index, feat_index_usize);
1078 if (mem.eql(u8, feature_name, feature.name)) {
1079 switch (op) {
1080 '+' => set.addFeature(feat_index),
1081 '-' => set.removeFeature(feat_index),
1082 else => unreachable,
1083 }
1084 break;
1085 }
1086 } else {
1087 diags.unknown_feature_name = feature_name;
1088 return error.UnknownCpuFeature;
1089 }
1090 }
1091 set.populateDependencies(all_features);
1092 break :blk .{
1093 .arch = arch,
1094 .model = cpu_model,
1095 .features = set,
1096 };
1097 };
1098 return Target{
1099 .cpu = cpu,
1100 .os = os,
1101 .abi = abi,
1102 };
1103963 }
1104964
1105 pub fn oFileExt(self: Target) []const u8 {
1106 return switch (self.abi) {
1107 .msvc => ".obj",
1108 else => ".o",
1109 };
1110 }
1111
1112 pub fn exeFileExt(self: Target) []const u8 {
1113 if (self.os.tag == .windows) {
1114 return ".exe";
1115 } else if (self.os.tag == .uefi) {
1116 return ".efi";
1117 } else if (self.cpu.arch.isWasm()) {
1118 return ".wasm";
1119 } else {
1120 return "";
1121 }
965 pub fn exeFileExt(self: Target) [:0]const u8 {
966 return exeFileExtSimple(self.cpu.arch, self.os.tag);
1122967 }
1123968
1124 pub fn staticLibSuffix(self: Target) []const u8 {
1125 if (self.cpu.arch.isWasm()) {
969 pub fn staticLibSuffix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
970 if (cpu_arch.isWasm()) {
1126971 return ".wasm";
1127972 }
1128 switch (self.abi) {
973 switch (abi) {
1129974 .msvc => return ".lib",
1130975 else => return ".a",
1131976 }
1132977 }
1133978
1134 pub fn dynamicLibSuffix(self: Target) []const u8 {
1135 if (self.isDarwin()) {
1136 return ".dylib";
1137 }
1138 switch (self.os) {
1139 .windows => return ".dll",
1140 else => return ".so",
1141 }
979 pub fn staticLibSuffix(self: Target) [:0]const u8 {
980 return staticLibSuffix_cpu_arch_abi(self.cpu.arch, self.abi);
1142981 }
1143982
1144 pub fn libPrefix(self: Target) []const u8 {
1145 if (self.cpu.arch.isWasm()) {
983 pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
984 return self.os.tag.dynamicLibSuffix();
985 }
986
987 pub fn libPrefix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
988 if (cpu_arch.isWasm()) {
1146989 return "";
1147990 }
1148 switch (self.abi) {
991 switch (abi) {
1149992 .msvc => return "",
1150993 else => return "lib",
1151994 }
1152995 }
1153996
997 pub fn libPrefix(self: Target) [:0]const u8 {
998 return libPrefix_cpu_arch_abi(self.cpu.arch, self.abi);
999 }
1000
11541001 pub fn getObjectFormat(self: Target) ObjectFormat {
11551002 if (self.os.tag == .windows or self.os.tag == .uefi) {
11561003 return .coff;
......@@ -1190,129 +1037,18 @@ pub const Target = struct {
11901037 return self.os.tag.isDarwin();
11911038 }
11921039
1193 pub fn isGnuLibC(self: Target) bool {
1194 return self.os.tag == .linux and self.abi.isGnu();
1040 pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
1041 return os_tag == .linux and abi.isGnu();
11951042 }
11961043
1197 pub fn wantSharedLibSymLinks(self: Target) bool {
1198 return self.os.tag != .windows;
1199 }
1200
1201 pub fn osRequiresLibC(self: Target) bool {
1202 return self.isDarwin() or self.os.tag == .freebsd or self.os.tag == .netbsd;
1203 }
1204
1205 pub fn getArchPtrBitWidth(self: Target) u32 {
1206 switch (self.cpu.arch) {
1207 .avr,
1208 .msp430,
1209 => return 16,
1210
1211 .arc,
1212 .arm,
1213 .armeb,
1214 .hexagon,
1215 .le32,
1216 .mips,
1217 .mipsel,
1218 .powerpc,
1219 .r600,
1220 .riscv32,
1221 .sparc,
1222 .sparcel,
1223 .tce,
1224 .tcele,
1225 .thumb,
1226 .thumbeb,
1227 .i386,
1228 .xcore,
1229 .nvptx,
1230 .amdil,
1231 .hsail,
1232 .spir,
1233 .kalimba,
1234 .shave,
1235 .lanai,
1236 .wasm32,
1237 .renderscript32,
1238 .aarch64_32,
1239 => return 32,
1240
1241 .aarch64,
1242 .aarch64_be,
1243 .mips64,
1244 .mips64el,
1245 .powerpc64,
1246 .powerpc64le,
1247 .riscv64,
1248 .x86_64,
1249 .nvptx64,
1250 .le64,
1251 .amdil64,
1252 .hsail64,
1253 .spir64,
1254 .wasm64,
1255 .renderscript64,
1256 .amdgcn,
1257 .bpfel,
1258 .bpfeb,
1259 .sparcv9,
1260 .s390x,
1261 => return 64,
1262 }
1044 pub fn isGnuLibC(self: Target) bool {
1045 return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
12631046 }
12641047
12651048 pub fn supportsNewStackCall(self: Target) bool {
12661049 return !self.cpu.arch.isWasm();
12671050 }
12681051
1269 pub const Executor = union(enum) {
1270 native,
1271 qemu: []const u8,
1272 wine: []const u8,
1273 wasmtime: []const u8,
1274 unavailable,
1275 };
1276
1277 pub fn getExternalExecutor(self: Target) Executor {
1278 // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
1279 if (self.os.tag == builtin.os.tag) {
1280 return switch (self.cpu.arch) {
1281 .aarch64 => Executor{ .qemu = "qemu-aarch64" },
1282 .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
1283 .arm => Executor{ .qemu = "qemu-arm" },
1284 .armeb => Executor{ .qemu = "qemu-armeb" },
1285 .i386 => Executor{ .qemu = "qemu-i386" },
1286 .mips => Executor{ .qemu = "qemu-mips" },
1287 .mipsel => Executor{ .qemu = "qemu-mipsel" },
1288 .mips64 => Executor{ .qemu = "qemu-mips64" },
1289 .mips64el => Executor{ .qemu = "qemu-mips64el" },
1290 .powerpc => Executor{ .qemu = "qemu-ppc" },
1291 .powerpc64 => Executor{ .qemu = "qemu-ppc64" },
1292 .powerpc64le => Executor{ .qemu = "qemu-ppc64le" },
1293 .riscv32 => Executor{ .qemu = "qemu-riscv32" },
1294 .riscv64 => Executor{ .qemu = "qemu-riscv64" },
1295 .s390x => Executor{ .qemu = "qemu-s390x" },
1296 .sparc => Executor{ .qemu = "qemu-sparc" },
1297 .x86_64 => Executor{ .qemu = "qemu-x86_64" },
1298 else => return .unavailable,
1299 };
1300 }
1301
1302 switch (self.os.tag) {
1303 .windows => switch (self.getArchPtrBitWidth()) {
1304 32 => return Executor{ .wine = "wine" },
1305 64 => return Executor{ .wine = "wine64" },
1306 else => return .unavailable,
1307 },
1308 .wasi => switch (self.getArchPtrBitWidth()) {
1309 32 => return Executor{ .wasmtime = "wasmtime" },
1310 else => return .unavailable,
1311 },
1312 else => return .unavailable,
1313 }
1314 }
1315
13161052 pub const FloatAbi = enum {
13171053 hard,
13181054 soft,
......@@ -1359,7 +1095,7 @@ pub const Target = struct {
13591095 }![:0]u8 {
13601096 const a = allocator;
13611097 if (self.isAndroid()) {
1362 return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)
1098 return mem.dupeZ(a, u8, if (self.cpu.arch.ptrBitWidth() == 64)
13631099 "/system/bin/linker64"
13641100 else
13651101 "/system/bin/linker");
......@@ -1477,52 +1213,3 @@ pub const Target = struct {
14771213 }
14781214 }
14791215};
1480
1481test "Target.parse" {
1482 {
1483 const target = try Target.parse(.{
1484 .arch_os_abi = "x86_64-linux-gnu",
1485 .cpu_features = "x86_64-sse-sse2-avx-cx8",
1486 });
1487
1488 std.testing.expect(target.os.tag == .linux);
1489 std.testing.expect(target.abi == .gnu);
1490 std.testing.expect(target.cpu.arch == .x86_64);
1491 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
1492 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
1493 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
1494 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
1495 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
1496 }
1497 {
1498 const target = try Target.parse(.{
1499 .arch_os_abi = "arm-linux-musleabihf",
1500 .cpu_features = "generic+v8a",
1501 });
1502
1503 std.testing.expect(target.os.tag == .linux);
1504 std.testing.expect(target.abi == .musleabihf);
1505 std.testing.expect(target.cpu.arch == .arm);
1506 std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
1507 std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
1508 }
1509 {
1510 const target = try Target.parse(.{
1511 .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
1512 .cpu_features = "generic+v8a",
1513 });
1514
1515 std.testing.expect(target.cpu.arch == .aarch64);
1516 std.testing.expect(target.os.tag == .linux);
1517 std.testing.expect(target.os.version_range.linux.range.min.major == 3);
1518 std.testing.expect(target.os.version_range.linux.range.min.minor == 10);
1519 std.testing.expect(target.os.version_range.linux.range.min.patch == 0);
1520 std.testing.expect(target.os.version_range.linux.range.max.major == 4);
1521 std.testing.expect(target.os.version_range.linux.range.max.minor == 4);
1522 std.testing.expect(target.os.version_range.linux.range.max.patch == 1);
1523 std.testing.expect(target.os.version_range.linux.glibc.major == 2);
1524 std.testing.expect(target.os.version_range.linux.glibc.minor == 27);
1525 std.testing.expect(target.os.version_range.linux.glibc.patch == 0);
1526 std.testing.expect(target.abi == .gnu);
1527 }
1528}
lib/std/testing.zig+4-6
......@@ -1,5 +1,3 @@
1const builtin = @import("builtin");
2const TypeId = builtin.TypeId;
31const std = @import("std.zig");
42
53pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;
......@@ -65,16 +63,16 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {
6563
6664 .Pointer => |pointer| {
6765 switch (pointer.size) {
68 builtin.TypeInfo.Pointer.Size.One,
69 builtin.TypeInfo.Pointer.Size.Many,
70 builtin.TypeInfo.Pointer.Size.C,
66 .One,
67 .Many,
68 .C,
7169 => {
7270 if (actual != expected) {
7371 std.debug.panic("expected {*}, found {*}", .{ expected, actual });
7472 }
7573 },
7674
77 builtin.TypeInfo.Pointer.Size.Slice => {
75 .Slice => {
7876 if (actual.ptr != expected.ptr) {
7977 std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });
8078 }
lib/std/zig.zig+3-6
......@@ -6,11 +6,8 @@ pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStri
66pub const render = @import("zig/render.zig").render;
77pub const ast = @import("zig/ast.zig");
88pub const system = @import("zig/system.zig");
9pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
910
10test "std.zig tests" {
11 _ = @import("zig/ast.zig");
12 _ = @import("zig/parse.zig");
13 _ = @import("zig/render.zig");
14 _ = @import("zig/tokenizer.zig");
15 _ = @import("zig/parse_string_literal.zig");
11test "" {
12 @import("std").meta.refAllDecls(@This());
1613}
lib/std/zig/cross_target.zig created+766
......@@ -0,0 +1,766 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const Target = std.Target;
4const mem = std.mem;
5
6/// Contains all the same data as `Target`, additionally introducing the concept of "the native target".
7/// The purpose of this abstraction is to provide meaningful and unsurprising defaults.
8pub const CrossTarget = struct {
9 /// `null` means native.
10 cpu_arch: ?Target.Cpu.Arch = null,
11
12 /// If `cpu_arch` is native, `null` means native. Otherwise it means baseline.
13 /// If this is non-null, `cpu_arch` must be specified.
14 cpu_model: ?*const Target.Cpu.Model = null,
15
16 /// Sparse set of CPU features to add to the set from `cpu_model`.
17 /// If this is non-empty, `cpu_arch` must be specified.
18 cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
19
20 /// Sparse set of CPU features to remove from the set from `cpu_model`.
21 /// If this is non-empty, `cpu_arch` must be specified.
22 cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
23
24 /// `null` means native.
25 os_tag: ?Target.Os.Tag = null,
26
27 /// `null` means the default version range for `os_tag`. If `os_tag` is `null` (native)
28 /// then `null` for this field means native.
29 os_version_min: ?OsVersion = null,
30
31 /// When cross compiling, `null` means default (latest known OS version).
32 /// When `os_tag` is native, `null` means equal to the native OS version.
33 os_version_max: ?OsVersion = null,
34
35 /// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI.
36 abi: ?Target.Abi = null,
37
38 /// `null` means default when cross compiling, or native when os_tag is native.
39 /// If `isGnuLibC()` is `false`, this must be `null` and is ignored.
40 glibc_version: ?SemVer = null,
41
42 pub const OsVersion = union(enum) {
43 none: void,
44 semver: SemVer,
45 windows: Target.Os.WindowsVersion,
46 };
47
48 pub const SemVer = std.builtin.Version;
49
50 pub fn fromTarget(target: Target) CrossTarget {
51 var result: CrossTarget = .{
52 .cpu_arch = target.cpu.arch,
53 .cpu_model = target.cpu.model,
54 .os_tag = target.os.tag,
55 .os_version_min = undefined,
56 .os_version_max = undefined,
57 .abi = target.abi,
58 .glibc_version = if (target.isGnuLibC())
59 target.os.version_range.linux.glibc
60 else
61 null,
62 };
63 result.updateOsVersionRange(target.os);
64
65 const all_features = target.cpu.arch.allFeaturesList();
66 var cpu_model_set = target.cpu.model.features;
67 cpu_model_set.populateDependencies(all_features);
68 {
69 // The "add" set is the full set with the CPU Model set removed.
70 const add_set = &result.cpu_features_add;
71 add_set.* = target.cpu.features;
72 add_set.removeFeatureSet(cpu_model_set);
73 }
74 {
75 // The "sub" set is the features that are on in CPU Model set and off in the full set.
76 const sub_set = &result.cpu_features_sub;
77 sub_set.* = cpu_model_set;
78 sub_set.removeFeatureSet(target.cpu.features);
79 }
80 return result;
81 }
82
83 fn updateOsVersionRange(self: *CrossTarget, os: Target.Os) void {
84 switch (os.tag) {
85 .freestanding,
86 .ananas,
87 .cloudabi,
88 .dragonfly,
89 .fuchsia,
90 .ios,
91 .kfreebsd,
92 .lv2,
93 .solaris,
94 .haiku,
95 .minix,
96 .rtems,
97 .nacl,
98 .cnk,
99 .aix,
100 .cuda,
101 .nvcl,
102 .amdhsa,
103 .ps4,
104 .elfiamcu,
105 .tvos,
106 .watchos,
107 .mesa3d,
108 .contiki,
109 .amdpal,
110 .hermit,
111 .hurd,
112 .wasi,
113 .emscripten,
114 .uefi,
115 .other,
116 => {
117 self.os_version_min = .{ .none = {} };
118 self.os_version_max = .{ .none = {} };
119 },
120
121 .freebsd,
122 .macosx,
123 .netbsd,
124 .openbsd,
125 => {
126 self.os_version_min = .{ .semver = os.version_range.semver.min };
127 self.os_version_max = .{ .semver = os.version_range.semver.max };
128 },
129
130 .linux => {
131 self.os_version_min = .{ .semver = os.version_range.linux.range.min };
132 self.os_version_max = .{ .semver = os.version_range.linux.range.max };
133 },
134
135 .windows => {
136 self.os_version_min = .{ .windows = os.version_range.windows.min };
137 self.os_version_max = .{ .windows = os.version_range.windows.max };
138 },
139 }
140 }
141
142 pub fn toTarget(self: CrossTarget) Target {
143 return .{
144 .cpu = self.getCpu(),
145 .os = self.getOs(),
146 .abi = self.getAbi(),
147 };
148 }
149
150 pub const ParseOptions = struct {
151 /// This is sometimes called a "triple". It looks roughly like this:
152 /// riscv64-linux-musl
153 /// The fields are, respectively:
154 /// * CPU Architecture
155 /// * Operating System (and optional version range)
156 /// * C ABI (optional, with optional glibc version)
157 /// The string "native" can be used for CPU architecture as well as Operating System.
158 /// If the CPU Architecture is specified as "native", then the Operating System and C ABI may be omitted.
159 arch_os_abi: []const u8 = "native",
160
161 /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
162 /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
163 /// to remove from the set.
164 /// The following special strings are recognized for CPU Model name:
165 /// * "baseline" - The "default" set of CPU features for cross-compiling. A conservative set
166 /// of features that is expected to be supported on most available hardware.
167 /// * "native" - The native CPU model is to be detected when compiling.
168 /// If this field is not provided (`null`), then the value will depend on the
169 /// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline".
170 cpu_features: ?[]const u8 = null,
171
172 /// If this is provided, the function will populate some information about parsing failures,
173 /// so that user-friendly error messages can be delivered.
174 diagnostics: ?*Diagnostics = null,
175
176 pub const Diagnostics = struct {
177 /// If the architecture was determined, this will be populated.
178 arch: ?Target.Cpu.Arch = null,
179
180 /// If the OS tag was determined, this will be populated.
181 os_tag: ?Target.Os.Tag = null,
182
183 /// If the ABI was determined, this will be populated.
184 abi: ?Target.Abi = null,
185
186 /// If the CPU name was determined, this will be populated.
187 cpu_name: ?[]const u8 = null,
188
189 /// If error.UnknownCpuFeature is returned, this will be populated.
190 unknown_feature_name: ?[]const u8 = null,
191 };
192 };
193
194 pub fn parse(args: ParseOptions) !CrossTarget {
195 var dummy_diags: ParseOptions.Diagnostics = undefined;
196 const diags = args.diagnostics orelse &dummy_diags;
197
198 // Start with everything initialized to default values.
199 var result: CrossTarget = .{};
200
201 var it = mem.separate(args.arch_os_abi, "-");
202 const arch_name = it.next().?;
203 const arch_is_native = mem.eql(u8, arch_name, "native");
204 if (!arch_is_native) {
205 result.cpu_arch = std.meta.stringToEnum(Target.Cpu.Arch, arch_name) orelse
206 return error.UnknownArchitecture;
207 }
208 const arch = result.getCpuArch();
209 diags.arch = arch;
210
211 if (it.next()) |os_text| {
212 try parseOs(&result, diags, os_text);
213 } else if (!arch_is_native) {
214 return error.MissingOperatingSystem;
215 }
216
217 const opt_abi_text = it.next();
218 if (opt_abi_text) |abi_text| {
219 var abi_it = mem.separate(abi_text, ".");
220 const abi = std.meta.stringToEnum(Target.Abi, abi_it.next().?) orelse
221 return error.UnknownApplicationBinaryInterface;
222 diags.abi = abi;
223
224 const abi_ver_text = abi_it.rest();
225 if (abi_it.next() != null) {
226 if (result.isGnuLibC()) {
227 result.glibc_version = SemVer.parse(abi_ver_text) catch |err| switch (err) {
228 error.Overflow => return error.InvalidAbiVersion,
229 error.InvalidCharacter => return error.InvalidAbiVersion,
230 error.InvalidVersion => return error.InvalidAbiVersion,
231 };
232 } else {
233 return error.InvalidAbiVersion;
234 }
235 }
236 }
237
238 if (it.next() != null) return error.UnexpectedExtraField;
239
240 if (args.cpu_features) |cpu_features| {
241 const all_features = arch.allFeaturesList();
242 var index: usize = 0;
243 while (index < cpu_features.len and
244 cpu_features[index] != '+' and
245 cpu_features[index] != '-')
246 {
247 index += 1;
248 }
249 const cpu_name = cpu_features[0..index];
250 diags.cpu_name = cpu_name;
251
252 const add_set = &result.cpu_features_add;
253 const sub_set = &result.cpu_features_sub;
254 if (mem.eql(u8, cpu_name, "native")) {
255 result.cpu_model = null;
256 } else if (mem.eql(u8, cpu_name, "baseline")) {
257 result.cpu_model = Target.Cpu.Model.baseline(arch);
258 } else {
259 result.cpu_model = try arch.parseCpuModel(cpu_name);
260 }
261
262 while (index < cpu_features.len) {
263 const op = cpu_features[index];
264 const set = switch (op) {
265 '+' => add_set,
266 '-' => sub_set,
267 else => unreachable,
268 };
269 index += 1;
270 const start = index;
271 while (index < cpu_features.len and
272 cpu_features[index] != '+' and
273 cpu_features[index] != '-')
274 {
275 index += 1;
276 }
277 const feature_name = cpu_features[start..index];
278 for (all_features) |feature, feat_index_usize| {
279 const feat_index = @intCast(Target.Cpu.Feature.Set.Index, feat_index_usize);
280 if (mem.eql(u8, feature_name, feature.name)) {
281 set.addFeature(feat_index);
282 break;
283 }
284 } else {
285 diags.unknown_feature_name = feature_name;
286 return error.UnknownCpuFeature;
287 }
288 }
289 }
290
291 return result;
292 }
293
294 pub fn getCpu(self: CrossTarget) Target.Cpu {
295 if (self.cpu_arch) |arch| {
296 if (self.cpu_model) |model| {
297 var adjusted_model = model.toCpu(arch);
298 self.updateCpuFeatures(&adjusted_model.features);
299 return adjusted_model;
300 } else {
301 var adjusted_baseline = Target.Cpu.baseline(arch);
302 self.updateCpuFeatures(&adjusted_baseline.features);
303 return adjusted_baseline;
304 }
305 } else {
306 assert(self.cpu_model == null);
307 assert(self.cpu_features_sub.isEmpty());
308 assert(self.cpu_features_add.isEmpty());
309 // This works when doing `zig build` because Zig generates a build executable using
310 // native CPU model & features. However this will not be accurate otherwise, and
311 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
312 return Target.current.cpu;
313 }
314 }
315
316 pub fn getCpuArch(self: CrossTarget) Target.Cpu.Arch {
317 return self.cpu_arch orelse Target.current.cpu.arch;
318 }
319
320 pub fn getCpuModel(self: CrossTarget) *const Target.Cpu.Model {
321 if (self.cpu_model) |cpu_model| return cpu_model;
322 return self.getCpu().model;
323 }
324
325 pub fn getCpuFeatures(self: CrossTarget) Target.Cpu.Feature.Set {
326 return self.getCpu().features;
327 }
328
329 pub fn getOs(self: CrossTarget) Target.Os {
330 // `Target.current.os` works when doing `zig build` because Zig generates a build executable using
331 // native OS version range. However this will not be accurate otherwise, and
332 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
333 var adjusted_os = if (self.os_tag) |os_tag| Target.Os.defaultVersionRange(os_tag) else Target.current.os;
334
335 if (self.os_version_min) |min| switch (min) {
336 .none => {},
337 .semver => |semver| switch (self.getOsTag()) {
338 .linux => adjusted_os.version_range.linux.range.min = semver,
339 else => adjusted_os.version_range.semver.min = semver,
340 },
341 .windows => |win_ver| adjusted_os.version_range.windows.min = win_ver,
342 };
343
344 if (self.os_version_max) |max| switch (max) {
345 .none => {},
346 .semver => |semver| switch (self.getOsTag()) {
347 .linux => adjusted_os.version_range.linux.range.max = semver,
348 else => adjusted_os.version_range.semver.max = semver,
349 },
350 .windows => |win_ver| adjusted_os.version_range.windows.max = win_ver,
351 };
352
353 if (self.glibc_version) |glibc| {
354 assert(self.isGnuLibC());
355 adjusted_os.version_range.linux.glibc = glibc;
356 }
357
358 return adjusted_os;
359 }
360
361 pub fn getOsTag(self: CrossTarget) Target.Os.Tag {
362 return self.os_tag orelse Target.current.os.tag;
363 }
364
365 pub fn getOsVersionMin(self: CrossTarget) OsVersion {
366 if (self.os_version_min) |version_min| return version_min;
367 var tmp: CrossTarget = undefined;
368 tmp.updateOsVersionRange(self.getOs());
369 return tmp.os_version_min.?;
370 }
371
372 pub fn getOsVersionMax(self: CrossTarget) OsVersion {
373 if (self.os_version_max) |version_max| return version_max;
374 var tmp: CrossTarget = undefined;
375 tmp.updateOsVersionRange(self.getOs());
376 return tmp.os_version_max.?;
377 }
378
379 pub fn getAbi(self: CrossTarget) Target.Abi {
380 if (self.abi) |abi| return abi;
381
382 if (self.isNativeOs()) {
383 // This works when doing `zig build` because Zig generates a build executable using
384 // native CPU model & features. However this will not be accurate otherwise, and
385 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
386 return Target.current.abi;
387 }
388
389 return Target.Abi.default(self.getCpuArch(), self.getOs());
390 }
391
392 pub fn isFreeBSD(self: CrossTarget) bool {
393 return self.getOsTag() == .freebsd;
394 }
395
396 pub fn isDarwin(self: CrossTarget) bool {
397 return self.getOsTag().isDarwin();
398 }
399
400 pub fn isNetBSD(self: CrossTarget) bool {
401 return self.getOsTag() == .netbsd;
402 }
403
404 pub fn isUefi(self: CrossTarget) bool {
405 return self.getOsTag() == .uefi;
406 }
407
408 pub fn isDragonFlyBSD(self: CrossTarget) bool {
409 return self.getOsTag() == .dragonfly;
410 }
411
412 pub fn isLinux(self: CrossTarget) bool {
413 return self.getOsTag() == .linux;
414 }
415
416 pub fn isWindows(self: CrossTarget) bool {
417 return self.getOsTag() == .windows;
418 }
419
420 pub fn oFileExt(self: CrossTarget) [:0]const u8 {
421 return self.getAbi().oFileExt();
422 }
423
424 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {
425 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());
426 }
427
428 pub fn staticLibSuffix(self: CrossTarget) [:0]const u8 {
429 return Target.staticLibSuffix_cpu_arch_abi(self.getCpuArch(), self.getAbi());
430 }
431
432 pub fn dynamicLibSuffix(self: CrossTarget) [:0]const u8 {
433 return self.getOsTag().dynamicLibSuffix();
434 }
435
436 pub fn libPrefix(self: CrossTarget) [:0]const u8 {
437 return Target.libPrefix_cpu_arch_abi(self.getCpuArch(), self.getAbi());
438 }
439
440 pub fn isNativeCpu(self: CrossTarget) bool {
441 return self.cpu_arch == null and self.cpu_model == null and
442 self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty();
443 }
444
445 pub fn isNativeOs(self: CrossTarget) bool {
446 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null;
447 }
448
449 pub fn isNativeAbi(self: CrossTarget) bool {
450 return self.abi == null and self.glibc_version == null;
451 }
452
453 pub fn isNative(self: CrossTarget) bool {
454 return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi();
455 }
456
457 pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![:0]u8 {
458 if (self.isNative()) {
459 return mem.dupeZ(allocator, u8, "native");
460 }
461
462 const arch_name = if (self.isNativeCpu()) "native" else @tagName(self.getCpuArch());
463 const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native";
464
465 var result = try std.Buffer.allocPrint(allocator, "{}-{}", .{ arch_name, os_name });
466 defer result.deinit();
467
468 // The zig target syntax does not allow specifying a max os version with no min, so
469 // if either are present, we need the min.
470 if (self.os_version_min != null or self.os_version_max != null) {
471 switch (self.getOsVersionMin()) {
472 .none => {},
473 .semver => |v| try result.print(".{}", .{v}),
474 .windows => |v| try result.print(".{}", .{@tagName(v)}),
475 }
476 }
477 if (self.os_version_max) |max| {
478 switch (max) {
479 .none => {},
480 .semver => |v| try result.print("...{}", .{v}),
481 .windows => |v| try result.print("...{}", .{@tagName(v)}),
482 }
483 }
484
485 if (self.abi) |abi| {
486 try result.print("-{}", .{@tagName(abi)});
487 if (self.glibc_version) |v| {
488 try result.print(".{}", .{v});
489 }
490 } else {
491 assert(self.glibc_version == null);
492 }
493
494 return result.toOwnedSlice();
495 }
496
497 pub fn allocDescription(self: CrossTarget, allocator: *mem.Allocator) ![:0]u8 {
498 // TODO is there anything else worthy of the description that is not
499 // already captured in the triple?
500 return self.zigTriple(allocator);
501 }
502
503 pub fn linuxTriple(self: CrossTarget, allocator: *mem.Allocator) ![:0]u8 {
504 return Target.linuxTripleSimple(allocator, self.getCpuArch(), self.getOsTag(), self.getAbi());
505 }
506
507 pub fn wantSharedLibSymLinks(self: CrossTarget) bool {
508 return self.getOsTag() != .windows;
509 }
510
511 pub const VcpkgLinkage = std.builtin.LinkMode;
512
513 /// Returned slice must be freed by the caller.
514 pub fn vcpkgTriplet(self: CrossTarget, allocator: *mem.Allocator, linkage: VcpkgLinkage) ![:0]u8 {
515 const arch = switch (self.getCpuArch()) {
516 .i386 => "x86",
517 .x86_64 => "x64",
518
519 .arm,
520 .armeb,
521 .thumb,
522 .thumbeb,
523 .aarch64_32,
524 => "arm",
525
526 .aarch64,
527 .aarch64_be,
528 => "arm64",
529
530 else => return error.UnsupportedVcpkgArchitecture,
531 };
532
533 const os = switch (self.getOsTag()) {
534 .windows => "windows",
535 .linux => "linux",
536 .macosx => "macos",
537 else => return error.UnsupportedVcpkgOperatingSystem,
538 };
539
540 const static_suffix = switch (linkage) {
541 .Static => "-static",
542 .Dynamic => "",
543 };
544
545 return std.fmt.allocPrint0(allocator, "{}-{}{}", .{ arch, os, static_suffix });
546 }
547
548 pub const Executor = union(enum) {
549 native,
550 qemu: []const u8,
551 wine: []const u8,
552 wasmtime: []const u8,
553 unavailable,
554 };
555
556 pub fn getExternalExecutor(self: CrossTarget) Executor {
557 const os_tag = self.getOsTag();
558 const cpu_arch = self.getCpuArch();
559
560 // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
561 if (os_tag == Target.current.os.tag) {
562 return switch (cpu_arch) {
563 .aarch64 => Executor{ .qemu = "qemu-aarch64" },
564 .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
565 .arm => Executor{ .qemu = "qemu-arm" },
566 .armeb => Executor{ .qemu = "qemu-armeb" },
567 .i386 => Executor{ .qemu = "qemu-i386" },
568 .mips => Executor{ .qemu = "qemu-mips" },
569 .mipsel => Executor{ .qemu = "qemu-mipsel" },
570 .mips64 => Executor{ .qemu = "qemu-mips64" },
571 .mips64el => Executor{ .qemu = "qemu-mips64el" },
572 .powerpc => Executor{ .qemu = "qemu-ppc" },
573 .powerpc64 => Executor{ .qemu = "qemu-ppc64" },
574 .powerpc64le => Executor{ .qemu = "qemu-ppc64le" },
575 .riscv32 => Executor{ .qemu = "qemu-riscv32" },
576 .riscv64 => Executor{ .qemu = "qemu-riscv64" },
577 .s390x => Executor{ .qemu = "qemu-s390x" },
578 .sparc => Executor{ .qemu = "qemu-sparc" },
579 .x86_64 => Executor{ .qemu = "qemu-x86_64" },
580 else => return .unavailable,
581 };
582 }
583
584 switch (os_tag) {
585 .windows => switch (cpu_arch.ptrBitWidth()) {
586 32 => return Executor{ .wine = "wine" },
587 64 => return Executor{ .wine = "wine64" },
588 else => return .unavailable,
589 },
590 .wasi => switch (cpu_arch.ptrBitWidth()) {
591 32 => return Executor{ .wasmtime = "wasmtime" },
592 else => return .unavailable,
593 },
594 else => return .unavailable,
595 }
596 }
597
598 pub fn isGnuLibC(self: CrossTarget) bool {
599 return Target.isGnuLibC_os_tag_abi(self.getOsTag(), self.getAbi());
600 }
601
602 pub fn setGnuLibCVersion(self: CrossTarget, major: u32, minor: u32, patch: u32) void {
603 assert(self.isGnuLibC());
604 self.glibc_version = SemVer{ .major = major, .minor = minor, .patch = patch };
605 }
606
607 fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
608 set.removeFeatureSet(self.cpu_features_sub);
609 set.addFeatureSet(self.cpu_features_add);
610 set.populateDependencies(self.getCpuArch().allFeaturesList());
611 set.removeFeatureSet(self.cpu_features_sub);
612 }
613
614 fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void {
615 var it = mem.separate(text, ".");
616 const os_name = it.next().?;
617 const os_is_native = mem.eql(u8, os_name, "native");
618 if (!os_is_native) {
619 result.os_tag = std.meta.stringToEnum(Target.Os.Tag, os_name) orelse
620 return error.UnknownOperatingSystem;
621 }
622 const tag = result.getOsTag();
623 diags.os_tag = tag;
624
625 const version_text = it.rest();
626 if (it.next() == null) return;
627
628 switch (tag) {
629 .freestanding,
630 .ananas,
631 .cloudabi,
632 .dragonfly,
633 .fuchsia,
634 .ios,
635 .kfreebsd,
636 .lv2,
637 .solaris,
638 .haiku,
639 .minix,
640 .rtems,
641 .nacl,
642 .cnk,
643 .aix,
644 .cuda,
645 .nvcl,
646 .amdhsa,
647 .ps4,
648 .elfiamcu,
649 .tvos,
650 .watchos,
651 .mesa3d,
652 .contiki,
653 .amdpal,
654 .hermit,
655 .hurd,
656 .wasi,
657 .emscripten,
658 .uefi,
659 .other,
660 => return error.InvalidOperatingSystemVersion,
661
662 .freebsd,
663 .macosx,
664 .netbsd,
665 .openbsd,
666 .linux,
667 => {
668 var range_it = mem.separate(version_text, "...");
669
670 const min_text = range_it.next().?;
671 const min_ver = SemVer.parse(min_text) catch |err| switch (err) {
672 error.Overflow => return error.InvalidOperatingSystemVersion,
673 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
674 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
675 };
676 result.os_version_min = .{ .semver = min_ver };
677
678 const max_text = range_it.next() orelse return;
679 const max_ver = SemVer.parse(max_text) catch |err| switch (err) {
680 error.Overflow => return error.InvalidOperatingSystemVersion,
681 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
682 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
683 };
684 result.os_version_max = .{ .semver = max_ver };
685 },
686
687 .windows => {
688 var range_it = mem.separate(version_text, "...");
689
690 const min_text = range_it.next().?;
691 const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse
692 return error.InvalidOperatingSystemVersion;
693 result.os_version_min = .{ .windows = min_ver };
694
695 const max_text = range_it.next() orelse return;
696 const max_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, max_text) orelse
697 return error.InvalidOperatingSystemVersion;
698 result.os_version_max = .{ .windows = max_ver };
699 },
700 }
701 }
702};
703
704test "CrossTarget.parse" {
705 {
706 const cross_target = try CrossTarget.parse(.{
707 .arch_os_abi = "x86_64-linux-gnu",
708 .cpu_features = "x86_64-sse-sse2-avx-cx8",
709 });
710 const target = cross_target.toTarget();
711
712 std.testing.expect(target.os.tag == .linux);
713 std.testing.expect(target.abi == .gnu);
714 std.testing.expect(target.cpu.arch == .x86_64);
715 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
716 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
717 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
718 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
719 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
720
721 const text = try cross_target.zigTriple(std.testing.allocator);
722 defer std.testing.allocator.free(text);
723 std.testing.expectEqualSlices(u8, "x86_64-linux-gnu", text);
724 }
725 {
726 const cross_target = try CrossTarget.parse(.{
727 .arch_os_abi = "arm-linux-musleabihf",
728 .cpu_features = "generic+v8a",
729 });
730 const target = cross_target.toTarget();
731
732 std.testing.expect(target.os.tag == .linux);
733 std.testing.expect(target.abi == .musleabihf);
734 std.testing.expect(target.cpu.arch == .arm);
735 std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
736 std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
737
738 const text = try cross_target.zigTriple(std.testing.allocator);
739 defer std.testing.allocator.free(text);
740 std.testing.expectEqualSlices(u8, "arm-linux-musleabihf", text);
741 }
742 {
743 const cross_target = try CrossTarget.parse(.{
744 .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
745 .cpu_features = "generic+v8a",
746 });
747 const target = cross_target.toTarget();
748
749 std.testing.expect(target.cpu.arch == .aarch64);
750 std.testing.expect(target.os.tag == .linux);
751 std.testing.expect(target.os.version_range.linux.range.min.major == 3);
752 std.testing.expect(target.os.version_range.linux.range.min.minor == 10);
753 std.testing.expect(target.os.version_range.linux.range.min.patch == 0);
754 std.testing.expect(target.os.version_range.linux.range.max.major == 4);
755 std.testing.expect(target.os.version_range.linux.range.max.minor == 4);
756 std.testing.expect(target.os.version_range.linux.range.max.patch == 1);
757 std.testing.expect(target.os.version_range.linux.glibc.major == 2);
758 std.testing.expect(target.os.version_range.linux.glibc.minor == 27);
759 std.testing.expect(target.os.version_range.linux.glibc.patch == 0);
760 std.testing.expect(target.abi == .gnu);
761
762 const text = try cross_target.zigTriple(std.testing.allocator);
763 defer std.testing.allocator.free(text);
764 std.testing.expectEqualSlices(u8, "aarch64-linux.3.10...4.4.1-gnu.2.27", text);
765 }
766}
src-self-hosted/stage2.zig+77-66
......@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
1010const ArrayList = std.ArrayList;
1111const Buffer = std.Buffer;
1212const Target = std.Target;
13const CrossTarget = std.zig.CrossTarget;
1314const self_hosted_main = @import("main.zig");
1415const errmsg = @import("errmsg.zig");
1516const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
......@@ -87,7 +88,7 @@ const Error = extern enum {
8788 NotLazy,
8889 IsAsync,
8990 ImportOutsidePkgPath,
90 UnknownCpu,
91 UnknownCpuModel,
9192 UnknownCpuFeature,
9293 InvalidCpuFeatures,
9394 InvalidLlvmCpuFeaturesFormat,
......@@ -634,13 +635,9 @@ export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
634635}
635636
636637fn cmdTargets(zig_triple: [*:0]const u8) !void {
637 var target = try Target.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
638 target.cpu = blk: {
639 const llvm = @import("llvm.zig");
640 const llvm_cpu_name = llvm.GetHostCPUName();
641 const llvm_cpu_features = llvm.GetNativeFeatures();
642 break :blk try detectNativeCpuWithLLVM(target.cpu.arch, llvm_cpu_name, llvm_cpu_features);
643 };
638 var cross_target = try CrossTarget.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
639 var dynamic_linker: ?[*:0]u8 = null;
640 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
644641 return @import("print_targets.zig").cmdTargets(
645642 std.heap.c_allocator,
646643 &[0][]u8{},
......@@ -661,7 +658,6 @@ export fn stage2_target_parse(
661658 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
662659 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
663660 error.MissingOperatingSystem => return .MissingOperatingSystem,
664 error.MissingArchitecture => return .MissingArchitecture,
665661 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
666662 error.UnexpectedExtraField => return .SemanticAnalyzeFail,
667663 error.InvalidAbiVersion => return .InvalidAbiVersion,
......@@ -681,44 +677,42 @@ fn stage2TargetParse(
681677 zig_triple_oz: ?[*:0]const u8,
682678 mcpu_oz: ?[*:0]const u8,
683679) !void {
684 const target: std.build.Target = if (zig_triple_oz) |zig_triple_z| blk: {
680 const target: CrossTarget = if (zig_triple_oz) |zig_triple_z| blk: {
685681 const zig_triple = mem.toSliceConst(u8, zig_triple_z);
686682 const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline";
687 var diags: std.Target.ParseOptions.Diagnostics = .{};
688 break :blk std.build.Target{
689 .Cross = Target.parse(.{
690 .arch_os_abi = zig_triple,
691 .cpu_features = mcpu,
692 .diagnostics = &diags,
693 }) catch |err| switch (err) {
694 error.UnknownCpu => {
695 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
696 diags.cpu_name.?,
697 @tagName(diags.arch.?),
698 });
699 for (diags.arch.?.allCpuModels()) |cpu| {
700 std.debug.warn(" {}\n", .{cpu.name});
701 }
702 process.exit(1);
703 },
704 error.UnknownCpuFeature => {
705 std.debug.warn(
706 \\Unknown CPU feature: '{}'
707 \\Available CPU features for architecture '{}':
708 \\
709 , .{
710 diags.unknown_feature_name,
711 @tagName(diags.arch.?),
712 });
713 for (diags.arch.?.allFeaturesList()) |feature| {
714 std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
715 }
716 process.exit(1);
717 },
718 else => |e| return e,
683 var diags: CrossTarget.ParseOptions.Diagnostics = .{};
684 break :blk CrossTarget.parse(.{
685 .arch_os_abi = zig_triple,
686 .cpu_features = mcpu,
687 .diagnostics = &diags,
688 }) catch |err| switch (err) {
689 error.UnknownCpuModel => {
690 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
691 diags.cpu_name.?,
692 @tagName(diags.arch.?),
693 });
694 for (diags.arch.?.allCpuModels()) |cpu| {
695 std.debug.warn(" {}\n", .{cpu.name});
696 }
697 process.exit(1);
719698 },
699 error.UnknownCpuFeature => {
700 std.debug.warn(
701 \\Unknown CPU feature: '{}'
702 \\Available CPU features for architecture '{}':
703 \\
704 , .{
705 diags.unknown_feature_name,
706 @tagName(diags.arch.?),
707 });
708 for (diags.arch.?.allFeaturesList()) |feature| {
709 std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
710 }
711 process.exit(1);
712 },
713 else => |e| return e,
720714 };
721 } else std.build.Target.Native;
715 } else .{};
722716
723717 try stage1_target.fromTarget(target);
724718}
......@@ -908,8 +902,8 @@ const Stage2Target = extern struct {
908902
909903 dynamic_linker: ?[*:0]const u8,
910904
911 fn toTarget(in_target: Stage2Target) std.build.Target {
912 if (in_target.is_native) return .Native;
905 fn toTarget(in_target: Stage2Target) CrossTarget {
906 if (in_target.is_native) return .{};
913907
914908 const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
915909 const in_os = in_target.os;
......@@ -924,28 +918,11 @@ const Stage2Target = extern struct {
924918 };
925919 }
926920
927 fn fromTarget(self: *Stage2Target, build_target: std.build.Target) !void {
921 fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
928922 const allocator = std.heap.c_allocator;
929 var dynamic_linker: ?[*:0]u8 = null;
930 const target = switch (build_target) {
931 .Native => blk: {
932 const info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
933 if (info.dynamic_linker) |dl| {
934 dynamic_linker = dl.ptr;
935 }
936923
937 // TODO we want to just use info.target but implementing CPU model & feature detection is todo
938 // so here we rely on LLVM
939 const llvm = @import("llvm.zig");
940 const llvm_cpu_name = llvm.GetHostCPUName();
941 const llvm_cpu_features = llvm.GetNativeFeatures();
942 const arch = std.Target.current.cpu.arch;
943 var t = info.target;
944 t.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
945 break :blk t;
946 },
947 .Cross => |t| t,
948 };
924 var dynamic_linker: ?[*:0]u8 = null;
925 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
949926
950927 var cache_hash = try std.Buffer.allocPrint(allocator, "{}\n{}\n", .{
951928 target.cpu.model.name,
......@@ -1145,7 +1122,7 @@ const Stage2Target = extern struct {
11451122 .cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
11461123 .os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
11471124 .cache_hash = cache_hash.toOwnedSlice().ptr,
1148 .is_native = build_target == .Native,
1125 .is_native = cross_target.isNative(),
11491126 .glibc_version = glibc_version,
11501127 .dynamic_linker = dynamic_linker,
11511128 };
......@@ -1156,6 +1133,40 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
11561133 return @intToEnum(Enum, @intCast(@TagType(Enum), int));
11571134}
11581135
1136/// TODO move dynamic linker to be part of the target
1137/// TODO self-host this function
1138fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
1139 var adjusted_target = cross_target.toTarget();
1140 if (cross_target.isNativeCpu() or cross_target.isNativeOs()) {
1141 const detected_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
1142 if (cross_target.isNativeCpu()) {
1143 adjusted_target.cpu = detected_info.target.cpu;
1144
1145 // TODO We want to just use detected_info.target but implementing
1146 // CPU model & feature detection is todo so here we rely on LLVM.
1147 // There is another occurrence of this; search for detectNativeCpuWithLLVM.
1148 const llvm = @import("llvm.zig");
1149 const llvm_cpu_name = llvm.GetHostCPUName();
1150 const llvm_cpu_features = llvm.GetNativeFeatures();
1151 const arch = std.Target.current.cpu.arch;
1152 adjusted_target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
1153 }
1154 if (cross_target.isNativeOs()) {
1155 adjusted_target.os = detected_info.target.os;
1156
1157 if (detected_info.dynamic_linker) |dl| {
1158 dynamic_linker_ptr.* = dl.ptr;
1159 }
1160 if (cross_target.abi == null) {
1161 adjusted_target.abi = detected_info.target.abi;
1162 }
1163 } else if (cross_target.abi == null) {
1164 adjusted_target.abi = Target.Abi.default(adjusted_target.cpu.arch, adjusted_target.os);
1165 }
1166 }
1167 return adjusted_target;
1168}
1169
11591170// ABI warning
11601171const Stage2GLibCVersion = extern struct {
11611172 major: u32,
test/compile_errors.zig+10-14
......@@ -1,5 +1,5 @@
11const tests = @import("tests.zig");
2const Target = @import("std").Target;
2const std = @import("std");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
55 cases.addTest("type mismatch with tuple concatenation",
......@@ -386,12 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
386386 , &[_][]const u8{
387387 "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
388388 });
389 tc.target = tests.Target{
390 .Cross = .{
391 .cpu = Target.Cpu.baseline(.wasm32),
392 .os = Target.Os.defaultVersionRange(.wasi),
393 .abi = .none,
394 },
389 tc.target = std.zig.CrossTarget{
390 .cpu_arch = .wasm32,
391 .os_tag = .wasi,
392 .abi = .none,
395393 };
396394 break :x tc;
397395 });
......@@ -787,12 +785,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
787785 , &[_][]const u8{
788786 "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
789787 });
790 tc.target = tests.Target{
791 .Cross = .{
792 .cpu = Target.Cpu.baseline(.x86_64),
793 .os = Target.Os.defaultVersionRange(.linux),
794 .abi = .gnu,
795 },
788 tc.target = std.zig.CrossTarget{
789 .cpu_arch = .x86_64,
790 .os_tag = .linux,
791 .abi = .gnu,
796792 };
797793 break :x tc;
798794 });
......@@ -1452,7 +1448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14521448 "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
14531449 });
14541450
1455 if (Target.current.os.tag == .linux) {
1451 if (std.Target.current.os.tag == .linux) {
14561452 cases.addTest("implicit dependency on libc",
14571453 \\extern "c" fn exit(u8) void;
14581454 \\export fn entry() void {
test/src/translate_c.zig+3-2
......@@ -7,6 +7,7 @@ const fmt = std.fmt;
77const mem = std.mem;
88const fs = std.fs;
99const warn = std.debug.warn;
10const CrossTarget = std.zig.CrossTarget;
1011
1112pub const TranslateCContext = struct {
1213 b: *build.Builder,
......@@ -19,7 +20,7 @@ pub const TranslateCContext = struct {
1920 sources: ArrayList(SourceFile),
2021 expected_lines: ArrayList([]const u8),
2122 allow_warnings: bool,
22 target: build.Target = .Native,
23 target: CrossTarget = CrossTarget{},
2324
2425 const SourceFile = struct {
2526 filename: []const u8,
......@@ -75,7 +76,7 @@ pub const TranslateCContext = struct {
7576 pub fn addWithTarget(
7677 self: *TranslateCContext,
7778 name: []const u8,
78 target: build.Target,
79 target: CrossTarget,
7980 source: []const u8,
8081 expected_lines: []const []const u8,
8182 ) void {
test/tests.zig+82-122
......@@ -3,7 +3,7 @@ const builtin = std.builtin;
33const debug = std.debug;
44const warn = debug.warn;
55const build = std.build;
6pub const Target = build.Target;
6const CrossTarget = std.zig.CrossTarget;
77const Buffer = std.Buffer;
88const io = std.io;
99const fs = std.fs;
......@@ -30,7 +30,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla
3030pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;
3131
3232const TestTarget = struct {
33 target: build.Target = .Native,
33 target: CrossTarget = @as(CrossTarget, .{}),
3434 mode: builtin.Mode = .Debug,
3535 link_libc: bool = false,
3636 single_threaded: bool = false,
......@@ -52,105 +52,85 @@ const test_targets = blk: {
5252 },
5353
5454 TestTarget{
55 .target = Target{
56 .Cross = .{
57 .cpu = std.Target.Cpu.baseline(.x86_64),
58 .os = std.Target.Os.defaultVersionRange(.linux),
59 .abi = .none,
60 },
55 .target = .{
56 .cpu_arch = .x86_64,
57 .os_tag = .linux,
58 .abi = .none,
6159 },
6260 },
6361 TestTarget{
64 .target = Target{
65 .Cross = .{
66 .cpu = std.Target.Cpu.baseline(.x86_64),
67 .os = std.Target.Os.defaultVersionRange(.linux),
68 .abi = .gnu,
69 },
62 .target = .{
63 .cpu_arch = .x86_64,
64 .os_tag = .linux,
65 .abi = .gnu,
7066 },
7167 .link_libc = true,
7268 },
7369 TestTarget{
74 .target = Target{
75 .Cross = .{
76 .cpu = std.Target.Cpu.baseline(.x86_64),
77 .os = std.Target.Os.defaultVersionRange(.linux),
78 .abi = .musl,
79 },
70 .target = .{
71 .cpu_arch = .x86_64,
72 .os_tag = .linux,
73 .abi = .musl,
8074 },
8175 .link_libc = true,
8276 },
8377
8478 TestTarget{
85 .target = Target{
86 .Cross = .{
87 .cpu = std.Target.Cpu.baseline(.i386),
88 .os = std.Target.Os.defaultVersionRange(.linux),
89 .abi = .none,
90 },
79 .target = .{
80 .cpu_arch = .i386,
81 .os_tag = .linux,
82 .abi = .none,
9183 },
9284 },
9385 TestTarget{
94 .target = Target{
95 .Cross = .{
96 .cpu = std.Target.Cpu.baseline(.i386),
97 .os = std.Target.Os.defaultVersionRange(.linux),
98 .abi = .musl,
99 },
86 .target = .{
87 .cpu_arch = .i386,
88 .os_tag = .linux,
89 .abi = .musl,
10090 },
10191 .link_libc = true,
10292 },
10393
10494 TestTarget{
105 .target = Target{
106 .Cross = .{
107 .cpu = std.Target.Cpu.baseline(.aarch64),
108 .os = std.Target.Os.defaultVersionRange(.linux),
109 .abi = .none,
110 },
95 .target = .{
96 .cpu_arch = .aarch64,
97 .os_tag = .linux,
98 .abi = .none,
11199 },
112100 },
113101 TestTarget{
114 .target = Target{
115 .Cross = .{
116 .cpu = std.Target.Cpu.baseline(.aarch64),
117 .os = std.Target.Os.defaultVersionRange(.linux),
118 .abi = .musl,
119 },
102 .target = .{
103 .cpu_arch = .aarch64,
104 .os_tag = .linux,
105 .abi = .musl,
120106 },
121107 .link_libc = true,
122108 },
123109 TestTarget{
124 .target = Target{
125 .Cross = .{
126 .cpu = std.Target.Cpu.baseline(.aarch64),
127 .os = std.Target.Os.defaultVersionRange(.linux),
128 .abi = .gnu,
129 },
110 .target = .{
111 .cpu_arch = .aarch64,
112 .os_tag = .linux,
113 .abi = .gnu,
130114 },
131115 .link_libc = true,
132116 },
133117
134118 TestTarget{
135 .target = .{
136 .Cross = std.Target.parse(.{
137 .arch_os_abi = "arm-linux-none",
138 .cpu_features = "generic+v8a",
139 }) catch unreachable,
140 },
119 .target = CrossTarget.parse(.{
120 .arch_os_abi = "arm-linux-none",
121 .cpu_features = "generic+v8a",
122 }) catch unreachable,
141123 },
142124 TestTarget{
143 .target = .{
144 .Cross = std.Target.parse(.{
145 .arch_os_abi = "arm-linux-musleabihf",
146 .cpu_features = "generic+v8a",
147 }) catch unreachable,
148 },
125 .target = CrossTarget.parse(.{
126 .arch_os_abi = "arm-linux-musleabihf",
127 .cpu_features = "generic+v8a",
128 }) catch unreachable,
149129 .link_libc = true,
150130 },
151131 // TODO https://github.com/ziglang/zig/issues/3287
152132 //TestTarget{
153 // .target = std.Target.parse(.{
133 // .target = CrossTarget.parse(.{
154134 // .arch_os_abi = "arm-linux-gnueabihf",
155135 // .cpu_features = "generic+v8a",
156136 // }) catch unreachable,
......@@ -158,75 +138,61 @@ const test_targets = blk: {
158138 //},
159139
160140 TestTarget{
161 .target = Target{
162 .Cross = .{
163 .cpu = std.Target.Cpu.baseline(.mipsel),
164 .os = std.Target.Os.defaultVersionRange(.linux),
165 .abi = .none,
166 },
141 .target = .{
142 .cpu_arch = .mipsel,
143 .os_tag = .linux,
144 .abi = .none,
167145 },
168146 },
169147 TestTarget{
170 .target = Target{
171 .Cross = .{
172 .cpu = std.Target.Cpu.baseline(.mipsel),
173 .os = std.Target.Os.defaultVersionRange(.linux),
174 .abi = .musl,
175 },
148 .target = .{
149 .cpu_arch = .mipsel,
150 .os_tag = .linux,
151 .abi = .musl,
176152 },
177153 .link_libc = true,
178154 },
179155
180156 TestTarget{
181 .target = Target{
182 .Cross = .{
183 .cpu = std.Target.Cpu.baseline(.x86_64),
184 .os = std.Target.Os.defaultVersionRange(.macosx),
185 .abi = .gnu,
186 },
157 .target = .{
158 .cpu_arch = .x86_64,
159 .os_tag = .macosx,
160 .abi = .gnu,
187161 },
188162 // TODO https://github.com/ziglang/zig/issues/3295
189163 .disable_native = true,
190164 },
191165
192166 TestTarget{
193 .target = Target{
194 .Cross = .{
195 .cpu = std.Target.Cpu.baseline(.i386),
196 .os = std.Target.Os.defaultVersionRange(.windows),
197 .abi = .msvc,
198 },
167 .target = .{
168 .cpu_arch = .i386,
169 .os_tag = .windows,
170 .abi = .msvc,
199171 },
200172 },
201173
202174 TestTarget{
203 .target = Target{
204 .Cross = .{
205 .cpu = std.Target.Cpu.baseline(.x86_64),
206 .os = std.Target.Os.defaultVersionRange(.windows),
207 .abi = .msvc,
208 },
175 .target = .{
176 .cpu_arch = .x86_64,
177 .os_tag = .windows,
178 .abi = .msvc,
209179 },
210180 },
211181
212182 TestTarget{
213 .target = Target{
214 .Cross = .{
215 .cpu = std.Target.Cpu.baseline(.i386),
216 .os = std.Target.Os.defaultVersionRange(.windows),
217 .abi = .gnu,
218 },
183 .target = .{
184 .cpu_arch = .i386,
185 .os_tag = .windows,
186 .abi = .gnu,
219187 },
220188 .link_libc = true,
221189 },
222190
223191 TestTarget{
224 .target = Target{
225 .Cross = .{
226 .cpu = std.Target.Cpu.baseline(.x86_64),
227 .os = std.Target.Os.defaultVersionRange(.windows),
228 .abi = .gnu,
229 },
192 .target = .{
193 .cpu_arch = .x86_64,
194 .os_tag = .windows,
195 .abi = .gnu,
230196 },
231197 .link_libc = true,
232198 },
......@@ -435,13 +401,13 @@ pub fn addPkgTests(
435401 const step = b.step(b.fmt("test-{}", .{name}), desc);
436402
437403 for (test_targets) |test_target| {
438 if (skip_non_native and test_target.target != .Native)
404 if (skip_non_native and !test_target.target.isNative())
439405 continue;
440406
441407 if (skip_libc and test_target.link_libc)
442408 continue;
443409
444 if (test_target.link_libc and test_target.target.getTarget().osRequiresLibC()) {
410 if (test_target.link_libc and test_target.target.getOs().requiresLibC()) {
445411 // This would be a redundant test.
446412 continue;
447413 }
......@@ -451,8 +417,8 @@ pub fn addPkgTests(
451417
452418 const ArchTag = @TagType(builtin.Arch);
453419 if (test_target.disable_native and
454 test_target.target.getOs() == std.Target.current.os.tag and
455 test_target.target.getArch() == std.Target.current.cpu.arch)
420 test_target.target.getOsTag() == std.Target.current.os.tag and
421 test_target.target.getCpuArch() == std.Target.current.cpu.arch)
456422 {
457423 continue;
458424 }
......@@ -462,17 +428,14 @@ pub fn addPkgTests(
462428 } else false;
463429 if (!want_this_mode) continue;
464430
465 const libc_prefix = if (test_target.target.getTarget().osRequiresLibC())
431 const libc_prefix = if (test_target.target.getOs().requiresLibC())
466432 ""
467433 else if (test_target.link_libc)
468434 "c"
469435 else
470436 "bare";
471437
472 const triple_prefix = if (test_target.target == .Native)
473 @as([]const u8, "native")
474 else
475 test_target.target.zigTriple(b.allocator) catch unreachable;
438 const triple_prefix = test_target.target.zigTriple(b.allocator) catch unreachable;
476439
477440 const these_tests = b.addTest(root_src);
478441 const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
......@@ -486,7 +449,7 @@ pub fn addPkgTests(
486449 these_tests.single_threaded = test_target.single_threaded;
487450 these_tests.setFilter(test_filter);
488451 these_tests.setBuildMode(test_target.mode);
489 these_tests.setTheTarget(test_target.target);
452 these_tests.setTarget(test_target.target);
490453 if (test_target.link_libc) {
491454 these_tests.linkSystemLibrary("c");
492455 }
......@@ -716,7 +679,7 @@ pub const CompileErrorContext = struct {
716679 link_libc: bool,
717680 is_exe: bool,
718681 is_test: bool,
719 target: Target = .Native,
682 target: CrossTarget = CrossTarget{},
720683
721684 const SourceFile = struct {
722685 filename: []const u8,
......@@ -808,12 +771,9 @@ pub const CompileErrorContext = struct {
808771 zig_args.append("--output-dir") catch unreachable;
809772 zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;
810773
811 switch (self.case.target) {
812 .Native => {},
813 .Cross => {
814 try zig_args.append("-target");
815 try zig_args.append(try self.case.target.zigTriple(b.allocator));
816 },
774 if (!self.case.target.isNative()) {
775 try zig_args.append("-target");
776 try zig_args.append(try self.case.target.zigTriple(b.allocator));
817777 }
818778
819779 switch (self.build_mode) {
test/translate_c.zig+15-21
......@@ -1,6 +1,6 @@
11const tests = @import("tests.zig");
22const std = @import("std");
3const Target = std.Target;
3const CrossTarget = std.zig.CrossTarget;
44
55pub fn addCases(cases: *tests.TranslateCContext) void {
66 cases.add("macro line continuation",
......@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
665665 \\}
666666 });
667667
668 if (Target.current.os.tag != .windows) {
668 if (std.Target.current.os.tag != .windows) {
669669 // Windows treats this as an enum with type c_int
670670 cases.add("big negative enum init values when C ABI supports long long enums",
671671 \\enum EnumWithInits {
......@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10641064 \\}
10651065 });
10661066
1067 if (Target.current.os.tag != .windows) {
1067 if (std.Target.current.os.tag != .windows) {
10681068 // sysv_abi not currently supported on windows
10691069 cases.add("Macro qualified functions",
10701070 \\void __attribute__((sysv_abi)) foo(void);
......@@ -1094,11 +1094,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10941094 });
10951095
10961096 cases.addWithTarget("Calling convention", .{
1097 .Cross = .{
1098 .cpu = Target.Cpu.baseline(.i386),
1099 .os = Target.Os.defaultVersionRange(.linux),
1100 .abi = .none,
1101 },
1097 .cpu_arch = .i386,
1098 .os_tag = .linux,
1099 .abi = .none,
11021100 },
11031101 \\void __attribute__((fastcall)) foo1(float *a);
11041102 \\void __attribute__((stdcall)) foo2(float *a);
......@@ -1113,12 +1111,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11131111 \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;
11141112 });
11151113
1116 cases.addWithTarget("Calling convention", .{
1117 .Cross = Target.parse(.{
1118 .arch_os_abi = "arm-linux-none",
1119 .cpu_features = "generic+v8_5a",
1120 }) catch unreachable,
1121 },
1114 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
1115 .arch_os_abi = "arm-linux-none",
1116 .cpu_features = "generic+v8_5a",
1117 }) catch unreachable,
11221118 \\void __attribute__((pcs("aapcs"))) foo1(float *a);
11231119 \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a);
11241120 , &[_][]const u8{
......@@ -1126,12 +1122,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11261122 \\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;
11271123 });
11281124
1129 cases.addWithTarget("Calling convention", .{
1130 .Cross = Target.parse(.{
1131 .arch_os_abi = "aarch64-linux-none",
1132 .cpu_features = "generic+v8_5a",
1133 }) catch unreachable,
1134 },
1125 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
1126 .arch_os_abi = "aarch64-linux-none",
1127 .cpu_features = "generic+v8_5a",
1128 }) catch unreachable,
11351129 \\void __attribute__((aarch64_vector_pcs)) foo1(float *a);
11361130 , &[_][]const u8{
11371131 \\pub fn foo1(a: [*c]f32) callconv(.Vectorcall) void;
......@@ -1600,7 +1594,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16001594 \\}
16011595 });
16021596
1603 if (Target.current.os.tag != .windows) {
1597 if (std.Target.current.os.tag != .windows) {
16041598 // When clang uses the <arch>-windows-none triple it behaves as MSVC and
16051599 // interprets the inner `struct Bar` as an anonymous structure
16061600 cases.add("type referenced struct",