| ... | @@ -380,10 +380,12 @@ pub const Builder = struct { | ... | @@ -380,10 +380,12 @@ pub const Builder = struct { |
| 380 | switch (builtin.os) { | 380 | switch (builtin.os) { |
| 381 | .windows => {}, | 381 | .windows => {}, |
| 382 | else => { | 382 | else => { |
| 383 | const triple = (CrossTarget{ | 383 | const triple = (Target{ |
| 384 | .arch = builtin.arch, | 384 | .Cross = CrossTarget{ |
| 385 | .os = builtin.os, | 385 | .arch = builtin.arch, |
| 386 | .abi = builtin.abi, | 386 | .os = builtin.os, |
| | 387 | .abi = builtin.abi, |
| | 388 | }, |
| 387 | }).linuxTriple(self.allocator); | 389 | }).linuxTriple(self.allocator); |
| 388 | | 390 | |
| 389 | // TODO: $ ld --verbose | grep SEARCH_DIR | 391 | // TODO: $ ld --verbose | grep SEARCH_DIR |
| ... | @@ -507,6 +509,26 @@ pub const Builder = struct { | ... | @@ -507,6 +509,26 @@ pub const Builder = struct { |
| 507 | return mode; | 509 | return mode; |
| 508 | } | 510 | } |
| 509 | | 511 | |
| | 512 | /// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets. |
| | 513 | pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target { |
| | 514 | if (supported_targets) |target_list| { |
| | 515 | // TODO detect multiple args and emit an error message |
| | 516 | // there's probably a better way to collect the target |
| | 517 | for (target_list) |targ| { |
| | 518 | const targ_str = targ.zigTriple(self.allocator) catch unreachable; |
| | 519 | const targ_desc = targ.allocDescription(self.allocator) catch unreachable; |
| | 520 | const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false; |
| | 521 | if (this_targ_opt) { |
| | 522 | return targ; |
| | 523 | } |
| | 524 | } |
| | 525 | return Target.Native; |
| | 526 | } else { |
| | 527 | const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native; |
| | 528 | return Target.parse(target_str) catch unreachable; // TODO better error message for bad target |
| | 529 | } |
| | 530 | } |
| | 531 | |
| 510 | pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool { | 532 | pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool { |
| 511 | const gop = try self.user_input_options.getOrPut(name); | 533 | const gop = try self.user_input_options.getOrPut(name); |
| 512 | if (!gop.found_existing) { | 534 | if (!gop.found_existing) { |
| ... | @@ -858,67 +880,193 @@ pub const Builder = struct { | ... | @@ -858,67 +880,193 @@ pub const Builder = struct { |
| 858 | } | 880 | } |
| 859 | }; | 881 | }; |
| 860 | | 882 | |
| 861 | const Version = struct { | 883 | pub const Version = struct { |
| 862 | major: u32, | 884 | major: u32, |
| 863 | minor: u32, | 885 | minor: u32, |
| 864 | patch: u32, | 886 | patch: u32, |
| 865 | }; | 887 | }; |
| 866 | | 888 | |
| 867 | const CrossTarget = struct { | 889 | pub const CrossTarget = struct { |
| 868 | arch: builtin.Arch, | 890 | arch: builtin.Arch, |
| 869 | os: builtin.Os, | 891 | os: builtin.Os, |
| 870 | abi: builtin.Abi, | 892 | abi: builtin.Abi, |
| | 893 | }; |
| | 894 | |
| | 895 | pub const Target = union(enum) { |
| | 896 | Native: void, |
| | 897 | Cross: CrossTarget, |
| 871 | | 898 | |
| 872 | pub fn zigTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 { | 899 | pub fn zigTriple(self: Target, allocator: *Allocator) ![]u8 { |
| 873 | return std.fmt.allocPrint( | 900 | return std.fmt.allocPrint( |
| 874 | allocator, | 901 | allocator, |
| 875 | "{}{}-{}-{}", | 902 | "{}{}-{}-{}", |
| 876 | @tagName(cross_target.arch), | 903 | @tagName(self.getArch()), |
| 877 | Target.archSubArchName(cross_target.arch), | 904 | Target.archSubArchName(self.getArch()), |
| 878 | @tagName(cross_target.os), | 905 | @tagName(self.getOs()), |
| 879 | @tagName(cross_target.abi), | 906 | @tagName(self.getAbi()), |
| 880 | ) catch unreachable; | 907 | ); |
| | 908 | } |
| | 909 | |
| | 910 | pub fn allocDescription(self: Target, allocator: *Allocator) ![]u8 { |
| | 911 | // TODO is there anything else worthy of the description that is not |
| | 912 | // already captured in the triple? |
| | 913 | return self.zigTriple(allocator); |
| 881 | } | 914 | } |
| 882 | | 915 | |
| 883 | pub fn linuxTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 { | 916 | pub fn zigTripleNoSubArch(self: Target, allocator: *Allocator) ![]u8 { |
| 884 | return std.fmt.allocPrint( | 917 | return std.fmt.allocPrint( |
| 885 | allocator, | 918 | allocator, |
| 886 | "{}-{}-{}", | 919 | "{}-{}-{}", |
| 887 | @tagName(cross_target.arch), | 920 | @tagName(self.getArch()), |
| 888 | @tagName(cross_target.os), | 921 | @tagName(self.getOs()), |
| 889 | @tagName(cross_target.abi), | 922 | @tagName(self.getAbi()), |
| 890 | ) catch unreachable; | 923 | ); |
| 891 | } | 924 | } |
| 892 | }; | | |
| 893 | | 925 | |
| 894 | pub const Target = union(enum) { | 926 | pub fn linuxTriple(self: Target, allocator: *Allocator) ![]u8 { |
| 895 | Native: void, | 927 | return std.fmt.allocPrint( |
| 896 | Cross: CrossTarget, | 928 | allocator, |
| | 929 | "{}-{}-{}", |
| | 930 | @tagName(self.getArch()), |
| | 931 | @tagName(self.getOs()), |
| | 932 | @tagName(self.getAbi()), |
| | 933 | ); |
| | 934 | } |
| | 935 | |
| | 936 | pub fn parse(text: []const u8) !Target { |
| | 937 | var it = mem.separate(text, "-"); |
| | 938 | const arch_name = it.next() orelse return error.MissingArchitecture; |
| | 939 | const os_name = it.next() orelse return error.MissingOperatingSystem; |
| | 940 | const abi_name = it.next(); |
| | 941 | |
| | 942 | var cross = CrossTarget{ |
| | 943 | .arch = try parseArchSub(arch_name), |
| | 944 | .os = try parseOs(os_name), |
| | 945 | .abi = undefined, |
| | 946 | }; |
| | 947 | cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); |
| | 948 | return Target{ .Cross = cross }; |
| | 949 | } |
| | 950 | |
| | 951 | pub fn defaultAbi(arch: builtin.Arch, target_os: builtin.Os) builtin.Abi { |
| | 952 | switch (arch) { |
| | 953 | .wasm32, .wasm64 => return .musl, |
| | 954 | else => {}, |
| | 955 | } |
| | 956 | switch (target_os) { |
| | 957 | .freestanding, |
| | 958 | .ananas, |
| | 959 | .cloudabi, |
| | 960 | .dragonfly, |
| | 961 | .lv2, |
| | 962 | .solaris, |
| | 963 | .haiku, |
| | 964 | .minix, |
| | 965 | .rtems, |
| | 966 | .nacl, |
| | 967 | .cnk, |
| | 968 | .aix, |
| | 969 | .cuda, |
| | 970 | .nvcl, |
| | 971 | .amdhsa, |
| | 972 | .ps4, |
| | 973 | .elfiamcu, |
| | 974 | .mesa3d, |
| | 975 | .contiki, |
| | 976 | .amdpal, |
| | 977 | .zen, |
| | 978 | .hermit, |
| | 979 | => return .eabi, |
| | 980 | .openbsd, |
| | 981 | .macosx, |
| | 982 | .freebsd, |
| | 983 | .ios, |
| | 984 | .tvos, |
| | 985 | .watchos, |
| | 986 | .fuchsia, |
| | 987 | .kfreebsd, |
| | 988 | .netbsd, |
| | 989 | .hurd, |
| | 990 | => return .gnu, |
| | 991 | .windows, |
| | 992 | .uefi, |
| | 993 | => return .msvc, |
| | 994 | .linux, |
| | 995 | .wasi, |
| | 996 | => return .musl, |
| | 997 | } |
| | 998 | } |
| | 999 | |
| | 1000 | pub const ParseArchSubError = error{ |
| | 1001 | UnknownArchitecture, |
| | 1002 | UnknownSubArchitecture, |
| | 1003 | }; |
| | 1004 | |
| | 1005 | pub fn parseArchSub(text: []const u8) ParseArchSubError!builtin.Arch { |
| | 1006 | const info = @typeInfo(builtin.Arch); |
| | 1007 | inline for (info.Union.fields) |field| { |
| | 1008 | if (mem.eql(u8, text, field.name)) { |
| | 1009 | if (field.field_type == void) { |
| | 1010 | return (builtin.Arch)(@field(builtin.Arch, field.name)); |
| | 1011 | } else { |
| | 1012 | const sub_info = @typeInfo(field.field_type); |
| | 1013 | inline for (sub_info.Enum.fields) |sub_field| { |
| | 1014 | const combined = field.name ++ sub_field.name; |
| | 1015 | if (mem.eql(u8, text, combined)) { |
| | 1016 | return @unionInit(builtin.Arch, field.name, @field(field.field_type, sub_field.name)); |
| | 1017 | } |
| | 1018 | } |
| | 1019 | return error.UnknownSubArchitecture; |
| | 1020 | } |
| | 1021 | } |
| | 1022 | } |
| | 1023 | return error.UnknownArchitecture; |
| | 1024 | } |
| | 1025 | |
| | 1026 | pub fn parseOs(text: []const u8) !builtin.Os { |
| | 1027 | const info = @typeInfo(builtin.Os); |
| | 1028 | inline for (info.Enum.fields) |field| { |
| | 1029 | if (mem.eql(u8, text, field.name)) { |
| | 1030 | return @field(builtin.Os, field.name); |
| | 1031 | } |
| | 1032 | } |
| | 1033 | return error.UnknownOperatingSystem; |
| | 1034 | } |
| | 1035 | |
| | 1036 | pub fn parseAbi(text: []const u8) !builtin.Abi { |
| | 1037 | const info = @typeInfo(builtin.Abi); |
| | 1038 | inline for (info.Enum.fields) |field| { |
| | 1039 | if (mem.eql(u8, text, field.name)) { |
| | 1040 | return @field(builtin.Abi, field.name); |
| | 1041 | } |
| | 1042 | } |
| | 1043 | return error.UnknownApplicationBinaryInterface; |
| | 1044 | } |
| 897 | | 1045 | |
| 898 | fn archSubArchName(arch: builtin.Arch) []const u8 { | 1046 | fn archSubArchName(arch: builtin.Arch) []const u8 { |
| 899 | return switch (arch) { | 1047 | return switch (arch) { |
| 900 | builtin.Arch.arm => |sub| @tagName(sub), | 1048 | .arm => |sub| @tagName(sub), |
| 901 | builtin.Arch.armeb => |sub| @tagName(sub), | 1049 | .armeb => |sub| @tagName(sub), |
| 902 | builtin.Arch.thumb => |sub| @tagName(sub), | 1050 | .thumb => |sub| @tagName(sub), |
| 903 | builtin.Arch.thumbeb => |sub| @tagName(sub), | 1051 | .thumbeb => |sub| @tagName(sub), |
| 904 | builtin.Arch.aarch64 => |sub| @tagName(sub), | 1052 | .aarch64 => |sub| @tagName(sub), |
| 905 | builtin.Arch.aarch64_be => |sub| @tagName(sub), | 1053 | .aarch64_be => |sub| @tagName(sub), |
| 906 | builtin.Arch.kalimba => |sub| @tagName(sub), | 1054 | .kalimba => |sub| @tagName(sub), |
| 907 | else => "", | 1055 | else => "", |
| 908 | }; | 1056 | }; |
| 909 | } | 1057 | } |
| 910 | | 1058 | |
| 911 | pub fn subArchName(self: Target) []const u8 { | 1059 | pub fn subArchName(self: Target) []const u8 { |
| 912 | switch (self) { | 1060 | switch (self) { |
| 913 | Target.Native => return archSubArchName(builtin.arch), | 1061 | .Native => return archSubArchName(builtin.arch), |
| 914 | Target.Cross => |cross| return archSubArchName(cross.arch), | 1062 | .Cross => |cross| return archSubArchName(cross.arch), |
| 915 | } | 1063 | } |
| 916 | } | 1064 | } |
| 917 | | 1065 | |
| 918 | pub fn oFileExt(self: Target) []const u8 { | 1066 | pub fn oFileExt(self: Target) []const u8 { |
| 919 | const abi = switch (self) { | 1067 | const abi = switch (self) { |
| 920 | Target.Native => builtin.abi, | 1068 | .Native => builtin.abi, |
| 921 | Target.Cross => |t| t.abi, | 1069 | .Cross => |t| t.abi, |
| 922 | }; | 1070 | }; |
| 923 | return switch (abi) { | 1071 | return switch (abi) { |
| 924 | builtin.Abi.msvc => ".obj", | 1072 | builtin.Abi.msvc => ".obj", |
| ... | @@ -942,15 +1090,22 @@ pub const Target = union(enum) { | ... | @@ -942,15 +1090,22 @@ pub const Target = union(enum) { |
| 942 | | 1090 | |
| 943 | pub fn getOs(self: Target) builtin.Os { | 1091 | pub fn getOs(self: Target) builtin.Os { |
| 944 | return switch (self) { | 1092 | return switch (self) { |
| 945 | Target.Native => builtin.os, | 1093 | .Native => builtin.os, |
| 946 | Target.Cross => |t| t.os, | 1094 | .Cross => |t| t.os, |
| 947 | }; | 1095 | }; |
| 948 | } | 1096 | } |
| 949 | | 1097 | |
| 950 | pub fn getArch(self: Target) builtin.Arch { | 1098 | pub fn getArch(self: Target) builtin.Arch { |
| 951 | switch (self) { | 1099 | switch (self) { |
| 952 | Target.Native => return builtin.arch, | 1100 | .Native => return builtin.arch, |
| 953 | Target.Cross => |t| return t.arch, | 1101 | .Cross => |t| return t.arch, |
| | 1102 | } |
| | 1103 | } |
| | 1104 | |
| | 1105 | pub fn getAbi(self: Target) builtin.Abi { |
| | 1106 | switch (self) { |
| | 1107 | .Native => return builtin.abi, |
| | 1108 | .Cross => |t| return t.abi, |
| 954 | } | 1109 | } |
| 955 | } | 1110 | } |
| 956 | | 1111 | |
| ... | @@ -1206,19 +1361,24 @@ pub const LibExeObjStep = struct { | ... | @@ -1206,19 +1361,24 @@ pub const LibExeObjStep = struct { |
| 1206 | } | 1361 | } |
| 1207 | } | 1362 | } |
| 1208 | | 1363 | |
| | 1364 | /// Deprecated. Use `setTheTarget`. |
| 1209 | pub fn setTarget( | 1365 | pub fn setTarget( |
| 1210 | self: *LibExeObjStep, | 1366 | self: *LibExeObjStep, |
| 1211 | target_arch: builtin.Arch, | 1367 | target_arch: builtin.Arch, |
| 1212 | target_os: builtin.Os, | 1368 | target_os: builtin.Os, |
| 1213 | target_abi: builtin.Abi, | 1369 | target_abi: builtin.Abi, |
| 1214 | ) void { | 1370 | ) void { |
| 1215 | self.target = Target{ | 1371 | return self.setTheTarget(Target{ |
| 1216 | .Cross = CrossTarget{ | 1372 | .Cross = CrossTarget{ |
| 1217 | .arch = target_arch, | 1373 | .arch = target_arch, |
| 1218 | .os = target_os, | 1374 | .os = target_os, |
| 1219 | .abi = target_abi, | 1375 | .abi = target_abi, |
| 1220 | }, | 1376 | }, |
| 1221 | }; | 1377 | }); |
| | 1378 | } |
| | 1379 | |
| | 1380 | pub fn setTheTarget(self: *LibExeObjStep, target: Target) void { |
| | 1381 | self.target = target; |
| 1222 | self.computeOutFileNames(); | 1382 | self.computeOutFileNames(); |
| 1223 | } | 1383 | } |
| 1224 | | 1384 | |
| ... | @@ -1595,9 +1755,9 @@ pub const LibExeObjStep = struct { | ... | @@ -1595,9 +1755,9 @@ pub const LibExeObjStep = struct { |
| 1595 | | 1755 | |
| 1596 | switch (self.target) { | 1756 | switch (self.target) { |
| 1597 | Target.Native => {}, | 1757 | Target.Native => {}, |
| 1598 | Target.Cross => |cross_target| { | 1758 | Target.Cross => { |
| 1599 | try zig_args.append("-target"); | 1759 | try zig_args.append("-target"); |
| 1600 | try zig_args.append(cross_target.zigTriple(builder.allocator)); | 1760 | try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); |
| 1601 | }, | 1761 | }, |
| 1602 | } | 1762 | } |
| 1603 | | 1763 | |