authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-09 00:05:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-09 09:28:05-07:00
log193ad413f03322b047bbfe17c4b2b368ba6bc097
tree5be27a318191ad64cb96e6702e55326f4255f182
parentc99e34a00e1e839effbc8b257a400eb3b643fa12

stage2: compiling C objects with clang

* add target_util.zig which has ported code from src/target.cpp * Module gains an arena that owns memory used during initialization that has the same lifetime as the Module. Useful for constructing file paths and lists of strings that have mixed lifetimes. - The Module memory itself is allocated in this arena. init/deinit are modified to be create/destroy. - root_name moves to the arena and no longer needs manual free * implement the ability to invoke `zig clang` as a subprocess - there are lots of TODOs that should be solved before merging * Module now requires a Random object and zig_lib_dir * Module now requires a path to its own executable or any zig executable that can do `zig clang`. * Wire up more CLI options. * Module creates "zig-cache" directory and "tmp" and "o" subdirectories ("h" is created by the cache_hash) * stubbed out some of the things linker code needs to do with TODO prints * delete dead code for computing compiler id. the previous commit eliminated the need for it. * add `zig translate-c` CLI option but it's not fully hooked up yet. It should be possible for this to be fully wired up before merging this branch. * `zig targets` now uses canonical data for available_libcs

11 files changed, 1077 insertions(+), 408 deletions(-)

