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