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
signature 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 {...@@ -298,7 +298,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
298 }298 }
299 dependOnLib(b, exe, ctx.llvm);299 dependOnLib(b, exe, ctx.llvm);
300300
301 if (exe.target.getOs() == .linux) {301 if (exe.target.getOsTag() == .linux) {
302 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",302 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
303 \\Unable to determine path to libstdc++.a303 \\Unable to determine path to libstdc++.a
304 \\On Fedora, install libstdc++-static and try again.304 \\On Fedora, install libstdc++-static and try again.
doc/docgen.zig+2-2
...@@ -10,8 +10,8 @@ const testing = std.testing;...@@ -10,8 +10,8 @@ const testing = std.testing;
1010
11const max_doc_file_size = 10 * 1024 * 1024;11const max_doc_file_size = 10 * 1024 * 1024;
1212
13const exe_ext = @as(std.build.Target, std.build.Target.Native).exeFileExt();13const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();
14const obj_ext = @as(std.build.Target, std.build.Target.Native).oFileExt();14const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt();
15const tmp_dir_name = "docgen_tmp";15const tmp_dir_name = "docgen_tmp";
16const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;16const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1717
lib/std/build.zig+108-190
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = std.builtin;
3const io = std.io;3const io = std.io;
4const fs = std.fs;4const fs = std.fs;
5const mem = std.mem;5const mem = std.mem;
...@@ -15,6 +15,7 @@ const BufSet = std.BufSet;...@@ -15,6 +15,7 @@ const BufSet = std.BufSet;
15const BufMap = std.BufMap;15const BufMap = std.BufMap;
16const fmt_lib = std.fmt;16const fmt_lib = std.fmt;
17const File = std.fs.File;17const File = std.fs.File;
18const CrossTarget = std.zig.CrossTarget;
1819
19pub const FmtStep = @import("build/fmt.zig").FmtStep;20pub const FmtStep = @import("build/fmt.zig").FmtStep;
20pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;21pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;
...@@ -521,24 +522,77 @@ pub const Builder = struct {...@@ -521,24 +522,77 @@ pub const Builder = struct {
521 return mode;522 return mode;
522 }523 }
523524
524 /// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets.525 pub const StandardTargetOptionsArgs = struct {
525 pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target {526 whitelist: ?[]const CrossTarget = null,
526 if (supported_targets) |target_list| {527
527 // TODO detect multiple args and emit an error message528 default_target: CrossTarget = .{},
528 // there's probably a better way to collect the target529 };
529 for (target_list) |targ| {530
530 const targ_str = targ.zigTriple(self.allocator) catch unreachable;531 /// Exposes standard `zig build` options for choosing a target.
531 const targ_desc = targ.allocDescription(self.allocator) catch unreachable;532 pub fn standardTargetOptions(self: *Builder, args: StandardTargetOptionsArgs) CrossTarget {
532 const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false;533 const triple = self.option(
533 if (this_targ_opt) {534 []const u8,
534 return targ;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;
535 }581 }
536 }582 }
537 return Target.Native;583 std.debug.warn("Chosen target '{}' does not match one of the supported targets:\n", .{
538 } else {584 selected_canonicalized_triple,
539 const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native;585 });
540 return Target.parse(.{ .arch_os_abi = target_str }) catch unreachable; // TODO better error message for bad target586 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);
541 }593 }
594
595 return selected_target;
542 }596 }
543597
544 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {598 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
...@@ -796,7 +850,7 @@ pub const Builder = struct {...@@ -796,7 +850,7 @@ pub const Builder = struct {
796850
797 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {851 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
798 // TODO report error for ambiguous situations852 // TODO report error for ambiguous situations
799 const exe_extension = (Target{ .Native = {} }).exeFileExt();853 const exe_extension = @as(CrossTarget, .{}).exeFileExt();
800 for (self.search_prefixes.toSliceConst()) |search_prefix| {854 for (self.search_prefixes.toSliceConst()) |search_prefix| {
801 for (names) |name| {855 for (names) |name| {
802 if (fs.path.isAbsolute(name)) {856 if (fs.path.isAbsolute(name)) {
...@@ -978,111 +1032,11 @@ test "builder.findProgram compiles" {...@@ -978,111 +1032,11 @@ test "builder.findProgram compiles" {
978 _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;1032 _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
979}1033}
9801034
981/// Deprecated. Use `builtin.Version`.1035/// Deprecated. Use `std.builtin.Version`.
982pub const Version = builtin.Version;1036pub const Version = builtin.Version;
9831037
984/// Deprecated. Use `std.Target`.1038/// Deprecated. Use `std.zig.CrossTarget`.
985pub const CrossTarget = std.Target;1039pub const Target = std.zig.CrossTarget;
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};
10861040
1087pub const Pkg = struct {1041pub const Pkg = struct {
1088 name: []const u8,1042 name: []const u8,
...@@ -1135,7 +1089,7 @@ pub const LibExeObjStep = struct {...@@ -1135,7 +1089,7 @@ pub const LibExeObjStep = struct {
1135 step: Step,1089 step: Step,
1136 builder: *Builder,1090 builder: *Builder,
1137 name: []const u8,1091 name: []const u8,
1138 target: Target,1092 target: CrossTarget = CrossTarget{},
1139 linker_script: ?[]const u8 = null,1093 linker_script: ?[]const u8 = null,
1140 version_script: ?[]const u8 = null,1094 version_script: ?[]const u8 = null,
1141 out_filename: []const u8,1095 out_filename: []const u8,
...@@ -1188,7 +1142,6 @@ pub const LibExeObjStep = struct {...@@ -1188,7 +1142,6 @@ pub const LibExeObjStep = struct {
1188 install_step: ?*InstallArtifactStep,1142 install_step: ?*InstallArtifactStep,
11891143
1190 libc_file: ?[]const u8 = null,1144 libc_file: ?[]const u8 = null,
1191 target_glibc: ?Version = null,
11921145
1193 valgrind_support: ?bool = null,1146 valgrind_support: ?bool = null,
11941147
...@@ -1288,7 +1241,6 @@ pub const LibExeObjStep = struct {...@@ -1288,7 +1241,6 @@ pub const LibExeObjStep = struct {
1288 .kind = kind,1241 .kind = kind,
1289 .root_src = root_src,1242 .root_src = root_src,
1290 .name = name,1243 .name = name,
1291 .target = Target.Native,
1292 .frameworks = BufSet.init(builder.allocator),1244 .frameworks = BufSet.init(builder.allocator),
1293 .step = Step.init(name, builder.allocator, make),1245 .step = Step.init(name, builder.allocator, make),
1294 .version = ver,1246 .version = ver,
...@@ -1379,36 +1331,11 @@ pub const LibExeObjStep = struct {...@@ -1379,36 +1331,11 @@ pub const LibExeObjStep = struct {
1379 }1331 }
1380 }1332 }
13811333
1382 /// Deprecated. Use `setTheTarget`.1334 pub fn setTarget(self: *LibExeObjStep, target: CrossTarget) void {
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 {
1400 self.target = target;1335 self.target = target;
1401 self.computeOutFileNames();1336 self.computeOutFileNames();
1402 }1337 }
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
1412 pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {1339 pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
1413 self.output_dir = self.builder.dupePath(dir);1340 self.output_dir = self.builder.dupePath(dir);
1414 }1341 }
...@@ -2002,47 +1929,41 @@ pub const LibExeObjStep = struct {...@@ -2002,47 +1929,41 @@ pub const LibExeObjStep = struct {
2002 try zig_args.append(@tagName(self.code_model));1929 try zig_args.append(@tagName(self.code_model));
2003 }1930 }
20041931
2005 switch (self.target) {1932 if (!self.target.isNative()) {
2006 .Native => {},1933 try zig_args.append("-target");
2007 .Cross => |cross| {1934 try zig_args.append(try self.target.zigTriple(builder.allocator));
2008 try zig_args.append("-target");
2009 try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
20101935
2011 const all_features = self.target.getArch().allFeaturesList();1936 // TODO this logic can disappear if cpu model + features becomes part of the target triple
2012 var populated_cpu_features = cross.cpu.model.features;1937 const cross = self.target.toTarget();
2013 populated_cpu_features.populateDependencies(all_features);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)) {1942 if (populated_cpu_features.eql(cross.cpu.features)) {
2016 // The CPU name alone is sufficient.1943 // The CPU name alone is sufficient.
2017 // If it is the baseline CPU, no command line args are required.1944 // 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) {1945 if (cross.cpu.model != std.Target.Cpu.baseline(cross.cpu.arch).model) {
2019 try zig_args.append("-mcpu");1946 try zig_args.append("-mcpu");
2020 try zig_args.append(cross.cpu.model.name);1947 try zig_args.append(cross.cpu.model.name);
2021 }1948 }
2022 } else {1949 } else {
2023 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");1950 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
2024 try mcpu_buffer.append(cross.cpu.model.name);1951 try mcpu_buffer.append(cross.cpu.model.name);
20251952
2026 for (all_features) |feature, i_usize| {1953 for (all_features) |feature, i_usize| {
2027 const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);1954 const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
2028 const in_cpu_set = populated_cpu_features.isEnabled(i);1955 const in_cpu_set = populated_cpu_features.isEnabled(i);
2029 const in_actual_set = cross.cpu.features.isEnabled(i);1956 const in_actual_set = cross.cpu.features.isEnabled(i);
2030 if (in_cpu_set and !in_actual_set) {1957 if (in_cpu_set and !in_actual_set) {
2031 try mcpu_buffer.appendByte('-');1958 try mcpu_buffer.appendByte('-');
2032 try mcpu_buffer.append(feature.name);1959 try mcpu_buffer.append(feature.name);
2033 } else if (!in_cpu_set and in_actual_set) {1960 } else if (!in_cpu_set and in_actual_set) {
2034 try mcpu_buffer.appendByte('+');1961 try mcpu_buffer.appendByte('+');
2035 try mcpu_buffer.append(feature.name);1962 try mcpu_buffer.append(feature.name);
2036 }
2037 }1963 }
2038 try zig_args.append(mcpu_buffer.toSliceConst());
2039 }1964 }
2040 },1965 try zig_args.append(mcpu_buffer.toSliceConst());
2041 }1966 }
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 }));
2046 }1967 }
20471968
2048 if (self.linker_script) |linker_script| {1969 if (self.linker_script) |linker_script| {
...@@ -2517,10 +2438,7 @@ const VcpkgRootStatus = enum {...@@ -2517,10 +2438,7 @@ const VcpkgRootStatus = enum {
2517 Found,2438 Found,
2518};2439};
25192440
2520pub const VcpkgLinkage = enum {2441pub const VcpkgLinkage = std.builtin.LinkMode;
2521 Static,
2522 Dynamic,
2523};
25242442
2525pub const InstallDir = enum {2443pub const InstallDir = enum {
2526 Prefix,2444 Prefix,
lib/std/build/translate_c.zig+6-8
...@@ -7,6 +7,7 @@ const LibExeObjStep = build.LibExeObjStep;...@@ -7,6 +7,7 @@ const LibExeObjStep = build.LibExeObjStep;
7const CheckFileStep = build.CheckFileStep;7const CheckFileStep = build.CheckFileStep;
8const fs = std.fs;8const fs = std.fs;
9const mem = std.mem;9const mem = std.mem;
10const CrossTarget = std.zig.CrossTarget;
1011
11pub const TranslateCStep = struct {12pub const TranslateCStep = struct {
12 step: Step,13 step: Step,
...@@ -14,7 +15,7 @@ pub const TranslateCStep = struct {...@@ -14,7 +15,7 @@ pub const TranslateCStep = struct {
14 source: build.FileSource,15 source: build.FileSource,
15 output_dir: ?[]const u8,16 output_dir: ?[]const u8,
16 out_basename: []const u8,17 out_basename: []const u8,
17 target: build.Target = .Native,18 target: CrossTarget = CrossTarget{},
1819
19 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {20 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
20 const self = builder.allocator.create(TranslateCStep) catch unreachable;21 const self = builder.allocator.create(TranslateCStep) catch unreachable;
...@@ -39,7 +40,7 @@ pub const TranslateCStep = struct {...@@ -39,7 +40,7 @@ pub const TranslateCStep = struct {
39 ) catch unreachable;40 ) catch unreachable;
40 }41 }
4142
42 pub fn setTarget(self: *TranslateCStep, target: build.Target) void {43 pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
43 self.target = target;44 self.target = target;
44 }45 }
4546
...@@ -63,12 +64,9 @@ pub const TranslateCStep = struct {...@@ -63,12 +64,9 @@ pub const TranslateCStep = struct {
63 try argv_list.append("--cache");64 try argv_list.append("--cache");
64 try argv_list.append("on");65 try argv_list.append("on");
6566
66 switch (self.target) {67 if (!self.target.isNative()) {
67 .Native => {},68 try argv_list.append("-target");
68 .Cross => {69 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
69 try argv_list.append("-target");
70 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
71 },
72 }70 }
7371
74 try argv_list.append(self.source.getPath(self.builder));72 try argv_list.append(self.source.getPath(self.builder));
lib/std/builtin.zig+23
...@@ -429,6 +429,29 @@ pub const Version = struct {...@@ -429,6 +429,29 @@ pub const Version = struct {
429 .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),429 .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
430 };430 };
431 }431 }
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 }
432};455};
433456
434/// This data structure is used by the Zig language code generation and457/// 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 {...@@ -60,6 +60,16 @@ pub const Target = struct {
60 else => false,60 else => false,
61 };61 };
62 }62 }
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 }
63 };73 };
6474
65 /// Based on NTDDI version constants from75 /// Based on NTDDI version constants from
...@@ -210,64 +220,31 @@ pub const Target = struct {...@@ -210,64 +220,31 @@ pub const Target = struct {
210 }220 }
211 };221 };
212222
213 pub fn parse(text: []const u8) !Os {223 pub fn defaultVersionRange(tag: Tag) Os {
214 var it = mem.separate(text, ".");224 return .{
215 const os_name = it.next().?;225 .tag = tag,
216 const tag = std.meta.stringToEnum(Tag, os_name) orelse return error.UnknownOperatingSystem;226 .version_range = VersionRange.default(tag),
217 const version_text = it.rest();227 };
218 const S = struct {228 }
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;
252229
253 const max_text = range_it.next() orelse return WindowsVersion.Range{230 pub fn requiresLibC(os: Os) bool {
254 .min = min_ver,231 return switch (os.tag) {
255 .max = d_range.max,232 .freebsd,
256 };233 .netbsd,
257 const max_ver = std.meta.stringToEnum(WindowsVersion, max_text) orelse234 .macosx,
258 return error.InvalidOperatingSystemVersion;235 .ios,
236 .tvos,
237 .watchos,
238 .dragonfly,
239 .openbsd,
240 => true,
259241
260 return WindowsVersion.Range{ .min = min_ver, .max = max_ver };242 .linux,
261 }243 .windows,
262 };
263 const d_range = VersionRange.default(tag);
264 switch (tag) {
265 .freestanding,244 .freestanding,
266 .ananas,245 .ananas,
267 .cloudabi,246 .cloudabi,
268 .dragonfly,
269 .fuchsia,247 .fuchsia,
270 .ios,
271 .kfreebsd,248 .kfreebsd,
272 .lv2,249 .lv2,
273 .solaris,250 .solaris,
...@@ -282,8 +259,6 @@ pub const Target = struct {...@@ -282,8 +259,6 @@ pub const Target = struct {
282 .amdhsa,259 .amdhsa,
283 .ps4,260 .ps4,
284 .elfiamcu,261 .elfiamcu,
285 .tvos,
286 .watchos,
287 .mesa3d,262 .mesa3d,
288 .contiki,263 .contiki,
289 .amdpal,264 .amdpal,
...@@ -293,41 +268,7 @@ pub const Target = struct {...@@ -293,41 +268,7 @@ pub const Target = struct {
293 .emscripten,268 .emscripten,
294 .uefi,269 .uefi,
295 .other,270 .other,
296 => return Os{271 => false,
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),
331 };272 };
332 }273 }
333 };274 };
...@@ -434,6 +375,13 @@ pub const Target = struct {...@@ -434,6 +375,13 @@ pub const Target = struct {
434 else => false,375 else => false,
435 };376 };
436 }377 }
378
379 pub fn oFileExt(abi: Abi) [:0]const u8 {
380 return switch (abi) {
381 .msvc => ".obj",
382 else => ".o",
383 };
384 }
437 };385 };
438386
439 pub const ObjectFormat = enum {387 pub const ObjectFormat = enum {
...@@ -500,6 +448,12 @@ pub const Target = struct {...@@ -500,6 +448,12 @@ pub const Target = struct {
500 return Set{ .ints = [1]usize{0} ** usize_count };448 return Set{ .ints = [1]usize{0} ** usize_count };
501 }449 }
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
503 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {457 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
504 const usize_index = arch_feature_index / @bitSizeOf(usize);458 const usize_index = arch_feature_index / @bitSizeOf(usize);
505 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));459 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
...@@ -526,6 +480,15 @@ pub const Target = struct {...@@ -526,6 +480,15 @@ pub const Target = struct {
526 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);480 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
527 }481 }
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
529 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {492 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
530 @setEvalBranchQuota(1000000);493 @setEvalBranchQuota(1000000);
531494
...@@ -663,7 +626,7 @@ pub const Target = struct {...@@ -663,7 +626,7 @@ pub const Target = struct {
663 return cpu;626 return cpu;
664 }627 }
665 }628 }
666 return error.UnknownCpu;629 return error.UnknownCpuModel;
667 }630 }
668631
669 pub fn toElfMachine(arch: Arch) std.elf.EM {632 pub fn toElfMachine(arch: Arch) std.elf.EM {
...@@ -779,6 +742,66 @@ pub const Target = struct {...@@ -779,6 +742,66 @@ pub const Target = struct {
779 };742 };
780 }743 }
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
782 /// Returns a name that matches the lib/std/target/* directory name.805 /// Returns a name that matches the lib/std/target/* directory name.
783 pub fn genericName(arch: Arch) []const u8 {806 pub fn genericName(arch: Arch) []const u8 {
784 return switch (arch) {807 return switch (arch) {
...@@ -846,16 +869,6 @@ pub const Target = struct {...@@ -846,16 +869,6 @@ pub const Target = struct {
846 else => &[0]*const Model{},869 else => &[0]*const Model{},
847 };870 };
848 }871 }
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 }
859 };872 };
860873
861 pub const Model = struct {874 pub const Model = struct {
...@@ -872,41 +885,44 @@ pub const Target = struct {...@@ -872,41 +885,44 @@ pub const Target = struct {
872 .features = features,885 .features = features,
873 };886 };
874 }887 }
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 }
875 };920 };
876921
877 /// The "default" set of CPU features for cross-compiling. A conservative set922 /// The "default" set of CPU features for cross-compiling. A conservative set
878 /// of features that is expected to be supported on most available hardware.923 /// of features that is expected to be supported on most available hardware.
879 pub fn baseline(arch: Arch) Cpu {924 pub fn baseline(arch: Arch) Cpu {
880 const S = struct {925 return Model.baseline(arch).toCpu(arch);
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);
910 }926 }
911 };927 };
912928
...@@ -918,239 +934,70 @@ pub const Target = struct {...@@ -918,239 +934,70 @@ pub const Target = struct {
918934
919 pub const stack_align = 16;935 pub const stack_align = 16;
920936
921 /// TODO add OS version ranges and glibc version937 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
922 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {938 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
923 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
924 @tagName(self.cpu.arch),
925 @tagName(self.os.tag),
926 @tagName(self.abi),
927 });
928 }939 }
929940
930 /// Returned slice must be freed by the caller.941 pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![:0]u8 {
931 pub fn vcpkgTriplet(target: Target, allocator: *mem.Allocator, linkage: std.build.VcpkgLinkage) ![]const u8 {942 return std.fmt.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
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 }
962 }943 }
963944
964 pub fn allocDescription(self: Target, allocator: *mem.Allocator) ![]u8 {945 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
965 // TODO is there anything else worthy of the description that is not946 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
966 // already captured in the triple?
967 return self.zigTriple(allocator);
968 }947 }
969948
970 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {949 pub fn oFileExt(self: Target) [:0]const u8 {
971 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{950 return self.abi.oFileExt();
972 @tagName(self.cpu.arch),
973 @tagName(self.os.tag),
974 @tagName(self.abi),
975 });
976 }951 }
977952
978 pub const ParseOptions = struct {953 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
979 /// This is sometimes called a "triple". It looks roughly like this:954 switch (os_tag) {
980 /// riscv64-linux-gnu955 .windows => return ".exe",
981 /// The fields are, respectively:956 .uefi => return ".efi",
982 /// * CPU Architecture957 else => if (cpu_arch.isWasm()) {
983 /// * Operating System958 return ".wasm";
984 /// * C ABI (optional)959 } else {
985 arch_os_abi: []const u8,960 return "";
986961 },
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;
1057 }962 }
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 };
1103 }963 }
1104964
1105 pub fn oFileExt(self: Target) []const u8 {965 pub fn exeFileExt(self: Target) [:0]const u8 {
1106 return switch (self.abi) {966 return exeFileExtSimple(self.cpu.arch, self.os.tag);
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 }
1122 }967 }
1123968
1124 pub fn staticLibSuffix(self: Target) []const u8 {969 pub fn staticLibSuffix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
1125 if (self.cpu.arch.isWasm()) {970 if (cpu_arch.isWasm()) {
1126 return ".wasm";971 return ".wasm";
1127 }972 }
1128 switch (self.abi) {973 switch (abi) {
1129 .msvc => return ".lib",974 .msvc => return ".lib",
1130 else => return ".a",975 else => return ".a",
1131 }976 }
1132 }977 }
1133978
1134 pub fn dynamicLibSuffix(self: Target) []const u8 {979 pub fn staticLibSuffix(self: Target) [:0]const u8 {
1135 if (self.isDarwin()) {980 return staticLibSuffix_cpu_arch_abi(self.cpu.arch, self.abi);
1136 return ".dylib";
1137 }
1138 switch (self.os) {
1139 .windows => return ".dll",
1140 else => return ".so",
1141 }
1142 }981 }
1143982
1144 pub fn libPrefix(self: Target) []const u8 {983 pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
1145 if (self.cpu.arch.isWasm()) {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()) {
1146 return "";989 return "";
1147 }990 }
1148 switch (self.abi) {991 switch (abi) {
1149 .msvc => return "",992 .msvc => return "",
1150 else => return "lib",993 else => return "lib",
1151 }994 }
1152 }995 }
1153996
997 pub fn libPrefix(self: Target) [:0]const u8 {
998 return libPrefix_cpu_arch_abi(self.cpu.arch, self.abi);
999 }
1000
1154 pub fn getObjectFormat(self: Target) ObjectFormat {1001 pub fn getObjectFormat(self: Target) ObjectFormat {
1155 if (self.os.tag == .windows or self.os.tag == .uefi) {1002 if (self.os.tag == .windows or self.os.tag == .uefi) {
1156 return .coff;1003 return .coff;
...@@ -1190,129 +1037,18 @@ pub const Target = struct {...@@ -1190,129 +1037,18 @@ pub const Target = struct {
1190 return self.os.tag.isDarwin();1037 return self.os.tag.isDarwin();
1191 }1038 }
11921039
1193 pub fn isGnuLibC(self: Target) bool {1040 pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
1194 return self.os.tag == .linux and self.abi.isGnu();1041 return os_tag == .linux and abi.isGnu();
1195 }1042 }
11961043
1197 pub fn wantSharedLibSymLinks(self: Target) bool {1044 pub fn isGnuLibC(self: Target) bool {
1198 return self.os.tag != .windows;1045 return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
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 }
1263 }1046 }
12641047
1265 pub fn supportsNewStackCall(self: Target) bool {1048 pub fn supportsNewStackCall(self: Target) bool {
1266 return !self.cpu.arch.isWasm();1049 return !self.cpu.arch.isWasm();
1267 }1050 }
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
1316 pub const FloatAbi = enum {1052 pub const FloatAbi = enum {
1317 hard,1053 hard,
1318 soft,1054 soft,
...@@ -1359,7 +1095,7 @@ pub const Target = struct {...@@ -1359,7 +1095,7 @@ pub const Target = struct {
1359 }![:0]u8 {1095 }![:0]u8 {
1360 const a = allocator;1096 const a = allocator;
1361 if (self.isAndroid()) {1097 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)
1363 "/system/bin/linker64"1099 "/system/bin/linker64"
1364 else1100 else
1365 "/system/bin/linker");1101 "/system/bin/linker");
...@@ -1477,52 +1213,3 @@ pub const Target = struct {...@@ -1477,52 +1213,3 @@ pub const Target = struct {
1477 }1213 }
1478 }1214 }
1479};1215};
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 @@...@@ -1,5 +1,3 @@
1const builtin = @import("builtin");
2const TypeId = builtin.TypeId;
3const std = @import("std.zig");1const std = @import("std.zig");
42
5pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;3pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;
...@@ -65,16 +63,16 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {...@@ -65,16 +63,16 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {
6563
66 .Pointer => |pointer| {64 .Pointer => |pointer| {
67 switch (pointer.size) {65 switch (pointer.size) {
68 builtin.TypeInfo.Pointer.Size.One,66 .One,
69 builtin.TypeInfo.Pointer.Size.Many,67 .Many,
70 builtin.TypeInfo.Pointer.Size.C,68 .C,
71 => {69 => {
72 if (actual != expected) {70 if (actual != expected) {
73 std.debug.panic("expected {*}, found {*}", .{ expected, actual });71 std.debug.panic("expected {*}, found {*}", .{ expected, actual });
74 }72 }
75 },73 },
7674
77 builtin.TypeInfo.Pointer.Size.Slice => {75 .Slice => {
78 if (actual.ptr != expected.ptr) {76 if (actual.ptr != expected.ptr) {
79 std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });77 std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });
80 }78 }
lib/std/zig.zig+3-6
...@@ -6,11 +6,8 @@ pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStri...@@ -6,11 +6,8 @@ pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStri
6pub const render = @import("zig/render.zig").render;6pub const render = @import("zig/render.zig").render;
7pub const ast = @import("zig/ast.zig");7pub const ast = @import("zig/ast.zig");
8pub const system = @import("zig/system.zig");8pub const system = @import("zig/system.zig");
9pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
910
10test "std.zig tests" {11test "" {
11 _ = @import("zig/ast.zig");12 @import("std").meta.refAllDecls(@This());
12 _ = @import("zig/parse.zig");
13 _ = @import("zig/render.zig");
14 _ = @import("zig/tokenizer.zig");
15 _ = @import("zig/parse_string_literal.zig");
16}13}
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;...@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
10const ArrayList = std.ArrayList;10const ArrayList = std.ArrayList;
11const Buffer = std.Buffer;11const Buffer = std.Buffer;
12const Target = std.Target;12const Target = std.Target;
13const CrossTarget = std.zig.CrossTarget;
13const self_hosted_main = @import("main.zig");14const self_hosted_main = @import("main.zig");
14const errmsg = @import("errmsg.zig");15const errmsg = @import("errmsg.zig");
15const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;16const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
...@@ -87,7 +88,7 @@ const Error = extern enum {...@@ -87,7 +88,7 @@ const Error = extern enum {
87 NotLazy,88 NotLazy,
88 IsAsync,89 IsAsync,
89 ImportOutsidePkgPath,90 ImportOutsidePkgPath,
90 UnknownCpu,91 UnknownCpuModel,
91 UnknownCpuFeature,92 UnknownCpuFeature,
92 InvalidCpuFeatures,93 InvalidCpuFeatures,
93 InvalidLlvmCpuFeaturesFormat,94 InvalidLlvmCpuFeaturesFormat,
...@@ -634,13 +635,9 @@ export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {...@@ -634,13 +635,9 @@ export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
634}635}
635636
636fn cmdTargets(zig_triple: [*:0]const u8) !void {637fn cmdTargets(zig_triple: [*:0]const u8) !void {
637 var target = try Target.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });638 var cross_target = try CrossTarget.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
638 target.cpu = blk: {639 var dynamic_linker: ?[*:0]u8 = null;
639 const llvm = @import("llvm.zig");640 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
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 };
644 return @import("print_targets.zig").cmdTargets(641 return @import("print_targets.zig").cmdTargets(
645 std.heap.c_allocator,642 std.heap.c_allocator,
646 &[0][]u8{},643 &[0][]u8{},
...@@ -661,7 +658,6 @@ export fn stage2_target_parse(...@@ -661,7 +658,6 @@ export fn stage2_target_parse(
661 error.UnknownOperatingSystem => return .UnknownOperatingSystem,658 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
662 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,659 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
663 error.MissingOperatingSystem => return .MissingOperatingSystem,660 error.MissingOperatingSystem => return .MissingOperatingSystem,
664 error.MissingArchitecture => return .MissingArchitecture,
665 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,661 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
666 error.UnexpectedExtraField => return .SemanticAnalyzeFail,662 error.UnexpectedExtraField => return .SemanticAnalyzeFail,
667 error.InvalidAbiVersion => return .InvalidAbiVersion,663 error.InvalidAbiVersion => return .InvalidAbiVersion,
...@@ -681,44 +677,42 @@ fn stage2TargetParse(...@@ -681,44 +677,42 @@ fn stage2TargetParse(
681 zig_triple_oz: ?[*:0]const u8,677 zig_triple_oz: ?[*:0]const u8,
682 mcpu_oz: ?[*:0]const u8,678 mcpu_oz: ?[*:0]const u8,
683) !void {679) !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: {
685 const zig_triple = mem.toSliceConst(u8, zig_triple_z);681 const zig_triple = mem.toSliceConst(u8, zig_triple_z);
686 const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline";682 const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline";
687 var diags: std.Target.ParseOptions.Diagnostics = .{};683 var diags: CrossTarget.ParseOptions.Diagnostics = .{};
688 break :blk std.build.Target{684 break :blk CrossTarget.parse(.{
689 .Cross = Target.parse(.{685 .arch_os_abi = zig_triple,
690 .arch_os_abi = zig_triple,686 .cpu_features = mcpu,
691 .cpu_features = mcpu,687 .diagnostics = &diags,
692 .diagnostics = &diags,688 }) catch |err| switch (err) {
693 }) catch |err| switch (err) {689 error.UnknownCpuModel => {
694 error.UnknownCpu => {690 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
695 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{691 diags.cpu_name.?,
696 diags.cpu_name.?,692 @tagName(diags.arch.?),
697 @tagName(diags.arch.?),693 });
698 });694 for (diags.arch.?.allCpuModels()) |cpu| {
699 for (diags.arch.?.allCpuModels()) |cpu| {695 std.debug.warn(" {}\n", .{cpu.name});
700 std.debug.warn(" {}\n", .{cpu.name});696 }
701 }697 process.exit(1);
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,
719 },698 },
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,
720 };714 };
721 } else std.build.Target.Native;715 } else .{};
722716
723 try stage1_target.fromTarget(target);717 try stage1_target.fromTarget(target);
724}718}
...@@ -908,8 +902,8 @@ const Stage2Target = extern struct {...@@ -908,8 +902,8 @@ const Stage2Target = extern struct {
908902
909 dynamic_linker: ?[*:0]const u8,903 dynamic_linker: ?[*:0]const u8,
910904
911 fn toTarget(in_target: Stage2Target) std.build.Target {905 fn toTarget(in_target: Stage2Target) CrossTarget {
912 if (in_target.is_native) return .Native;906 if (in_target.is_native) return .{};
913907
914 const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch908 const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
915 const in_os = in_target.os;909 const in_os = in_target.os;
...@@ -924,28 +918,11 @@ const Stage2Target = extern struct {...@@ -924,28 +918,11 @@ const Stage2Target = extern struct {
924 };918 };
925 }919 }
926920
927 fn fromTarget(self: *Stage2Target, build_target: std.build.Target) !void {921 fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
928 const allocator = std.heap.c_allocator;922 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 todo924 var dynamic_linker: ?[*:0]u8 = null;
938 // so here we rely on LLVM925 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
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 };
949926
950 var cache_hash = try std.Buffer.allocPrint(allocator, "{}\n{}\n", .{927 var cache_hash = try std.Buffer.allocPrint(allocator, "{}\n{}\n", .{
951 target.cpu.model.name,928 target.cpu.model.name,
...@@ -1145,7 +1122,7 @@ const Stage2Target = extern struct {...@@ -1145,7 +1122,7 @@ const Stage2Target = extern struct {
1145 .cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,1122 .cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
1146 .os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,1123 .os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
1147 .cache_hash = cache_hash.toOwnedSlice().ptr,1124 .cache_hash = cache_hash.toOwnedSlice().ptr,
1148 .is_native = build_target == .Native,1125 .is_native = cross_target.isNative(),
1149 .glibc_version = glibc_version,1126 .glibc_version = glibc_version,
1150 .dynamic_linker = dynamic_linker,1127 .dynamic_linker = dynamic_linker,
1151 };1128 };
...@@ -1156,6 +1133,40 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {...@@ -1156,6 +1133,40 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
1156 return @intToEnum(Enum, @intCast(@TagType(Enum), int));1133 return @intToEnum(Enum, @intCast(@TagType(Enum), int));
1157}1134}
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
1159// ABI warning1170// ABI warning
1160const Stage2GLibCVersion = extern struct {1171const Stage2GLibCVersion = extern struct {
1161 major: u32,1172 major: u32,
test/compile_errors.zig+10-14
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
2const Target = @import("std").Target;2const std = @import("std");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("type mismatch with tuple concatenation",5 cases.addTest("type mismatch with tuple concatenation",
...@@ -386,12 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -386,12 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
386 , &[_][]const u8{386 , &[_][]const u8{
387 "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",387 "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
388 });388 });
389 tc.target = tests.Target{389 tc.target = std.zig.CrossTarget{
390 .Cross = .{390 .cpu_arch = .wasm32,
391 .cpu = Target.Cpu.baseline(.wasm32),391 .os_tag = .wasi,
392 .os = Target.Os.defaultVersionRange(.wasi),392 .abi = .none,
393 .abi = .none,
394 },
395 };393 };
396 break :x tc;394 break :x tc;
397 });395 });
...@@ -787,12 +785,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -787,12 +785,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
787 , &[_][]const u8{785 , &[_][]const u8{
788 "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",786 "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
789 });787 });
790 tc.target = tests.Target{788 tc.target = std.zig.CrossTarget{
791 .Cross = .{789 .cpu_arch = .x86_64,
792 .cpu = Target.Cpu.baseline(.x86_64),790 .os_tag = .linux,
793 .os = Target.Os.defaultVersionRange(.linux),791 .abi = .gnu,
794 .abi = .gnu,
795 },
796 };792 };
797 break :x tc;793 break :x tc;
798 });794 });
...@@ -1452,7 +1448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1452,7 +1448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1452 "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",1448 "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
1453 });1449 });
14541450
1455 if (Target.current.os.tag == .linux) {1451 if (std.Target.current.os.tag == .linux) {
1456 cases.addTest("implicit dependency on libc",1452 cases.addTest("implicit dependency on libc",
1457 \\extern "c" fn exit(u8) void;1453 \\extern "c" fn exit(u8) void;
1458 \\export fn entry() void {1454 \\export fn entry() void {
test/src/translate_c.zig+3-2
...@@ -7,6 +7,7 @@ const fmt = std.fmt;...@@ -7,6 +7,7 @@ const fmt = std.fmt;
7const mem = std.mem;7const mem = std.mem;
8const fs = std.fs;8const fs = std.fs;
9const warn = std.debug.warn;9const warn = std.debug.warn;
10const CrossTarget = std.zig.CrossTarget;
1011
11pub const TranslateCContext = struct {12pub const TranslateCContext = struct {
12 b: *build.Builder,13 b: *build.Builder,
...@@ -19,7 +20,7 @@ pub const TranslateCContext = struct {...@@ -19,7 +20,7 @@ pub const TranslateCContext = struct {
19 sources: ArrayList(SourceFile),20 sources: ArrayList(SourceFile),
20 expected_lines: ArrayList([]const u8),21 expected_lines: ArrayList([]const u8),
21 allow_warnings: bool,22 allow_warnings: bool,
22 target: build.Target = .Native,23 target: CrossTarget = CrossTarget{},
2324
24 const SourceFile = struct {25 const SourceFile = struct {
25 filename: []const u8,26 filename: []const u8,
...@@ -75,7 +76,7 @@ pub const TranslateCContext = struct {...@@ -75,7 +76,7 @@ pub const TranslateCContext = struct {
75 pub fn addWithTarget(76 pub fn addWithTarget(
76 self: *TranslateCContext,77 self: *TranslateCContext,
77 name: []const u8,78 name: []const u8,
78 target: build.Target,79 target: CrossTarget,
79 source: []const u8,80 source: []const u8,
80 expected_lines: []const []const u8,81 expected_lines: []const []const u8,
81 ) void {82 ) void {
test/tests.zig+82-122
...@@ -3,7 +3,7 @@ const builtin = std.builtin;...@@ -3,7 +3,7 @@ const builtin = std.builtin;
3const debug = std.debug;3const debug = std.debug;
4const warn = debug.warn;4const warn = debug.warn;
5const build = std.build;5const build = std.build;
6pub const Target = build.Target;6const CrossTarget = std.zig.CrossTarget;
7const Buffer = std.Buffer;7const Buffer = std.Buffer;
8const io = std.io;8const io = std.io;
9const fs = std.fs;9const fs = std.fs;
...@@ -30,7 +30,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla...@@ -30,7 +30,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla
30pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;30pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;
3131
32const TestTarget = struct {32const TestTarget = struct {
33 target: build.Target = .Native,33 target: CrossTarget = @as(CrossTarget, .{}),
34 mode: builtin.Mode = .Debug,34 mode: builtin.Mode = .Debug,
35 link_libc: bool = false,35 link_libc: bool = false,
36 single_threaded: bool = false,36 single_threaded: bool = false,
...@@ -52,105 +52,85 @@ const test_targets = blk: {...@@ -52,105 +52,85 @@ const test_targets = blk: {
52 },52 },
5353
54 TestTarget{54 TestTarget{
55 .target = Target{55 .target = .{
56 .Cross = .{56 .cpu_arch = .x86_64,
57 .cpu = std.Target.Cpu.baseline(.x86_64),57 .os_tag = .linux,
58 .os = std.Target.Os.defaultVersionRange(.linux),58 .abi = .none,
59 .abi = .none,
60 },
61 },59 },
62 },60 },
63 TestTarget{61 TestTarget{
64 .target = Target{62 .target = .{
65 .Cross = .{63 .cpu_arch = .x86_64,
66 .cpu = std.Target.Cpu.baseline(.x86_64),64 .os_tag = .linux,
67 .os = std.Target.Os.defaultVersionRange(.linux),65 .abi = .gnu,
68 .abi = .gnu,
69 },
70 },66 },
71 .link_libc = true,67 .link_libc = true,
72 },68 },
73 TestTarget{69 TestTarget{
74 .target = Target{70 .target = .{
75 .Cross = .{71 .cpu_arch = .x86_64,
76 .cpu = std.Target.Cpu.baseline(.x86_64),72 .os_tag = .linux,
77 .os = std.Target.Os.defaultVersionRange(.linux),73 .abi = .musl,
78 .abi = .musl,
79 },
80 },74 },
81 .link_libc = true,75 .link_libc = true,
82 },76 },
8377
84 TestTarget{78 TestTarget{
85 .target = Target{79 .target = .{
86 .Cross = .{80 .cpu_arch = .i386,
87 .cpu = std.Target.Cpu.baseline(.i386),81 .os_tag = .linux,
88 .os = std.Target.Os.defaultVersionRange(.linux),82 .abi = .none,
89 .abi = .none,
90 },
91 },83 },
92 },84 },
93 TestTarget{85 TestTarget{
94 .target = Target{86 .target = .{
95 .Cross = .{87 .cpu_arch = .i386,
96 .cpu = std.Target.Cpu.baseline(.i386),88 .os_tag = .linux,
97 .os = std.Target.Os.defaultVersionRange(.linux),89 .abi = .musl,
98 .abi = .musl,
99 },
100 },90 },
101 .link_libc = true,91 .link_libc = true,
102 },92 },
10393
104 TestTarget{94 TestTarget{
105 .target = Target{95 .target = .{
106 .Cross = .{96 .cpu_arch = .aarch64,
107 .cpu = std.Target.Cpu.baseline(.aarch64),97 .os_tag = .linux,
108 .os = std.Target.Os.defaultVersionRange(.linux),98 .abi = .none,
109 .abi = .none,
110 },
111 },99 },
112 },100 },
113 TestTarget{101 TestTarget{
114 .target = Target{102 .target = .{
115 .Cross = .{103 .cpu_arch = .aarch64,
116 .cpu = std.Target.Cpu.baseline(.aarch64),104 .os_tag = .linux,
117 .os = std.Target.Os.defaultVersionRange(.linux),105 .abi = .musl,
118 .abi = .musl,
119 },
120 },106 },
121 .link_libc = true,107 .link_libc = true,
122 },108 },
123 TestTarget{109 TestTarget{
124 .target = Target{110 .target = .{
125 .Cross = .{111 .cpu_arch = .aarch64,
126 .cpu = std.Target.Cpu.baseline(.aarch64),112 .os_tag = .linux,
127 .os = std.Target.Os.defaultVersionRange(.linux),113 .abi = .gnu,
128 .abi = .gnu,
129 },
130 },114 },
131 .link_libc = true,115 .link_libc = true,
132 },116 },
133117
134 TestTarget{118 TestTarget{
135 .target = .{119 .target = CrossTarget.parse(.{
136 .Cross = std.Target.parse(.{120 .arch_os_abi = "arm-linux-none",
137 .arch_os_abi = "arm-linux-none",121 .cpu_features = "generic+v8a",
138 .cpu_features = "generic+v8a",122 }) catch unreachable,
139 }) catch unreachable,
140 },
141 },123 },
142 TestTarget{124 TestTarget{
143 .target = .{125 .target = CrossTarget.parse(.{
144 .Cross = std.Target.parse(.{126 .arch_os_abi = "arm-linux-musleabihf",
145 .arch_os_abi = "arm-linux-musleabihf",127 .cpu_features = "generic+v8a",
146 .cpu_features = "generic+v8a",128 }) catch unreachable,
147 }) catch unreachable,
148 },
149 .link_libc = true,129 .link_libc = true,
150 },130 },
151 // TODO https://github.com/ziglang/zig/issues/3287131 // TODO https://github.com/ziglang/zig/issues/3287
152 //TestTarget{132 //TestTarget{
153 // .target = std.Target.parse(.{133 // .target = CrossTarget.parse(.{
154 // .arch_os_abi = "arm-linux-gnueabihf",134 // .arch_os_abi = "arm-linux-gnueabihf",
155 // .cpu_features = "generic+v8a",135 // .cpu_features = "generic+v8a",
156 // }) catch unreachable,136 // }) catch unreachable,
...@@ -158,75 +138,61 @@ const test_targets = blk: {...@@ -158,75 +138,61 @@ const test_targets = blk: {
158 //},138 //},
159139
160 TestTarget{140 TestTarget{
161 .target = Target{141 .target = .{
162 .Cross = .{142 .cpu_arch = .mipsel,
163 .cpu = std.Target.Cpu.baseline(.mipsel),143 .os_tag = .linux,
164 .os = std.Target.Os.defaultVersionRange(.linux),144 .abi = .none,
165 .abi = .none,
166 },
167 },145 },
168 },146 },
169 TestTarget{147 TestTarget{
170 .target = Target{148 .target = .{
171 .Cross = .{149 .cpu_arch = .mipsel,
172 .cpu = std.Target.Cpu.baseline(.mipsel),150 .os_tag = .linux,
173 .os = std.Target.Os.defaultVersionRange(.linux),151 .abi = .musl,
174 .abi = .musl,
175 },
176 },152 },
177 .link_libc = true,153 .link_libc = true,
178 },154 },
179155
180 TestTarget{156 TestTarget{
181 .target = Target{157 .target = .{
182 .Cross = .{158 .cpu_arch = .x86_64,
183 .cpu = std.Target.Cpu.baseline(.x86_64),159 .os_tag = .macosx,
184 .os = std.Target.Os.defaultVersionRange(.macosx),160 .abi = .gnu,
185 .abi = .gnu,
186 },
187 },161 },
188 // TODO https://github.com/ziglang/zig/issues/3295162 // TODO https://github.com/ziglang/zig/issues/3295
189 .disable_native = true,163 .disable_native = true,
190 },164 },
191165
192 TestTarget{166 TestTarget{
193 .target = Target{167 .target = .{
194 .Cross = .{168 .cpu_arch = .i386,
195 .cpu = std.Target.Cpu.baseline(.i386),169 .os_tag = .windows,
196 .os = std.Target.Os.defaultVersionRange(.windows),170 .abi = .msvc,
197 .abi = .msvc,
198 },
199 },171 },
200 },172 },
201173
202 TestTarget{174 TestTarget{
203 .target = Target{175 .target = .{
204 .Cross = .{176 .cpu_arch = .x86_64,
205 .cpu = std.Target.Cpu.baseline(.x86_64),177 .os_tag = .windows,
206 .os = std.Target.Os.defaultVersionRange(.windows),178 .abi = .msvc,
207 .abi = .msvc,
208 },
209 },179 },
210 },180 },
211181
212 TestTarget{182 TestTarget{
213 .target = Target{183 .target = .{
214 .Cross = .{184 .cpu_arch = .i386,
215 .cpu = std.Target.Cpu.baseline(.i386),185 .os_tag = .windows,
216 .os = std.Target.Os.defaultVersionRange(.windows),186 .abi = .gnu,
217 .abi = .gnu,
218 },
219 },187 },
220 .link_libc = true,188 .link_libc = true,
221 },189 },
222190
223 TestTarget{191 TestTarget{
224 .target = Target{192 .target = .{
225 .Cross = .{193 .cpu_arch = .x86_64,
226 .cpu = std.Target.Cpu.baseline(.x86_64),194 .os_tag = .windows,
227 .os = std.Target.Os.defaultVersionRange(.windows),195 .abi = .gnu,
228 .abi = .gnu,
229 },
230 },196 },
231 .link_libc = true,197 .link_libc = true,
232 },198 },
...@@ -435,13 +401,13 @@ pub fn addPkgTests(...@@ -435,13 +401,13 @@ pub fn addPkgTests(
435 const step = b.step(b.fmt("test-{}", .{name}), desc);401 const step = b.step(b.fmt("test-{}", .{name}), desc);
436402
437 for (test_targets) |test_target| {403 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())
439 continue;405 continue;
440406
441 if (skip_libc and test_target.link_libc)407 if (skip_libc and test_target.link_libc)
442 continue;408 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()) {
445 // This would be a redundant test.411 // This would be a redundant test.
446 continue;412 continue;
447 }413 }
...@@ -451,8 +417,8 @@ pub fn addPkgTests(...@@ -451,8 +417,8 @@ pub fn addPkgTests(
451417
452 const ArchTag = @TagType(builtin.Arch);418 const ArchTag = @TagType(builtin.Arch);
453 if (test_target.disable_native and419 if (test_target.disable_native and
454 test_target.target.getOs() == std.Target.current.os.tag and420 test_target.target.getOsTag() == std.Target.current.os.tag and
455 test_target.target.getArch() == std.Target.current.cpu.arch)421 test_target.target.getCpuArch() == std.Target.current.cpu.arch)
456 {422 {
457 continue;423 continue;
458 }424 }
...@@ -462,17 +428,14 @@ pub fn addPkgTests(...@@ -462,17 +428,14 @@ pub fn addPkgTests(
462 } else false;428 } else false;
463 if (!want_this_mode) continue;429 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())
466 ""432 ""
467 else if (test_target.link_libc)433 else if (test_target.link_libc)
468 "c"434 "c"
469 else435 else
470 "bare";436 "bare";
471437
472 const triple_prefix = if (test_target.target == .Native)438 const triple_prefix = test_target.target.zigTriple(b.allocator) catch unreachable;
473 @as([]const u8, "native")
474 else
475 test_target.target.zigTriple(b.allocator) catch unreachable;
476439
477 const these_tests = b.addTest(root_src);440 const these_tests = b.addTest(root_src);
478 const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";441 const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
...@@ -486,7 +449,7 @@ pub fn addPkgTests(...@@ -486,7 +449,7 @@ pub fn addPkgTests(
486 these_tests.single_threaded = test_target.single_threaded;449 these_tests.single_threaded = test_target.single_threaded;
487 these_tests.setFilter(test_filter);450 these_tests.setFilter(test_filter);
488 these_tests.setBuildMode(test_target.mode);451 these_tests.setBuildMode(test_target.mode);
489 these_tests.setTheTarget(test_target.target);452 these_tests.setTarget(test_target.target);
490 if (test_target.link_libc) {453 if (test_target.link_libc) {
491 these_tests.linkSystemLibrary("c");454 these_tests.linkSystemLibrary("c");
492 }455 }
...@@ -716,7 +679,7 @@ pub const CompileErrorContext = struct {...@@ -716,7 +679,7 @@ pub const CompileErrorContext = struct {
716 link_libc: bool,679 link_libc: bool,
717 is_exe: bool,680 is_exe: bool,
718 is_test: bool,681 is_test: bool,
719 target: Target = .Native,682 target: CrossTarget = CrossTarget{},
720683
721 const SourceFile = struct {684 const SourceFile = struct {
722 filename: []const u8,685 filename: []const u8,
...@@ -808,12 +771,9 @@ pub const CompileErrorContext = struct {...@@ -808,12 +771,9 @@ pub const CompileErrorContext = struct {
808 zig_args.append("--output-dir") catch unreachable;771 zig_args.append("--output-dir") catch unreachable;
809 zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;772 zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;
810773
811 switch (self.case.target) {774 if (!self.case.target.isNative()) {
812 .Native => {},775 try zig_args.append("-target");
813 .Cross => {776 try zig_args.append(try self.case.target.zigTriple(b.allocator));
814 try zig_args.append("-target");
815 try zig_args.append(try self.case.target.zigTriple(b.allocator));
816 },
817 }777 }
818778
819 switch (self.build_mode) {779 switch (self.build_mode) {
test/translate_c.zig+15-21
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
2const std = @import("std");2const std = @import("std");
3const Target = std.Target;3const CrossTarget = std.zig.CrossTarget;
44
5pub fn addCases(cases: *tests.TranslateCContext) void {5pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("macro line continuation",6 cases.add("macro line continuation",
...@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
665 \\}665 \\}
666 });666 });
667667
668 if (Target.current.os.tag != .windows) {668 if (std.Target.current.os.tag != .windows) {
669 // Windows treats this as an enum with type c_int669 // Windows treats this as an enum with type c_int
670 cases.add("big negative enum init values when C ABI supports long long enums",670 cases.add("big negative enum init values when C ABI supports long long enums",
671 \\enum EnumWithInits {671 \\enum EnumWithInits {
...@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1064 \\}1064 \\}
1065 });1065 });
10661066
1067 if (Target.current.os.tag != .windows) {1067 if (std.Target.current.os.tag != .windows) {
1068 // sysv_abi not currently supported on windows1068 // sysv_abi not currently supported on windows
1069 cases.add("Macro qualified functions",1069 cases.add("Macro qualified functions",
1070 \\void __attribute__((sysv_abi)) foo(void);1070 \\void __attribute__((sysv_abi)) foo(void);
...@@ -1094,11 +1094,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1094,11 +1094,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1094 });1094 });
10951095
1096 cases.addWithTarget("Calling convention", .{1096 cases.addWithTarget("Calling convention", .{
1097 .Cross = .{1097 .cpu_arch = .i386,
1098 .cpu = Target.Cpu.baseline(.i386),1098 .os_tag = .linux,
1099 .os = Target.Os.defaultVersionRange(.linux),1099 .abi = .none,
1100 .abi = .none,
1101 },
1102 },1100 },
1103 \\void __attribute__((fastcall)) foo1(float *a);1101 \\void __attribute__((fastcall)) foo1(float *a);
1104 \\void __attribute__((stdcall)) foo2(float *a);1102 \\void __attribute__((stdcall)) foo2(float *a);
...@@ -1113,12 +1111,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1113,12 +1111,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1113 \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;1111 \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;
1114 });1112 });
11151113
1116 cases.addWithTarget("Calling convention", .{1114 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
1117 .Cross = Target.parse(.{1115 .arch_os_abi = "arm-linux-none",
1118 .arch_os_abi = "arm-linux-none",1116 .cpu_features = "generic+v8_5a",
1119 .cpu_features = "generic+v8_5a",1117 }) catch unreachable,
1120 }) catch unreachable,
1121 },
1122 \\void __attribute__((pcs("aapcs"))) foo1(float *a);1118 \\void __attribute__((pcs("aapcs"))) foo1(float *a);
1123 \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a);1119 \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a);
1124 , &[_][]const u8{1120 , &[_][]const u8{
...@@ -1126,12 +1122,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1126,12 +1122,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1126 \\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;1122 \\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;
1127 });1123 });
11281124
1129 cases.addWithTarget("Calling convention", .{1125 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
1130 .Cross = Target.parse(.{1126 .arch_os_abi = "aarch64-linux-none",
1131 .arch_os_abi = "aarch64-linux-none",1127 .cpu_features = "generic+v8_5a",
1132 .cpu_features = "generic+v8_5a",1128 }) catch unreachable,
1133 }) catch unreachable,
1134 },
1135 \\void __attribute__((aarch64_vector_pcs)) foo1(float *a);1129 \\void __attribute__((aarch64_vector_pcs)) foo1(float *a);
1136 , &[_][]const u8{1130 , &[_][]const u8{
1137 \\pub fn foo1(a: [*c]f32) callconv(.Vectorcall) void;1131 \\pub fn foo1(a: [*c]f32) callconv(.Vectorcall) void;
...@@ -1600,7 +1594,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1600,7 +1594,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1600 \\}1594 \\}
1601 });1595 });
16021596
1603 if (Target.current.os.tag != .windows) {1597 if (std.Target.current.os.tag != .windows) {
1604 // When clang uses the <arch>-windows-none triple it behaves as MSVC and1598 // When clang uses the <arch>-windows-none triple it behaves as MSVC and
1605 // interprets the inner `struct Bar` as an anonymous structure1599 // interprets the inner `struct Bar` as an anonymous structure
1606 cases.add("type referenced struct",1600 cases.add("type referenced struct",