src-self-hosted/Module.zig+691-201
......@@ -10,6 +10,7 @@ const log = std.log.scoped(.module);
1010const BigIntConst = std.math.big.int.Const;
1111const BigIntMutable = std.math.big.int.Mutable;
1212const Target = std.Target;
13const target_util = @import("target.zig");
1314const Package = @import("Package.zig");
1415const link = @import("link.zig");
1516const ir = @import("ir.zig");
......@@ -26,6 +27,8 @@ const build_options = @import("build_options");
2627
2728/// General-purpose allocator. Used for both temporary and long-term storage.
2829gpa: *Allocator,
30/// Arena-allocated memory used during initialization. Should be untouched until deinit.
31arena_state: std.heap.ArenaAllocator.State,
2932/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
3033root_pkg: ?*Package,
3134/// Module owns this resource.
......@@ -85,6 +88,12 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
8588root_name: []u8,
8689keep_source_files_loaded: bool,
8790use_clang: bool,
91sanitize_c: bool,
92/// When this is `true` it means invoking clang as a sub-process is expected to inherit
93/// stdin, stdout, stderr, and if it returns non success, to forward the exit code.
94/// Otherwise we attempt to parse the error messages and expose them via the Module API.
95/// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`.
96clang_passthrough_mode: bool,
8897
8998/// Error tags and their values, tag names are duped with mod.gpa.
9099global_error_set: std.StringHashMapUnmanaged(u16) = .{},
......@@ -92,6 +101,12 @@ global_error_set: std.StringHashMapUnmanaged(u16) = .{},
92101c_source_files: []const []const u8,
93102clang_argv: []const []const u8,
94103cache: std.cache_hash.CacheHash,
104/// Path to own executable for invoking `zig clang`.
105self_exe_path: ?[]const u8,
106zig_lib_dir: []const u8,
107zig_cache_dir_path: []const u8,
108libc_include_dir_list: []const []const u8,
109rand: *std.rand.Random,
95110
96111pub const InnerError = error{ OutOfMemory, AnalysisFail };
97112
......@@ -913,10 +928,12 @@ pub const AllErrors = struct {
913928};
914929
915930pub const InitOptions = struct {
916 target: std.Target,
931 zig_lib_dir: []const u8,
932 target: Target,
917933 root_name: []const u8,
918934 root_pkg: ?*Package,
919935 output_mode: std.builtin.OutputMode,
936 rand: *std.rand.Random,
920937 bin_file_dir: ?std.fs.Dir = null,
921938 bin_file_path: []const u8,
922939 emit_h: ?[]const u8 = null,
......@@ -932,8 +949,8 @@ pub const InitOptions = struct {
932949 framework_dirs: []const []const u8 = &[0][]const u8{},
933950 frameworks: []const []const u8 = &[0][]const u8{},
934951 system_libs: []const []const u8 = &[0][]const u8{},
935 have_libc: bool = false,
936 have_libcpp: bool = false,
952 link_libc: bool = false,
953 link_libcpp: bool = false,
937954 want_pic: ?bool = null,
938955 want_sanitize_c: ?bool = null,
939956 use_llvm: ?bool = null,
......@@ -943,170 +960,232 @@ pub const InitOptions = struct {
943960 strip: bool = false,
944961 linker_script: ?[]const u8 = null,
945962 version_script: ?[]const u8 = null,
946 disable_c_depfile: bool = false,
947963 override_soname: ?[]const u8 = null,
948964 linker_optimization: ?[]const u8 = null,
949965 linker_gc_sections: ?bool = null,
966 function_sections: ?bool = null,
950967 linker_allow_shlib_undefined: ?bool = null,
951968 linker_bind_global_refs_locally: ?bool = null,
969 disable_c_depfile: bool = false,
952970 linker_z_nodelete: bool = false,
953971 linker_z_defs: bool = false,
972 clang_passthrough_mode: bool = false,
954973 stack_size_override: u64 = 0,
974 self_exe_path: ?[]const u8 = null,
955975};
956976
957pub fn init(gpa: *Allocator, options: InitOptions) !Module {
958 const root_name = try gpa.dupe(u8, options.root_name);
959 errdefer gpa.free(root_name);
960
961 const ofmt = options.object_format orelse options.target.getObjectFormat();
962
963 // Make a decision on whether to use LLD or our own linker.
964 const use_lld = if (options.use_lld) |explicit| explicit else blk: {
965 if (!build_options.have_llvm)
977pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
978 const mod: *Module = mod: {
979 // For allocations that have the same lifetime as Module. This arena is used only during this
980 // initialization and then is freed in deinit().
981 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
982 errdefer arena_allocator.deinit();
983 const arena = &arena_allocator.allocator;
984
985 // We put the `Module` itself in the arena. Freeing the arena will free the module.
986 // It's initialized later after we prepare the initialization options.
987 const mod = try arena.create(Module);
988 const root_name = try arena.dupe(u8, options.root_name);
989
990 const ofmt = options.object_format orelse options.target.getObjectFormat();
991
992 // Make a decision on whether to use LLD or our own linker.
993 const use_lld = if (options.use_lld) |explicit| explicit else blk: {
994 if (!build_options.have_llvm)
995 break :blk false;
996
997 if (ofmt == .c)
998 break :blk false;
999
1000 // Our linker can't handle objects or most advanced options yet.
1001 if (options.link_objects.len != 0 or
1002 options.c_source_files.len != 0 or
1003 options.frameworks.len != 0 or
1004 options.system_libs.len != 0 or
1005 options.link_libc or options.link_libcpp or
1006 options.linker_script != null or options.version_script != null)
1007 {
1008 break :blk true;
1009 }
9661010 break :blk false;
1011 };
9671012
968 if (ofmt == .c)
1013 // Make a decision on whether to use LLVM or our own backend.
1014 const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
1015 // We would want to prefer LLVM for release builds when it is available, however
1016 // we don't have an LLVM backend yet :)
1017 // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
9691018 break :blk false;
1019 };
9701020
971 // Our linker can't handle objects or most advanced options yet.
972 if (options.link_objects.len != 0 or
973 options.c_source_files.len != 0 or
974 options.frameworks.len != 0 or
975 options.system_libs.len != 0 or
976 options.have_libc or options.have_libcpp or
977 options.linker_script != null or options.version_script != null)
978 {
979 break :blk true;
980 }
981 break :blk false;
982 };
983
984 // Make a decision on whether to use LLVM or our own backend.
985 const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
986 // We would want to prefer LLVM for release builds when it is available, however
987 // we don't have an LLVM backend yet :)
988 // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
989 break :blk false;
990 };
991
992 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
993 const bin_file = try link.File.openPath(gpa, bin_file_dir, options.bin_file_path, .{
994 .root_name = root_name,
995 .root_pkg = options.root_pkg,
996 .target = options.target,
997 .output_mode = options.output_mode,
998 .link_mode = options.link_mode orelse .Static,
999 .object_format = ofmt,
1000 .optimize_mode = options.optimize_mode,
1001 .use_lld = use_lld,
1002 .use_llvm = use_llvm,
1003 .objects = options.link_objects,
1004 .frameworks = options.frameworks,
1005 .framework_dirs = options.framework_dirs,
1006 .system_libs = options.system_libs,
1007 .lib_dirs = options.lib_dirs,
1008 .rpath_list = options.rpath_list,
1009 .strip = options.strip,
1010 });
1011 errdefer bin_file.destroy();
1012
1013 const root_scope = blk: {
1014 if (options.root_pkg) |root_pkg| {
1015 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
1016 const root_scope = try gpa.create(Scope.File);
1017 root_scope.* = .{
1018 .sub_file_path = root_pkg.root_src_path,
1019 .source = .{ .unloaded = {} },
1020 .contents = .{ .not_available = {} },
1021 .status = .never_loaded,
1022 .root_container = .{
1023 .file_scope = root_scope,
1021 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
1022 const bin_file = try link.File.openPath(gpa, bin_file_dir, options.bin_file_path, .{
1023 .root_name = root_name,
1024 .root_pkg = options.root_pkg,
1025 .target = options.target,
1026 .output_mode = options.output_mode,
1027 .link_mode = options.link_mode orelse .Static,
1028 .object_format = ofmt,
1029 .optimize_mode = options.optimize_mode,
1030 .use_lld = use_lld,
1031 .use_llvm = use_llvm,
1032 .link_libc = options.link_libc,
1033 .link_libcpp = options.link_libcpp,
1034 .objects = options.link_objects,
1035 .frameworks = options.frameworks,
1036 .framework_dirs = options.framework_dirs,
1037 .system_libs = options.system_libs,
1038 .lib_dirs = options.lib_dirs,
1039 .rpath_list = options.rpath_list,
1040 .strip = options.strip,
1041 .function_sections = options.function_sections orelse false,
1042 });
1043 errdefer bin_file.destroy();
1044
1045 // We arena-allocate the root scope so there is no free needed.
1046 const root_scope = blk: {
1047 if (options.root_pkg) |root_pkg| {
1048 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
1049 const root_scope = try gpa.create(Scope.File);
1050 root_scope.* = .{
1051 .sub_file_path = root_pkg.root_src_path,
1052 .source = .{ .unloaded = {} },
1053 .contents = .{ .not_available = {} },
1054 .status = .never_loaded,
1055 .root_container = .{
1056 .file_scope = root_scope,
1057 .decls = .{},
1058 },
1059 };
1060 break :blk &root_scope.base;
1061 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
1062 const root_scope = try gpa.create(Scope.ZIRModule);
1063 root_scope.* = .{
1064 .sub_file_path = root_pkg.root_src_path,
1065 .source = .{ .unloaded = {} },
1066 .contents = .{ .not_available = {} },
1067 .status = .never_loaded,
10241068 .decls = .{},
1025 },
1026 };
1027 break :blk &root_scope.base;
1028 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
1029 const root_scope = try gpa.create(Scope.ZIRModule);
1030 root_scope.* = .{
1031 .sub_file_path = root_pkg.root_src_path,
1032 .source = .{ .unloaded = {} },
1033 .contents = .{ .not_available = {} },
1034 .status = .never_loaded,
1035 .decls = .{},
1036 };
1037 break :blk &root_scope.base;
1069 };
1070 break :blk &root_scope.base;
1071 } else {
1072 unreachable;
1073 }
10381074 } else {
1039 unreachable;
1075 const root_scope = try gpa.create(Scope.None);
1076 root_scope.* = .{};
1077 break :blk &root_scope.base;
10401078 }
1041 } else {
1042 const root_scope = try gpa.create(Scope.None);
1043 root_scope.* = .{};
1044 break :blk &root_scope.base;
1045 }
1046 };
1079 };
10471080
1048 // We put everything into the cache hash except for the root source file, because we want to
1049 // find the same binary and incrementally update it even if the file contents changed.
1050 // TODO Look into storing this information in memory rather than on disk and solving
1051 // serialization/deserialization of *all* incremental compilation state in a more generic way.
1052 const cache_dir = if (options.root_pkg) |root_pkg| root_pkg.root_src_dir else std.fs.cwd();
1053 var cache = try std.cache_hash.CacheHash.init(gpa, cache_dir, "zig-cache");
1054 errdefer cache.release();
1055
1056 // Now we will prepare hash state initializations to avoid redundantly computing hashes.
1057 // First we add common things between things that apply to zig source and all c source files.
1058 cache.addBytes(build_options.version);
1059 cache.add(options.optimize_mode);
1060 cache.add(options.target.cpu.arch);
1061 cache.addBytes(options.target.cpu.model.name);
1062 cache.add(options.target.cpu.features.ints);
1063 cache.add(options.target.os.tag);
1064 switch (options.target.os.tag) {
1065 .linux => {
1066 cache.add(options.target.os.version_range.linux.range.min);
1067 cache.add(options.target.os.version_range.linux.range.max);
1068 cache.add(options.target.os.version_range.linux.glibc);
1069 },
1070 .windows => {
1071 cache.add(options.target.os.version_range.windows.min);
1072 cache.add(options.target.os.version_range.windows.max);
1073 },
1074 .freebsd,
1075 .macosx,
1076 .ios,
1077 .tvos,
1078 .watchos,
1079 .netbsd,
1080 .openbsd,
1081 .dragonfly,
1082 => {
1083 cache.add(options.target.os.version_range.semver.min);
1084 cache.add(options.target.os.version_range.semver.max);
1085 },
1086 else => {},
1087 }
1088 cache.add(options.target.abi);
1089 cache.add(ofmt);
1090 // TODO PIC (see detect_pic from codegen.cpp)
1091 cache.add(bin_file.options.link_mode);
1092 cache.add(options.strip);
1093
1094 // Make a decision on whether to use Clang for translate-c and compiling C files.
1095 const use_clang = if (options.use_clang) |explicit| explicit else blk: {
1096 if (build_options.have_llvm) {
1097 // Can't use it if we don't have it!
1098 break :blk false;
1081 // We put everything into the cache hash except for the root source file, because we want to
1082 // find the same binary and incrementally update it even if the file contents changed.
1083 // TODO Look into storing this information in memory rather than on disk and solving
1084 // serialization/deserialization of *all* incremental compilation state in a more generic way.
1085 const cache_parent_dir = if (options.root_pkg) |root_pkg| root_pkg.root_src_dir else std.fs.cwd();
1086 var cache_dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
1087 defer cache_dir.close();
1088
1089 try cache_dir.makePath("tmp");
1090 try cache_dir.makePath("o");
1091 // We need this string because of sending paths to clang as a child process.
1092 const zig_cache_dir_path = if (options.root_pkg) |root_pkg|
1093 try std.fmt.allocPrint(arena, "{}" ++ std.fs.path.sep_str ++ "zig-cache", .{root_pkg.root_src_dir_path})
1094 else
1095 "zig-cache";
1096
1097 var cache = try std.cache_hash.CacheHash.init(gpa, cache_dir, "h");
1098 errdefer cache.release();
1099
1100 // Now we will prepare hash state initializations to avoid redundantly computing hashes.
1101 // First we add common things between things that apply to zig source and all c source files.
1102 cache.addBytes(build_options.version);
1103 cache.add(options.optimize_mode);
1104 cache.add(options.target.cpu.arch);
1105 cache.addBytes(options.target.cpu.model.name);
1106 cache.add(options.target.cpu.features.ints);
1107 cache.add(options.target.os.tag);
1108 switch (options.target.os.tag) {
1109 .linux => {
1110 cache.add(options.target.os.version_range.linux.range.min);
1111 cache.add(options.target.os.version_range.linux.range.max);
1112 cache.add(options.target.os.version_range.linux.glibc);
1113 },
1114 .windows => {
1115 cache.add(options.target.os.version_range.windows.min);
1116 cache.add(options.target.os.version_range.windows.max);
1117 },
1118 .freebsd,
1119 .macosx,
1120 .ios,
1121 .tvos,
1122 .watchos,
1123 .netbsd,
1124 .openbsd,
1125 .dragonfly,
1126 => {
1127 cache.add(options.target.os.version_range.semver.min);
1128 cache.add(options.target.os.version_range.semver.max);
1129 },
1130 else => {},
10991131 }
1100 // It's not planned to do our own translate-c or C compilation.
1101 break :blk true;
1132 cache.add(options.target.abi);
1133 cache.add(ofmt);
1134 // TODO PIC (see detect_pic from codegen.cpp)
1135 cache.add(bin_file.options.link_mode);
1136 cache.add(options.strip);
1137
1138 // Make a decision on whether to use Clang for translate-c and compiling C files.
1139 const use_clang = if (options.use_clang) |explicit| explicit else blk: {
1140 if (build_options.have_llvm) {
1141 // Can't use it if we don't have it!
1142 break :blk false;
1143 }
1144 // It's not planned to do our own translate-c or C compilation.
1145 break :blk true;
1146 };
1147
1148 const libc_include_dir_list = try detectLibCIncludeDirs(
1149 arena,
1150 options.zig_lib_dir,
1151 options.target,
1152 options.link_libc,
1153 );
1154
1155 const sanitize_c: bool = options.want_sanitize_c orelse switch (options.optimize_mode) {
1156 .Debug, .ReleaseSafe => true,
1157 .ReleaseSmall, .ReleaseFast => false,
1158 };
1159
1160 mod.* = .{
1161 .gpa = gpa,
1162 .arena_state = arena_allocator.state,
1163 .zig_lib_dir = options.zig_lib_dir,
1164 .zig_cache_dir_path = zig_cache_dir_path,
1165 .root_name = root_name,
1166 .root_pkg = options.root_pkg,
1167 .root_scope = root_scope,
1168 .bin_file_dir = bin_file_dir,
1169 .bin_file_path = options.bin_file_path,
1170 .bin_file = bin_file,
1171 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
1172 .keep_source_files_loaded = options.keep_source_files_loaded,
1173 .use_clang = use_clang,
1174 .clang_argv = options.clang_argv,
1175 .c_source_files = options.c_source_files,
1176 .cache = cache,
1177 .self_exe_path = options.self_exe_path,
1178 .libc_include_dir_list = libc_include_dir_list,
1179 .sanitize_c = sanitize_c,
1180 .rand = options.rand,
1181 .clang_passthrough_mode = options.clang_passthrough_mode,
1182 };
1183 break :mod mod;
11021184 };
1103 var c_object_table = std.AutoArrayHashMapUnmanaged(*CObject, void){};
1104 errdefer {
1105 for (c_object_table.items()) |entry| entry.key.destroy(gpa);
1106 c_object_table.deinit(gpa);
1107 }
1185 errdefer mod.destroy();
1186
11081187 // Add a `CObject` for each `c_source_files`.
1109 try c_object_table.ensureCapacity(gpa, options.c_source_files.len);
1188 try mod.c_object_table.ensureCapacity(gpa, options.c_source_files.len);
11101189 for (options.c_source_files) |c_source_file| {
11111190 var local_arena = std.heap.ArenaAllocator.init(gpa);
11121191 errdefer local_arena.deinit();
......@@ -1120,31 +1199,15 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
11201199 .extra_flags = &[0][]const u8{},
11211200 .arena = local_arena.state,
11221201 };
1123 c_object_table.putAssumeCapacityNoClobber(c_object, {});
1124 }
1125
1126 return Module{
1127 .gpa = gpa,
1128 .root_name = root_name,
1129 .root_pkg = options.root_pkg,
1130 .root_scope = root_scope,
1131 .bin_file_dir = bin_file_dir,
1132 .bin_file_path = options.bin_file_path,
1133 .bin_file = bin_file,
1134 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
1135 .keep_source_files_loaded = options.keep_source_files_loaded,
1136 .use_clang = use_clang,
1137 .clang_argv = options.clang_argv,
1138 .c_source_files = options.c_source_files,
1139 .cache = cache,
1140 .c_object_table = c_object_table,
1141 };
1202 mod.c_object_table.putAssumeCapacityNoClobber(c_object, {});
1203 }
1204
1205 return mod;
11421206}
11431207
1144pub fn deinit(self: *Module) void {
1208pub fn destroy(self: *Module) void {
11451209 self.bin_file.destroy();
11461210 const gpa = self.gpa;
1147 self.gpa.free(self.root_name);
11481211 self.deletion_set.deinit(gpa);
11491212 self.work_queue.deinit();
11501213
......@@ -1198,7 +1261,9 @@ pub fn deinit(self: *Module) void {
11981261 }
11991262 self.global_error_set.deinit(gpa);
12001263 self.cache.release();
1201 self.* = undefined;
1264
1265 // This destroys `self`.
1266 self.arena_state.promote(gpa).deinit();
12021267}
12031268
12041269fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
......@@ -1209,7 +1274,7 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
12091274 gpa.free(export_list);
12101275}
12111276
1212pub fn target(self: Module) std.Target {
1277pub fn getTarget(self: Module) Target {
12131278 return self.bin_file.options.target;
12141279}
12151280
......@@ -1440,29 +1505,335 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
14401505 c_object.status = .{ .new = {} };
14411506 },
14421507 }
1443 if (!build_options.have_llvm) {
1444 try self.failed_c_objects.ensureCapacity(self.gpa, self.failed_c_objects.items().len + 1);
1445 self.failed_c_objects.putAssumeCapacityNoClobber(c_object, try ErrorMsg.create(
1446 self.gpa,
1447 0,
1448 "clang not available: compiler not built with LLVM extensions enabled",
1449 .{},
1450 ));
1451 c_object.status = .{ .failure = "" };
1452 continue;
1453 }
1454 try self.failed_c_objects.ensureCapacity(self.gpa, self.failed_c_objects.items().len + 1);
1455 self.failed_c_objects.putAssumeCapacityNoClobber(c_object, try ErrorMsg.create(
1456 self.gpa,
1457 0,
1458 "TODO: implement invoking clang to compile C source files",
1459 .{},
1460 ));
1461 c_object.status = .{ .failure = "" };
1508 self.buildCObject(c_object) catch |err| switch (err) {
1509 error.AnalysisFail => continue,
1510 else => {
1511 try self.failed_c_objects.ensureCapacity(self.gpa, self.failed_c_objects.items().len + 1);
1512 self.failed_c_objects.putAssumeCapacityNoClobber(c_object, try ErrorMsg.create(
1513 self.gpa,
1514 0,
1515 "unable to build C object: {}",
1516 .{@errorName(err)},
1517 ));
1518 c_object.status = .{ .failure = "" };
1519 },
1520 };
14621521 },
14631522 };
14641523}
14651524
1525fn buildCObject(mod: *Module, c_object: *CObject) !void {
1526 const tracy = trace(@src());
1527 defer tracy.end();
1528
1529 if (!build_options.have_llvm) {
1530 return mod.failCObj(c_object, "clang not available: compiler not built with LLVM extensions enabled", .{});
1531 }
1532 const self_exe_path = mod.self_exe_path orelse
1533 return mod.failCObj(c_object, "clang compilation disabled", .{});
1534
1535 var arena_allocator = std.heap.ArenaAllocator.init(mod.gpa);
1536 defer arena_allocator.deinit();
1537 const arena = &arena_allocator.allocator;
1538
1539 var argv = std.ArrayList([]const u8).init(mod.gpa);
1540 defer argv.deinit();
1541
1542 const c_source_basename = std.fs.path.basename(c_object.src_path);
1543 // Special case when doing build-obj for just one C file. When there are more than one object
1544 // file and building an object we need to link them together, but with just one it should go
1545 // directly to the output file.
1546 const direct_o = mod.c_source_files.len == 1 and mod.root_pkg == null and
1547 mod.bin_file.options.output_mode == .Obj and mod.bin_file.options.objects.len == 0;
1548 const o_basename_noext = if (direct_o) mod.root_name else mem.split(c_source_basename, ".").next().?;
1549 const o_basename = try std.fmt.allocPrint(arena, "{}{}", .{ o_basename_noext, mod.getTarget().oFileExt() });
1550
1551 // We can't know the digest until we do the C compiler invocation, so we need a temporary filename.
1552 const out_obj_path = try mod.tmpFilePath(arena, o_basename);
1553
1554 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang", "-c" });
1555
1556 const ext = classifyFileExt(c_object.src_path);
1557 // TODO capture the .d file and deal with caching stuff
1558 try mod.addCCArgs(arena, &argv, ext, false, null);
1559
1560 try argv.append("-o");
1561 try argv.append(out_obj_path);
1562
1563 try argv.append(c_object.src_path);
1564 try argv.appendSlice(c_object.extra_flags);
1565
1566 //for (argv.items) |arg| {
1567 // std.debug.print("{} ", .{arg});
1568 //}
1569
1570 const child = try std.ChildProcess.init(argv.items, arena);
1571 defer child.deinit();
1572
1573 if (mod.clang_passthrough_mode) {
1574 child.stdin_behavior = .Inherit;
1575 child.stdout_behavior = .Inherit;
1576 child.stderr_behavior = .Inherit;
1577
1578 const term = child.spawnAndWait() catch |err| {
1579 return mod.failCObj(c_object, "unable to spawn {}: {}", .{ argv.items[0], @errorName(err) });
1580 };
1581 switch (term) {
1582 .Exited => |code| {
1583 if (code != 0) {
1584 // TODO make std.process.exit and std.ChildProcess exit code have the same type
1585 // and forward it here. Currently it is u32 vs u8.
1586 std.process.exit(1);
1587 }
1588 },
1589 else => std.process.exit(1),
1590 }
1591 } else {
1592 child.stdin_behavior = .Ignore;
1593 child.stdout_behavior = .Pipe;
1594 child.stderr_behavior = .Pipe;
1595
1596 try child.spawn();
1597
1598 const stdout_reader = child.stdout.?.reader();
1599 const stderr_reader = child.stderr.?.reader();
1600
1601 // TODO Need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
1602 const stdout = try stdout_reader.readAllAlloc(arena, std.math.maxInt(u32));
1603 const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
1604
1605 const term = child.wait() catch |err| {
1606 return mod.failCObj(c_object, "unable to spawn {}: {}", .{ argv.items[0], @errorName(err) });
1607 };
1608
1609 switch (term) {
1610 .Exited => |code| {
1611 if (code != 0) {
1612 // TODO parse clang stderr and turn it into an error message
1613 // and then call failCObjWithOwnedErrorMsg
1614 std.log.err("clang failed with stderr: {}", .{stderr});
1615 return mod.failCObj(c_object, "clang exited with code {}", .{code});
1616 }
1617 },
1618 else => {
1619 std.log.err("clang terminated with stderr: {}", .{stderr});
1620 return mod.failCObj(c_object, "clang terminated unexpectedly", .{});
1621 },
1622 }
1623 }
1624
1625 // TODO handle .d files
1626
1627 // TODO rename into place
1628 std.debug.print("TODO rename {} into cache dir\n", .{out_obj_path});
1629
1630 // TODO use the cache file name instead of tmp file name
1631 const success_file_path = try mod.gpa.dupe(u8, out_obj_path);
1632 c_object.status = .{ .success = success_file_path };
1633}
1634
1635fn tmpFilePath(mod: *Module, arena: *Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
1636 const s = std.fs.path.sep_str;
1637 return std.fmt.allocPrint(
1638 arena,
1639 "{}" ++ s ++ "tmp" ++ s ++ "{x}-{}",
1640 .{ mod.zig_cache_dir_path, mod.rand.int(u64), suffix },
1641 );
1642}
1643
1644/// Add common C compiler args between translate-c and C object compilation.
1645fn addCCArgs(
1646 mod: *Module,
1647 arena: *Allocator,
1648 argv: *std.ArrayList([]const u8),
1649 ext: FileExt,
1650 translate_c: bool,
1651 out_dep_path: ?[]const u8,
1652) !void {
1653 const target = mod.getTarget();
1654
1655 if (translate_c) {
1656 try argv.appendSlice(&[_][]const u8{ "-x", "c" });
1657 }
1658
1659 if (ext == .cpp) {
1660 try argv.append("-nostdinc++");
1661 }
1662 try argv.appendSlice(&[_][]const u8{
1663 "-nostdinc",
1664 "-fno-spell-checking",
1665 });
1666
1667 // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode
1668 // we want Clang to infer it, and in normal mode we always want it off, which will be true since
1669 // clang will detect stderr as a pipe rather than a terminal.
1670 if (!mod.clang_passthrough_mode) {
1671 // Make stderr more easily parseable.
1672 try argv.append("-fno-caret-diagnostics");
1673 }
1674
1675 if (mod.bin_file.options.function_sections) {
1676 try argv.append("-ffunction-sections");
1677 }
1678
1679 try argv.ensureCapacity(argv.items.len + mod.bin_file.options.framework_dirs.len * 2);
1680 for (mod.bin_file.options.framework_dirs) |framework_dir| {
1681 argv.appendAssumeCapacity("-iframework");
1682 argv.appendAssumeCapacity(framework_dir);
1683 }
1684
1685 if (mod.bin_file.options.link_libcpp) {
1686 const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{
1687 mod.zig_lib_dir, "libcxx", "include",
1688 });
1689 const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{
1690 mod.zig_lib_dir, "libcxxabi", "include",
1691 });
1692
1693 try argv.append("-isystem");
1694 try argv.append(libcxx_include_path);
1695
1696 try argv.append("-isystem");
1697 try argv.append(libcxxabi_include_path);
1698
1699 if (target.abi.isMusl()) {
1700 try argv.append("-D_LIBCPP_HAS_MUSL_LIBC");
1701 }
1702 try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
1703 try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
1704 }
1705
1706 const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target);
1707 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });
1708
1709 switch (ext) {
1710 .c, .cpp, .h => {
1711 // According to Rich Felker libc headers are supposed to go before C language headers.
1712 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
1713 // and other compiler specific items.
1714 const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ mod.zig_lib_dir, "include" });
1715 try argv.append("-isystem");
1716 try argv.append(c_headers_dir);
1717
1718 for (mod.libc_include_dir_list) |include_dir| {
1719 try argv.append("-isystem");
1720 try argv.append(include_dir);
1721 }
1722
1723 if (target.cpu.model.llvm_name) |llvm_name| {
1724 try argv.appendSlice(&[_][]const u8{
1725 "-Xclang", "-target-cpu", "-Xclang", llvm_name,
1726 });
1727 }
1728 // TODO CLI args for target features
1729 //if (g->zig_target->llvm_cpu_features != nullptr) {
1730 // // https://github.com/ziglang/zig/issues/5017
1731 // SplitIterator it = memSplit(str(g->zig_target->llvm_cpu_features), str(","));
1732 // Optional<Slice<uint8_t>> flag = SplitIterator_next(&it);
1733 // while (flag.is_some) {
1734 // try argv.append("-Xclang");
1735 // try argv.append("-target-feature");
1736 // try argv.append("-Xclang");
1737 // try argv.append(buf_ptr(buf_create_from_slice(flag.value)));
1738 // flag = SplitIterator_next(&it);
1739 // }
1740 //}
1741 if (translate_c) {
1742 // This gives us access to preprocessing entities, presumably at the cost of performance.
1743 try argv.append("-Xclang");
1744 try argv.append("-detailed-preprocessing-record");
1745 }
1746 if (out_dep_path) |p| {
1747 try argv.append("-MD");
1748 try argv.append("-MV");
1749 try argv.append("-MF");
1750 try argv.append(p);
1751 }
1752 },
1753 .assembly, .ll, .bc, .unknown => {},
1754 }
1755 // TODO CLI args for cpu features when compiling assembly
1756 //for (size_t i = 0; i < g->zig_target->llvm_cpu_features_asm_len; i += 1) {
1757 // try argv.append(g->zig_target->llvm_cpu_features_asm_ptr[i]);
1758 //}
1759
1760 if (target.os.tag == .freestanding) {
1761 try argv.append("-ffreestanding");
1762 }
1763
1764 // windows.h has files such as pshpack1.h which do #pragma packing, triggering a clang warning.
1765 // So for this target, we disable this warning.
1766 if (target.os.tag == .windows and target.abi.isGnu()) {
1767 try argv.append("-Wno-pragma-pack");
1768 }
1769
1770 if (!mod.bin_file.options.strip) {
1771 try argv.append("-g");
1772 }
1773
1774 if (mod.haveFramePointer()) {
1775 try argv.append("-fno-omit-frame-pointer");
1776 } else {
1777 try argv.append("-fomit-frame-pointer");
1778 }
1779
1780 if (mod.sanitize_c) {
1781 try argv.append("-fsanitize=undefined");
1782 try argv.append("-fsanitize-trap=undefined");
1783 }
1784
1785 switch (mod.bin_file.options.optimize_mode) {
1786 .Debug => {
1787 // windows c runtime requires -D_DEBUG if using debug libraries
1788 try argv.append("-D_DEBUG");
1789 try argv.append("-Og");
1790
1791 if (mod.bin_file.options.link_libc) {
1792 try argv.append("-fstack-protector-strong");
1793 try argv.append("--param");
1794 try argv.append("ssp-buffer-size=4");
1795 } else {
1796 try argv.append("-fno-stack-protector");
1797 }
1798 },
1799 .ReleaseSafe => {
1800 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
1801 // than -O3 here.
1802 try argv.append("-O2");
1803 if (mod.bin_file.options.link_libc) {
1804 try argv.append("-D_FORTIFY_SOURCE=2");
1805 try argv.append("-fstack-protector-strong");
1806 try argv.append("--param");
1807 try argv.append("ssp-buffer-size=4");
1808 } else {
1809 try argv.append("-fno-stack-protector");
1810 }
1811 },
1812 .ReleaseFast => {
1813 try argv.append("-DNDEBUG");
1814 // Here we pass -O2 rather than -O3 because, although we do the equivalent of
1815 // -O3 in Zig code, the justification for the difference here is that Zig
1816 // has better detection and prevention of undefined behavior, so -O3 is safer for
1817 // Zig code than it is for C code. Also, C programmers are used to their code
1818 // running in -O2 and thus the -O3 path has been tested less.
1819 try argv.append("-O2");
1820 try argv.append("-fno-stack-protector");
1821 },
1822 .ReleaseSmall => {
1823 try argv.append("-DNDEBUG");
1824 try argv.append("-Os");
1825 try argv.append("-fno-stack-protector");
1826 },
1827 }
1828
1829 // TODO add CLI args for PIC
1830 //if (target_supports_fpic(g->zig_target) and g->have_pic) {
1831 // try argv.append("-fPIC");
1832 //}
1833
1834 try argv.appendSlice(mod.clang_argv);
1835}
1836
14661837pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
14671838 const tracy = trace(@src());
14681839 defer tracy.end();
......@@ -3041,7 +3412,7 @@ pub fn cmpNumeric(
30413412 } else if (rhs_ty_tag == .ComptimeFloat) {
30423413 break :x lhs.ty;
30433414 }
3044 if (lhs.ty.floatBits(self.target()) >= rhs.ty.floatBits(self.target())) {
3415 if (lhs.ty.floatBits(self.getTarget()) >= rhs.ty.floatBits(self.getTarget())) {
30453416 break :x lhs.ty;
30463417 } else {
30473418 break :x rhs.ty;
......@@ -3100,7 +3471,7 @@ pub fn cmpNumeric(
31003471 } else if (lhs_is_float) {
31013472 dest_float_type = lhs.ty;
31023473 } else {
3103 const int_info = lhs.ty.intInfo(self.target());
3474 const int_info = lhs.ty.intInfo(self.getTarget());
31043475 lhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
31053476 }
31063477
......@@ -3135,7 +3506,7 @@ pub fn cmpNumeric(
31353506 } else if (rhs_is_float) {
31363507 dest_float_type = rhs.ty;
31373508 } else {
3138 const int_info = rhs.ty.intInfo(self.target());
3509 const int_info = rhs.ty.intInfo(self.getTarget());
31393510 rhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
31403511 }
31413512
......@@ -3200,13 +3571,13 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
32003571 next_inst.ty.isInt() and
32013572 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())
32023573 {
3203 if (prev_inst.ty.intInfo(self.target()).bits < next_inst.ty.intInfo(self.target()).bits) {
3574 if (prev_inst.ty.intInfo(self.getTarget()).bits < next_inst.ty.intInfo(self.getTarget()).bits) {
32043575 prev_inst = next_inst;
32053576 }
32063577 continue;
32073578 }
32083579 if (prev_inst.ty.isFloat() and next_inst.ty.isFloat()) {
3209 if (prev_inst.ty.floatBits(self.target()) < next_inst.ty.floatBits(self.target())) {
3580 if (prev_inst.ty.floatBits(self.getTarget()) < next_inst.ty.floatBits(self.getTarget())) {
32103581 prev_inst = next_inst;
32113582 }
32123583 continue;
......@@ -3274,8 +3645,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
32743645 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
32753646 assert(inst.value() == null); // handled above
32763647
3277 const src_info = inst.ty.intInfo(self.target());
3278 const dst_info = dest_type.intInfo(self.target());
3648 const src_info = inst.ty.intInfo(self.getTarget());
3649 const dst_info = dest_type.intInfo(self.getTarget());
32793650 if ((src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) or
32803651 // small enough unsigned ints can get casted to large enough signed ints
32813652 (src_info.signed and !dst_info.signed and dst_info.bits > src_info.bits))
......@@ -3289,8 +3660,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
32893660 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
32903661 assert(inst.value() == null); // handled above
32913662
3292 const src_bits = inst.ty.floatBits(self.target());
3293 const dst_bits = dest_type.floatBits(self.target());
3663 const src_bits = inst.ty.floatBits(self.getTarget());
3664 const dst_bits = dest_type.floatBits(self.getTarget());
32943665 if (dst_bits >= src_bits) {
32953666 const b = try self.requireRuntimeBlock(scope, inst.src);
32963667 return self.addUnOp(b, inst.src, dest_type, .floatcast, inst);
......@@ -3312,14 +3683,14 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*
33123683 }
33133684 return self.fail(scope, inst.src, "TODO float to int", .{});
33143685 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3315 if (!val.intFitsInType(dest_type, self.target())) {
3686 if (!val.intFitsInType(dest_type, self.getTarget())) {
33163687 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
33173688 }
33183689 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
33193690 }
33203691 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
33213692 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3322 const res = val.floatCast(scope.arena(), dest_type, self.target()) catch |err| switch (err) {
3693 const res = val.floatCast(scope.arena(), dest_type, self.getTarget()) catch |err| switch (err) {
33233694 error.Overflow => return self.fail(
33243695 scope,
33253696 inst.src,
......@@ -3370,6 +3741,22 @@ fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *I
33703741 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
33713742}
33723743
3744fn failCObj(mod: *Module, c_object: *CObject, comptime format: []const u8, args: anytype) InnerError {
3745 @setCold(true);
3746 const err_msg = try ErrorMsg.create(mod.gpa, 0, "unable to build C object: " ++ format, args);
3747 return mod.failCObjWithOwnedErrorMsg(c_object, err_msg);
3748}
3749
3750fn failCObjWithOwnedErrorMsg(mod: *Module, c_object: *CObject, err_msg: *ErrorMsg) InnerError {
3751 {
3752 errdefer err_msg.destroy(mod.gpa);
3753 try mod.failed_c_objects.ensureCapacity(mod.gpa, mod.failed_c_objects.items().len + 1);
3754 }
3755 mod.failed_c_objects.putAssumeCapacityNoClobber(c_object, err_msg);
3756 c_object.status = .{ .failure = "" };
3757 return error.AnalysisFail;
3758}
3759
33733760pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {
33743761 @setCold(true);
33753762 const err_msg = try ErrorMsg.create(self.gpa, src, format, args);
......@@ -3560,7 +3947,7 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
35603947pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
35613948 var bit_count = switch (float_type.tag()) {
35623949 .comptime_float => 128,
3563 else => float_type.floatBits(self.target()),
3950 else => float_type.floatBits(self.getTarget()),
35643951 };
35653952
35663953 const allocator = scope.arena();
......@@ -3594,7 +3981,7 @@ pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
35943981pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
35953982 var bit_count = switch (float_type.tag()) {
35963983 .comptime_float => 128,
3597 else => float_type.floatBits(self.target()),
3984 else => float_type.floatBits(self.getTarget()),
35983985 };
35993986
36003987 const allocator = scope.arena();
......@@ -3865,3 +4252,106 @@ pub fn safetyPanic(mod: *Module, block: *Scope.Block, src: usize, panic_id: Pani
38654252 _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint);
38664253 return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach);
38674254}
4255
4256pub const FileExt = enum {
4257 c,
4258 cpp,
4259 h,
4260 ll,
4261 bc,
4262 assembly,
4263 unknown,
4264};
4265
4266pub fn hasCExt(filename: []const u8) bool {
4267 return mem.endsWith(u8, filename, ".c");
4268}
4269
4270pub fn hasCppExt(filename: []const u8) bool {
4271 return mem.endsWith(u8, filename, ".C") or
4272 mem.endsWith(u8, filename, ".cc") or
4273 mem.endsWith(u8, filename, ".cpp") or
4274 mem.endsWith(u8, filename, ".cxx");
4275}
4276
4277pub fn hasAsmExt(filename: []const u8) bool {
4278 return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
4279}
4280
4281pub fn classifyFileExt(filename: []const u8) FileExt {
4282 if (hasCExt(filename)) {
4283 return .c;
4284 } else if (hasCppExt(filename)) {
4285 return .cpp;
4286 } else if (mem.endsWith(u8, filename, ".ll")) {
4287 return .ll;
4288 } else if (mem.endsWith(u8, filename, ".bc")) {
4289 return .bc;
4290 } else if (hasAsmExt(filename)) {
4291 return .assembly;
4292 } else if (mem.endsWith(u8, filename, ".h")) {
4293 return .h;
4294 } else {
4295 // TODO look for .so, .so.X, .so.X.Y, .so.X.Y.Z
4296 return .unknown;
4297 }
4298}
4299
4300fn haveFramePointer(mod: *Module) bool {
4301 return switch (mod.bin_file.options.optimize_mode) {
4302 .Debug, .ReleaseSafe => !mod.bin_file.options.strip,
4303 .ReleaseSmall, .ReleaseFast => false,
4304 };
4305}
4306
4307fn detectLibCIncludeDirs(
4308 arena: *Allocator,
4309 zig_lib_dir: []const u8,
4310 target: Target,
4311 link_libc: bool,
4312) ![]const []const u8 {
4313 if (!link_libc) return &[0][]u8{};
4314
4315 // TODO Support --libc file explicitly providing libc paths. Or not? Maybe we are better off
4316 // deleting that feature.
4317
4318 if (target_util.canBuildLibC(target)) {
4319 const generic_name = target_util.libCGenericName(target);
4320 // Some architectures are handled by the same set of headers.
4321 const arch_name = if (target.abi.isMusl()) target_util.archMuslName(target.cpu.arch) else @tagName(target.cpu.arch);
4322 const os_name = @tagName(target.os.tag);
4323 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
4324 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
4325 const s = std.fs.path.sep_str;
4326 const arch_include_dir = try std.fmt.allocPrint(
4327 arena,
4328 "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{}-{}-{}",
4329 .{ zig_lib_dir, arch_name, os_name, abi_name },
4330 );
4331 const generic_include_dir = try std.fmt.allocPrint(
4332 arena,
4333 "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{}",
4334 .{ zig_lib_dir, generic_name },
4335 );
4336 const arch_os_include_dir = try std.fmt.allocPrint(
4337 arena,
4338 "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{}-{}-any",
4339 .{ zig_lib_dir, @tagName(target.cpu.arch), os_name },
4340 );
4341 const generic_os_include_dir = try std.fmt.allocPrint(
4342 arena,
4343 "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{}-any",
4344 .{ zig_lib_dir, os_name },
4345 );
4346
4347 const list = try arena.alloc([]const u8, 4);
4348 list[0] = arch_include_dir;
4349 list[1] = generic_include_dir;
4350 list[2] = arch_os_include_dir;
4351 list[3] = generic_os_include_dir;
4352 return list;
4353 }
4354
4355 // TODO finish porting detect_libc from codegen.cpp
4356 return error.LibCDetectionUnimplemented;
4357}
src-self-hosted/codegen/llvm.zig created+125
......@@ -0,0 +1,125 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3
4pub fn targetTriple(allocator: *Allocator, target: std.Target) ![]u8 {
5 const llvm_arch = switch (target.cpu.arch) {
6 .arm => "arm",
7 .armeb => "armeb",
8 .aarch64 => "aarch64",
9 .aarch64_be => "aarch64_be",
10 .aarch64_32 => "aarch64_32",
11 .arc => "arc",
12 .avr => "avr",
13 .bpfel => "bpfel",
14 .bpfeb => "bpfeb",
15 .hexagon => "hexagon",
16 .mips => "mips",
17 .mipsel => "mipsel",
18 .mips64 => "mips64",
19 .mips64el => "mips64el",
20 .msp430 => "msp430",
21 .powerpc => "powerpc",
22 .powerpc64 => "powerpc64",
23 .powerpc64le => "powerpc64le",
24 .r600 => "r600",
25 .amdgcn => "amdgcn",
26 .riscv32 => "riscv32",
27 .riscv64 => "riscv64",
28 .sparc => "sparc",
29 .sparcv9 => "sparcv9",
30 .sparcel => "sparcel",
31 .s390x => "s390x",
32 .tce => "tce",
33 .tcele => "tcele",
34 .thumb => "thumb",
35 .thumbeb => "thumbeb",
36 .i386 => "i386",
37 .x86_64 => "x86_64",
38 .xcore => "xcore",
39 .nvptx => "nvptx",
40 .nvptx64 => "nvptx64",
41 .le32 => "le32",
42 .le64 => "le64",
43 .amdil => "amdil",
44 .amdil64 => "amdil64",
45 .hsail => "hsail",
46 .hsail64 => "hsail64",
47 .spir => "spir",
48 .spir64 => "spir64",
49 .kalimba => "kalimba",
50 .shave => "shave",
51 .lanai => "lanai",
52 .wasm32 => "wasm32",
53 .wasm64 => "wasm64",
54 .renderscript32 => "renderscript32",
55 .renderscript64 => "renderscript64",
56 .ve => "ve",
57 .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII,
58 };
59 // TODO Add a sub-arch for some architectures depending on CPU features.
60
61 const llvm_os = switch (target.os.tag) {
62 .freestanding => "unknown",
63 .ananas => "ananas",
64 .cloudabi => "cloudabi",
65 .dragonfly => "dragonfly",
66 .freebsd => "freebsd",
67 .fuchsia => "fuchsia",
68 .ios => "ios",
69 .kfreebsd => "kfreebsd",
70 .linux => "linux",
71 .lv2 => "lv2",
72 .macosx => "macosx",
73 .netbsd => "netbsd",
74 .openbsd => "openbsd",
75 .solaris => "solaris",
76 .windows => "windows",
77 .haiku => "haiku",
78 .minix => "minix",
79 .rtems => "rtems",
80 .nacl => "nacl",
81 .cnk => "cnk",
82 .aix => "aix",
83 .cuda => "cuda",
84 .nvcl => "nvcl",
85 .amdhsa => "amdhsa",
86 .ps4 => "ps4",
87 .elfiamcu => "elfiamcu",
88 .tvos => "tvos",
89 .watchos => "watchos",
90 .mesa3d => "mesa3d",
91 .contiki => "contiki",
92 .amdpal => "amdpal",
93 .hermit => "hermit",
94 .hurd => "hurd",
95 .wasi => "wasi",
96 .emscripten => "emscripten",
97 .uefi => "windows",
98 .other => "unknown",
99 };
100
101 const llvm_abi = switch (target.abi) {
102 .none => "unknown",
103 .gnu => "gnu",
104 .gnuabin32 => "gnuabin32",
105 .gnuabi64 => "gnuabi64",
106 .gnueabi => "gnueabi",
107 .gnueabihf => "gnueabihf",
108 .gnux32 => "gnux32",
109 .code16 => "code16",
110 .eabi => "eabi",
111 .eabihf => "eabihf",
112 .android => "android",
113 .musl => "musl",
114 .musleabi => "musleabi",
115 .musleabihf => "musleabihf",
116 .msvc => "msvc",
117 .itanium => "itanium",
118 .cygnus => "cygnus",
119 .coreclr => "coreclr",
120 .simulator => "simulator",
121 .macabi => "macabi",
122 };
123
124 return std.fmt.allocPrint(allocator, "{}-unknown-{}-{}", .{ llvm_arch, llvm_os, llvm_abi });
125}
src-self-hosted/introspect.zig-43
......@@ -93,46 +93,3 @@ pub fn openGlobalCacheDir() !fs.Dir {
9393 const path_name = try resolveGlobalCacheDir(&fba.allocator);
9494 return fs.cwd().makeOpenPath(path_name, .{});
9595}
96
97var compiler_id_mutex = std.Mutex{};
98var compiler_id: [16]u8 = undefined;
99var compiler_id_computed = false;
100
101pub fn resolveCompilerId(gpa: *mem.Allocator) ![16]u8 {
102 const held = compiler_id_mutex.acquire();
103 defer held.release();
104
105 if (compiler_id_computed)
106 return compiler_id;
107 compiler_id_computed = true;
108
109 var cache_dir = try openGlobalCacheDir();
110 defer cache_dir.close();
111
112 var ch = try CacheHash.init(gpa, cache_dir, "exe");
113 defer ch.release();
114
115 const self_exe_path = try fs.selfExePathAlloc(gpa);
116 defer gpa.free(self_exe_path);
117
118 _ = try ch.addFile(self_exe_path, null);
119
120 if (try ch.hit()) |digest| {
121 compiler_id = digest[0..16].*;
122 return compiler_id;
123 }
124
125 const libs = try std.process.getSelfExeSharedLibPaths(gpa);
126 defer {
127 for (libs) |lib| gpa.free(lib);
128 gpa.free(libs);
129 }
130
131 for (libs) |lib| {
132 try ch.addFilePost(lib);
133 }
134
135 const digest = ch.final();
136 compiler_id = digest[0..16].*;
137 return compiler_id;
138}
src-self-hosted/link.zig+3
......@@ -35,6 +35,9 @@ pub const Options = struct {
3535 /// other objects.
3636 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.
3737 use_llvm: bool = false,
38 link_libc: bool = false,
39 link_libcpp: bool = false,
40 function_sections: bool = false,
3841
3942 objects: []const []const u8 = &[0][]const u8{},
4043 framework_dirs: []const []const u8 = &[0][]const u8{},
src-self-hosted/link/Elf.zig+19-3
......@@ -219,8 +219,11 @@ pub const SrcFn = struct {
219219pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File {
220220 assert(options.object_format == .elf);
221221
222 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForELF; // TODO
223 if (options.use_lld) return error.LLD_LinkingIsTODOForELF; // TODO
222 if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO
223
224 if (build_options.have_llvm and options.use_lld) {
225 std.debug.print("TODO open a temporary object file, not the final output file because we want to link with LLD\n", .{});
226 }
224227
225228 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options) });
226229 errdefer file.close();
......@@ -741,8 +744,21 @@ pub const abbrev_base_type = 4;
741744pub const abbrev_pad1 = 5;
742745pub const abbrev_parameter = 6;
743746
744/// Commit pending changes and write headers.
745747pub fn flush(self: *Elf, module: *Module) !void {
748 if (build_options.have_llvm and self.base.options.use_lld) {
749 // If there is no Zig code to compile, then we should skip flushing the output file because it
750 // will not be part of the linker line anyway.
751 if (module.root_pkg != null) {
752 try self.flushInner(module);
753 }
754 std.debug.print("TODO create an LLD command line and invoke it\n", .{});
755 } else {
756 return self.flushInner(module);
757 }
758}
759
760/// Commit pending changes and write headers.
761fn flushInner(self: *Elf, module: *Module) !void {
746762 const target_endian = self.base.options.target.cpu.arch.endian();
747763 const foreign_endian = target_endian != std.Target.current.cpu.arch.endian();
748764 const ptr_width_bytes: u8 = self.ptrWidthBytes();
src-self-hosted/main.zig+93-101
......@@ -33,13 +33,14 @@ const usage =
3333 \\
3434 \\Commands:
3535 \\
36 \\ build-exe [source] Create executable from source or object files
37 \\ build-lib [source] Create library from source or object files
38 \\ build-obj [source] Create object from source or assembly
36 \\ build-exe [source] Create executable from source or object files
37 \\ build-lib [source] Create library from source or object files
38 \\ build-obj [source] Create object from source or assembly
3939 \\ cc Use Zig as a drop-in C compiler
4040 \\ c++ Use Zig as a drop-in C++ compiler
4141 \\ env Print lib path, std path, compiler id and version
42 \\ fmt [source] Parse file and render in canonical zig format
42 \\ fmt [source] Parse file and render in canonical zig format
43 \\ translate-c [source] Convert C code to Zig code
4344 \\ targets List available compilation targets
4445 \\ version Print version number and exit
4546 \\ zen Print zen of zig and exit
......@@ -47,15 +48,21 @@ const usage =
4748 \\
4849;
4950
51pub const log_level: std.log.Level = switch (std.builtin.mode) {
52 .Debug => .debug,
53 .ReleaseSafe, .ReleaseFast => .info,
54 .ReleaseSmall => .crit,
55};
56
5057pub fn log(
5158 comptime level: std.log.Level,
5259 comptime scope: @TypeOf(.EnumLiteral),
5360 comptime format: []const u8,
5461 args: anytype,
5562) void {
56 // Hide anything more verbose than warn unless it was added with `-Dlog=foo`.
63 // Hide debug messages unless added with `-Dlog=foo`.
5764 if (@enumToInt(level) > @enumToInt(std.log.level) or
58 @enumToInt(level) > @enumToInt(std.log.Level.warn))
65 @enumToInt(level) > @enumToInt(std.log.Level.info))
5966 {
6067 const scope_name = @tagName(scope);
6168 const ok = comptime for (build_options.log_scopes) |log_scope| {
......@@ -67,13 +74,15 @@ pub fn log(
6774 return;
6875 }
6976
77 // We only recognize 4 log levels in this application.
7078 const level_txt = switch (level) {
71 .emerg => "error",
72 .warn => "warning",
73 else => @tagName(level),
79 .emerg, .alert, .crit => "error",
80 .err, .warn => "warning",
81 .notice, .info => "info",
82 .debug => "debug",
7483 };
75 const prefix1 = level_txt ++ ": ";
76 const prefix2 = if (scope == .default) "" else "(" ++ @tagName(scope) ++ "): ";
84 const prefix1 = level_txt;
85 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
7786
7887 // Print the message to stderr, silently ignoring any errors
7988 std.debug.print(prefix1 ++ prefix2 ++ format ++ "\n", args);
......@@ -93,8 +102,8 @@ pub fn main() !void {
93102 const args = try process.argsAlloc(arena);
94103
95104 if (args.len <= 1) {
96 std.debug.print("expected command argument\n\n{}", .{usage});
97 process.exit(1);
105 std.log.info("{}", .{usage});
106 fatal("expected command argument", .{});
98107 }
99108
100109 const cmd = args[1];
......@@ -109,6 +118,8 @@ pub fn main() !void {
109118 return buildOutputType(gpa, arena, args, .cc);
110119 } else if (mem.eql(u8, cmd, "c++")) {
111120 return buildOutputType(gpa, arena, args, .cpp);
121 } else if (mem.eql(u8, cmd, "translate-c")) {
122 return buildOutputType(gpa, arena, args, .translate_c);
112123 } else if (mem.eql(u8, cmd, "clang") or
113124 mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
114125 {
......@@ -128,8 +139,8 @@ pub fn main() !void {
128139 } else if (mem.eql(u8, cmd, "help")) {
129140 try io.getStdOut().writeAll(usage);
130141 } else {
131 std.debug.print("unknown command: {}\n\n{}", .{ args[1], usage });
132 process.exit(1);
142 std.log.info("{}", .{usage});
143 fatal("unknown command: {}", .{args[1]});
133144 }
134145}
135146
......@@ -223,6 +234,7 @@ pub fn buildOutputType(
223234 build: std.builtin.OutputMode,
224235 cc,
225236 cpp,
237 translate_c,
226238 },
227239) !void {
228240 var color: Color = .Auto;
......@@ -251,8 +263,8 @@ pub fn buildOutputType(
251263 var emit_h: Emit = undefined;
252264 var ensure_libc_on_non_freestanding = false;
253265 var ensure_libcpp_on_non_freestanding = false;
254 var have_libc = false;
255 var have_libcpp = false;
266 var link_libc = false;
267 var link_libcpp = false;
256268 var want_native_include_dirs = false;
257269 var enable_cache: ?bool = null;
258270 var want_pic: ?bool = null;
......@@ -298,13 +310,20 @@ pub fn buildOutputType(
298310 var frameworks = std.ArrayList([]const u8).init(gpa);
299311 defer frameworks.deinit();
300312
301 if (arg_mode == .build) {
302 output_mode = arg_mode.build;
303 emit_h = switch (output_mode) {
304 .Exe => .no,
305 .Obj, .Lib => .yes_default_path,
313 if (arg_mode == .build or arg_mode == .translate_c) {
314 output_mode = switch (arg_mode) {
315 .build => |m| m,
316 .translate_c => .Obj,
317 else => unreachable,
306318 };
307
319 switch (arg_mode) {
320 .build => switch (output_mode) {
321 .Exe => emit_h = .no,
322 .Obj, .Lib => emit_h = .yes_default_path,
323 },
324 .translate_c => emit_h = .no,
325 else => unreachable,
326 }
308327 const args = all_args[2..];
309328 var i: usize = 0;
310329 while (i < args.len) : (i += 1) {
......@@ -499,7 +518,7 @@ pub fn buildOutputType(
499518 mem.endsWith(u8, arg, ".lib"))
500519 {
501520 try link_objects.append(arg);
502 } else if (hasAsmExt(arg) or hasCExt(arg) or hasCppExt(arg)) {
521 } else if (Module.hasAsmExt(arg) or Module.hasCExt(arg) or Module.hasCppExt(arg)) {
503522 try c_source_files.append(arg);
504523 } else if (mem.endsWith(u8, arg, ".so") or
505524 mem.endsWith(u8, arg, ".dylib") or
......@@ -543,7 +562,7 @@ pub fn buildOutputType(
543562 try clang_argv.appendSlice(it.other_args);
544563 },
545564 .positional => {
546 const file_ext = classify_file_ext(mem.spanZ(it.only_arg));
565 const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg));
547566 switch (file_ext) {
548567 .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg),
549568 .unknown => try link_objects.append(it.only_arg),
......@@ -819,28 +838,28 @@ pub fn buildOutputType(
819838 .diagnostics = &diags,
820839 }) catch |err| switch (err) {
821840 error.UnknownCpuModel => {
822 std.debug.print("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
823 diags.cpu_name.?,
824 @tagName(diags.arch.?),
825 });
826 for (diags.arch.?.allCpuModels()) |cpu| {
827 std.debug.print(" {}\n", .{cpu.name});
841 help: {
842 var help_text = std.ArrayList(u8).init(arena);
843 for (diags.arch.?.allCpuModels()) |cpu| {
844 help_text.writer().print(" {}\n", .{cpu.name}) catch break :help;
845 }
846 std.log.info("Available CPUs for architecture '{}': {}", .{
847 @tagName(diags.arch.?), help_text.items,
848 });
828849 }
829 process.exit(1);
850 fatal("Unknown CPU: '{}'", .{diags.cpu_name.?});
830851 },
831852 error.UnknownCpuFeature => {
832 std.debug.print(
833 \\Unknown CPU feature: '{}'
834 \\Available CPU features for architecture '{}':
835 \\
836 , .{
837 diags.unknown_feature_name,
838 @tagName(diags.arch.?),
839 });
840 for (diags.arch.?.allFeaturesList()) |feature| {
841 std.debug.print(" {}: {}\n", .{ feature.name, feature.description });
853 help: {
854 var help_text = std.ArrayList(u8).init(arena);
855 for (diags.arch.?.allFeaturesList()) |feature| {
856 help_text.writer().print(" {}: {}\n", .{ feature.name, feature.description }) catch break :help;
857 }
858 std.log.info("Available CPU features for architecture '{}': {}", .{
859 @tagName(diags.arch.?), help_text.items,
860 });
842861 }
843 process.exit(1);
862 fatal("Unknown CPU feature: '{}'", .{diags.unknown_feature_name});
844863 },
845864 else => |e| return e,
846865 };
......@@ -849,14 +868,16 @@ pub fn buildOutputType(
849868 if (target_info.cpu_detection_unimplemented) {
850869 // TODO We want to just use detected_info.target but implementing
851870 // CPU model & feature detection is todo so here we rely on LLVM.
871 // TODO The workaround to use LLVM to detect features needs to be used for
872 // `zig targets` as well.
852873 fatal("CPU features detection is not yet available for this system without LLVM extensions", .{});
853874 }
854875
855876 if (target_info.target.os.tag != .freestanding) {
856877 if (ensure_libc_on_non_freestanding)
857 have_libc = true;
878 link_libc = true;
858879 if (ensure_libcpp_on_non_freestanding)
859 have_libcpp = true;
880 link_libcpp = true;
860881 }
861882
862883 // Now that we have target info, we can find out if any of the system libraries
......@@ -867,12 +888,12 @@ pub fn buildOutputType(
867888 while (i < system_libs.items.len) {
868889 const lib_name = system_libs.items[i];
869890 if (is_libc_lib_name(target_info.target, lib_name)) {
870 have_libc = true;
891 link_libc = true;
871892 _ = system_libs.orderedRemove(i);
872893 continue;
873894 }
874895 if (is_libcpp_lib_name(target_info.target, lib_name)) {
875 have_libcpp = true;
896 link_libcpp = true;
876897 _ = system_libs.orderedRemove(i);
877898 continue;
878899 }
......@@ -960,7 +981,21 @@ pub fn buildOutputType(
960981 .yes_default_path => try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
961982 };
962983
963 var module = Module.init(gpa, .{
984 const self_exe_path = try fs.selfExePathAlloc(arena);
985 const zig_lib_dir = introspect.resolveZigLibDir(gpa) catch |err| {
986 fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
987 };
988 defer gpa.free(zig_lib_dir);
989
990 const random_seed = blk: {
991 var random_seed: u64 = undefined;
992 try std.crypto.randomBytes(mem.asBytes(&random_seed));
993 break :blk random_seed;
994 };
995 var default_prng = std.rand.DefaultPrng.init(random_seed);
996
997 const module = Module.create(gpa, .{
998 .zig_lib_dir = zig_lib_dir,
964999 .root_name = root_name,
9651000 .target = target_info.target,
9661001 .output_mode = output_mode,
......@@ -980,8 +1015,8 @@ pub fn buildOutputType(
9801015 .frameworks = frameworks.items,
9811016 .system_libs = system_libs.items,
9821017 .emit_h = emit_h_path,
983 .have_libc = have_libc,
984 .have_libcpp = have_libcpp,
1018 .link_libc = link_libc,
1019 .link_libcpp = link_libcpp,
9851020 .want_pic = want_pic,
9861021 .want_sanitize_c = want_sanitize_c,
9871022 .use_llvm = use_llvm,
......@@ -1000,16 +1035,19 @@ pub fn buildOutputType(
10001035 .linker_z_defs = linker_z_defs,
10011036 .stack_size_override = stack_size_override,
10021037 .strip = strip,
1038 .self_exe_path = self_exe_path,
1039 .rand = &default_prng.random,
1040 .clang_passthrough_mode = arg_mode != .build,
10031041 }) catch |err| {
1004 fatal("unable to initialize module: {}", .{@errorName(err)});
1042 fatal("unable to create module: {}", .{@errorName(err)});
10051043 };
1006 defer module.deinit();
1044 defer module.destroy();
10071045
10081046 const stdin = std.io.getStdIn().inStream();
10091047 const stderr = std.io.getStdErr().outStream();
10101048 var repl_buf: [1024]u8 = undefined;
10111049
1012 try updateModule(gpa, &module, zir_out_path);
1050 try updateModule(gpa, module, zir_out_path);
10131051
10141052 if (build_options.have_llvm and only_pp_or_asm) {
10151053 // this may include dumping the output to stdout
......@@ -1031,7 +1069,7 @@ pub fn buildOutputType(
10311069 if (output_mode == .Exe) {
10321070 try module.makeBinFileWritable();
10331071 }
1034 try updateModule(gpa, &module, zir_out_path);
1072 try updateModule(gpa, module, zir_out_path);
10351073 } else if (mem.eql(u8, actual_line, "exit")) {
10361074 break;
10371075 } else if (mem.eql(u8, actual_line, "help")) {
......@@ -1062,12 +1100,10 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo
10621100 full_err_msg.msg,
10631101 });
10641102 }
1065 } else {
1066 std.log.info("Update completed in {} ms", .{update_nanos / std.time.ns_per_ms});
10671103 }
10681104
10691105 if (zir_out_path) |zop| {
1070 var new_zir_module = try zir.emit(gpa, module.*);
1106 var new_zir_module = try zir.emit(gpa, module);
10711107 defer new_zir_module.deinit(gpa);
10721108
10731109 const baf = try io.BufferedAtomicFile.create(gpa, fs.cwd(), zop, .{});
......@@ -1422,50 +1458,6 @@ pub const info_zen =
14221458 \\
14231459;
14241460
1425const FileExt = enum {
1426 c,
1427 cpp,
1428 h,
1429 ll,
1430 bc,
1431 assembly,
1432 unknown,
1433};
1434
1435fn hasCExt(filename: []const u8) bool {
1436 return mem.endsWith(u8, filename, ".c");
1437}
1438
1439fn hasCppExt(filename: []const u8) bool {
1440 return mem.endsWith(u8, filename, ".C") or
1441 mem.endsWith(u8, filename, ".cc") or
1442 mem.endsWith(u8, filename, ".cpp") or
1443 mem.endsWith(u8, filename, ".cxx");
1444}
1445
1446fn hasAsmExt(filename: []const u8) bool {
1447 return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
1448}
1449
1450fn classify_file_ext(filename: []const u8) FileExt {
1451 if (hasCExt(filename)) {
1452 return .c;
1453 } else if (hasCppExt(filename)) {
1454 return .cpp;
1455 } else if (mem.endsWith(u8, filename, ".ll")) {
1456 return .ll;
1457 } else if (mem.endsWith(u8, filename, ".bc")) {
1458 return .bc;
1459 } else if (hasAsmExt(filename)) {
1460 return .assembly;
1461 } else if (mem.endsWith(u8, filename, ".h")) {
1462 return .h;
1463 } else {
1464 // TODO look for .so, .so.X, .so.X.Y, .so.X.Y.Z
1465 return .unknown;
1466 }
1467}
1468
14691461extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
14701462
14711463/// TODO make it so the return value can be !noreturn
src-self-hosted/print_targets.zig+7-52
......@@ -4,60 +4,11 @@ const io = std.io;
44const mem = std.mem;
55const Allocator = mem.Allocator;
66const Target = std.Target;
7const target = @import("target.zig");
78const assert = std.debug.assert;
89
910const introspect = @import("introspect.zig");
1011
11// TODO this is hard-coded until self-hosted gains this information canonically
12const available_libcs = [_][]const u8{
13 "aarch64_be-linux-gnu",
14 "aarch64_be-linux-musl",
15 "aarch64_be-windows-gnu",
16 "aarch64-linux-gnu",
17 "aarch64-linux-musl",
18 "aarch64-windows-gnu",
19 "armeb-linux-gnueabi",
20 "armeb-linux-gnueabihf",
21 "armeb-linux-musleabi",
22 "armeb-linux-musleabihf",
23 "armeb-windows-gnu",
24 "arm-linux-gnueabi",
25 "arm-linux-gnueabihf",
26 "arm-linux-musleabi",
27 "arm-linux-musleabihf",
28 "arm-windows-gnu",
29 "i386-linux-gnu",
30 "i386-linux-musl",
31 "i386-windows-gnu",
32 "mips64el-linux-gnuabi64",
33 "mips64el-linux-gnuabin32",
34 "mips64el-linux-musl",
35 "mips64-linux-gnuabi64",
36 "mips64-linux-gnuabin32",
37 "mips64-linux-musl",
38 "mipsel-linux-gnu",
39 "mipsel-linux-musl",
40 "mips-linux-gnu",
41 "mips-linux-musl",
42 "powerpc64le-linux-gnu",
43 "powerpc64le-linux-musl",
44 "powerpc64-linux-gnu",
45 "powerpc64-linux-musl",
46 "powerpc-linux-gnu",
47 "powerpc-linux-musl",
48 "riscv64-linux-gnu",
49 "riscv64-linux-musl",
50 "s390x-linux-gnu",
51 "s390x-linux-musl",
52 "sparc-linux-gnu",
53 "sparcv9-linux-gnu",
54 "wasm32-freestanding-musl",
55 "x86_64-linux-gnu",
56 "x86_64-linux-gnux32",
57 "x86_64-linux-musl",
58 "x86_64-windows-gnu",
59};
60
6112pub fn cmdTargets(
6213 allocator: *Allocator,
6314 args: []const []const u8,
......@@ -127,9 +78,13 @@ pub fn cmdTargets(
12778
12879 try jws.objectField("libc");
12980 try jws.beginArray();
130 for (available_libcs) |libc| {
81 for (target.available_libcs) |libc| {
82 const tmp = try std.fmt.allocPrint(allocator, "{}-{}-{}", .{
83 @tagName(libc.arch), @tagName(libc.os), @tagName(libc.abi),
84 });
85 defer allocator.free(tmp);
13186 try jws.arrayElem();
132 try jws.emitString(libc);
87 try jws.emitString(tmp);
13388 }
13489 try jws.endArray();
13590
src-self-hosted/target.zig created+111
......@@ -0,0 +1,111 @@
1const std = @import("std");
2
3pub const ArchOsAbi = struct {
4 arch: std.Target.Cpu.Arch,
5 os: std.Target.Os.Tag,
6 abi: std.Target.Abi,
7};
8
9pub const available_libcs = [_]ArchOsAbi{
10 .{ .arch = .aarch64_be, .os = .linux, .abi = .gnu },
11 .{ .arch = .aarch64_be, .os = .linux, .abi = .musl },
12 .{ .arch = .aarch64_be, .os = .windows, .abi = .gnu },
13 .{ .arch = .aarch64, .os = .linux, .abi = .gnu },
14 .{ .arch = .aarch64, .os = .linux, .abi = .musl },
15 .{ .arch = .aarch64, .os = .windows, .abi = .gnu },
16 .{ .arch = .armeb, .os = .linux, .abi = .gnueabi },
17 .{ .arch = .armeb, .os = .linux, .abi = .gnueabihf },
18 .{ .arch = .armeb, .os = .linux, .abi = .musleabi },
19 .{ .arch = .armeb, .os = .linux, .abi = .musleabihf },
20 .{ .arch = .armeb, .os = .windows, .abi = .gnu },
21 .{ .arch = .arm, .os = .linux, .abi = .gnueabi },
22 .{ .arch = .arm, .os = .linux, .abi = .gnueabihf },
23 .{ .arch = .arm, .os = .linux, .abi = .musleabi },
24 .{ .arch = .arm, .os = .linux, .abi = .musleabihf },
25 .{ .arch = .arm, .os = .windows, .abi = .gnu },
26 .{ .arch = .i386, .os = .linux, .abi = .gnu },
27 .{ .arch = .i386, .os = .linux, .abi = .musl },
28 .{ .arch = .i386, .os = .windows, .abi = .gnu },
29 .{ .arch = .mips64el, .os = .linux, .abi = .gnuabi64 },
30 .{ .arch = .mips64el, .os = .linux, .abi = .gnuabin32 },
31 .{ .arch = .mips64el, .os = .linux, .abi = .musl },
32 .{ .arch = .mips64, .os = .linux, .abi = .gnuabi64 },
33 .{ .arch = .mips64, .os = .linux, .abi = .gnuabin32 },
34 .{ .arch = .mips64, .os = .linux, .abi = .musl },
35 .{ .arch = .mipsel, .os = .linux, .abi = .gnu },
36 .{ .arch = .mipsel, .os = .linux, .abi = .musl },
37 .{ .arch = .mips, .os = .linux, .abi = .gnu },
38 .{ .arch = .mips, .os = .linux, .abi = .musl },
39 .{ .arch = .powerpc64le, .os = .linux, .abi = .gnu },
40 .{ .arch = .powerpc64le, .os = .linux, .abi = .musl },
41 .{ .arch = .powerpc64, .os = .linux, .abi = .gnu },
42 .{ .arch = .powerpc64, .os = .linux, .abi = .musl },
43 .{ .arch = .powerpc, .os = .linux, .abi = .gnu },
44 .{ .arch = .powerpc, .os = .linux, .abi = .musl },
45 .{ .arch = .riscv64, .os = .linux, .abi = .gnu },
46 .{ .arch = .riscv64, .os = .linux, .abi = .musl },
47 .{ .arch = .s390x, .os = .linux, .abi = .gnu },
48 .{ .arch = .s390x, .os = .linux, .abi = .musl },
49 .{ .arch = .sparc, .os = .linux, .abi = .gnu },
50 .{ .arch = .sparcv9, .os = .linux, .abi = .gnu },
51 .{ .arch = .wasm32, .os = .freestanding, .abi = .musl },
52 .{ .arch = .x86_64, .os = .linux, .abi = .gnu },
53 .{ .arch = .x86_64, .os = .linux, .abi = .gnux32 },
54 .{ .arch = .x86_64, .os = .linux, .abi = .musl },
55 .{ .arch = .x86_64, .os = .windows, .abi = .gnu },
56};
57
58pub fn libCGenericName(target: std.Target) [:0]const u8 {
59 if (target.os.tag == .windows)
60 return "mingw";
61 switch (target.abi) {
62 .gnu,
63 .gnuabin32,
64 .gnuabi64,
65 .gnueabi,
66 .gnueabihf,
67 .gnux32,
68 => return "glibc",
69 .musl,
70 .musleabi,
71 .musleabihf,
72 .none,
73 => return "musl",
74 .code16,
75 .eabi,
76 .eabihf,
77 .android,
78 .msvc,
79 .itanium,
80 .cygnus,
81 .coreclr,
82 .simulator,
83 .macabi,
84 => unreachable,
85 }
86}
87
88pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {
89 switch (arch) {
90 .aarch64, .aarch64_be => return "aarch64",
91 .arm, .armeb => return "arm",
92 .mips, .mipsel => return "mips",
93 .mips64el, .mips64 => return "mips64",
94 .powerpc => return "powerpc",
95 .powerpc64, .powerpc64le => return "powerpc64",
96 .s390x => return "s390x",
97 .i386 => return "i386",
98 .x86_64 => return "x86_64",
99 .riscv64 => return "riscv64",
100 else => unreachable,
101 }
102}
103
104pub fn canBuildLibC(target: std.Target) bool {
105 for (available_libcs) |libc| {
106 if (target.cpu.arch == libc.arch and target.os.tag == libc.os and target.abi == libc.abi) {
107 return true;
108 }
109 }
110 return false;
111}
src-self-hosted/test.zig+24-4
......@@ -4,6 +4,7 @@ const Module = @import("Module.zig");
44const Allocator = std.mem.Allocator;
55const zir = @import("zir.zig");
66const Package = @import("Package.zig");
7const introspect = @import("introspect.zig");
78const build_options = @import("build_options");
89const enable_qemu: bool = build_options.enable_qemu;
910const enable_wine: bool = build_options.enable_wine;
......@@ -406,6 +407,16 @@ pub const TestContext = struct {
406407 const root_node = try progress.start("tests", self.cases.items.len);
407408 defer root_node.end();
408409
410 const zig_lib_dir = try introspect.resolveZigLibDir(std.testing.allocator);
411 defer std.testing.allocator.free(zig_lib_dir);
412
413 const random_seed = blk: {
414 var random_seed: u64 = undefined;
415 try std.crypto.randomBytes(std.mem.asBytes(&random_seed));
416 break :blk random_seed;
417 };
418 var default_prng = std.rand.DefaultPrng.init(random_seed);
419
409420 for (self.cases.items) |case| {
410421 var prg_node = root_node.start(case.name, case.updates.items.len);
411422 prg_node.activate();
......@@ -416,11 +427,18 @@ pub const TestContext = struct {
416427 progress.initial_delay_ns = 0;
417428 progress.refresh_rate_ns = 0;
418429
419 try self.runOneCase(std.testing.allocator, &prg_node, case);
430 try self.runOneCase(std.testing.allocator, &prg_node, case, zig_lib_dir, &default_prng.random);
420431 }
421432 }
422433
423 fn runOneCase(self: *TestContext, allocator: *Allocator, root_node: *std.Progress.Node, case: Case) !void {
434 fn runOneCase(
435 self: *TestContext,
436 allocator: *Allocator,
437 root_node: *std.Progress.Node,
438 case: Case,
439 zig_lib_dir: []const u8,
440 rand: *std.rand.Random,
441 ) !void {
424442 const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);
425443 const target = target_info.target;
426444
......@@ -438,7 +456,9 @@ pub const TestContext = struct {
438456 const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null;
439457 const bin_name = try std.zig.binNameAlloc(arena, "test_case", target, case.output_mode, null, ofmt);
440458
441 var module = try Module.init(allocator, .{
459 const module = try Module.create(allocator, .{
460 .zig_lib_dir = zig_lib_dir,
461 .rand = rand,
442462 .root_name = "test_case",
443463 .target = target,
444464 // TODO: support tests for object file building, and library builds
......@@ -453,7 +473,7 @@ pub const TestContext = struct {
453473 .keep_source_files_loaded = true,
454474 .object_format = ofmt,
455475 });
456 defer module.deinit();
476 defer module.destroy();
457477
458478 for (case.updates.items) |update, update_index| {
459479 var update_node = root_node.start("update", 3);
src-self-hosted/zir.zig+3-3
......@@ -1700,12 +1700,12 @@ const Parser = struct {
17001700 }
17011701};
17021702
1703pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {
1703pub fn emit(allocator: *Allocator, old_module: *IrModule) !Module {
17041704 var ctx: EmitZIR = .{
17051705 .allocator = allocator,
17061706 .decls = .{},
17071707 .arena = std.heap.ArenaAllocator.init(allocator),
1708 .old_module = &old_module,
1708 .old_module = old_module,
17091709 .next_auto_name = 0,
17101710 .names = std.StringArrayHashMap(void).init(allocator),
17111711 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
......@@ -2539,7 +2539,7 @@ const EmitZIR = struct {
25392539 return self.emitUnnamedDecl(&fntype_inst.base);
25402540 },
25412541 .Int => {
2542 const info = ty.intInfo(self.old_module.target());
2542 const info = ty.intInfo(self.old_module.getTarget());
25432543 const signed = try self.emitPrimitive(src, if (info.signed) .@"true" else .@"false");
25442544 const bits_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
25452545 bits_payload.* = .{ .int = info.bits };
src/main.cpp+1-1
......@@ -78,7 +78,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
7878 " -fno-emit-asm (default) do not output .s (assembly code)\n"
7979 " -femit-llvm-ir produce a .ll file with LLVM IR\n"
8080 " -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n"
81 " -femit-h generate a C header file (.h)\n"
81 " -femit-h generate a C header file (.h)\n"
8282 " -fno-emit-h (default) do not generate a C header file (.h)\n"
8383 " --libc [file] Provide a file which specifies libc paths\n"
8484 " --name [name] override output name\n"