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);...@@ -10,6 +10,7 @@ const log = std.log.scoped(.module);
10const BigIntConst = std.math.big.int.Const;10const BigIntConst = std.math.big.int.Const;
11const BigIntMutable = std.math.big.int.Mutable;11const BigIntMutable = std.math.big.int.Mutable;
12const Target = std.Target;12const Target = std.Target;
13const target_util = @import("target.zig");
13const Package = @import("Package.zig");14const Package = @import("Package.zig");
14const link = @import("link.zig");15const link = @import("link.zig");
15const ir = @import("ir.zig");16const ir = @import("ir.zig");
...@@ -26,6 +27,8 @@ const build_options = @import("build_options");...@@ -26,6 +27,8 @@ const build_options = @import("build_options");
2627
27/// General-purpose allocator. Used for both temporary and long-term storage.28/// General-purpose allocator. Used for both temporary and long-term storage.
28gpa: *Allocator,29gpa: *Allocator,
30/// Arena-allocated memory used during initialization. Should be untouched until deinit.
31arena_state: std.heap.ArenaAllocator.State,
29/// Pointer to externally managed resource. `null` if there is no zig file being compiled.32/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
30root_pkg: ?*Package,33root_pkg: ?*Package,
31/// Module owns this resource.34/// Module owns this resource.
...@@ -85,6 +88,12 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},...@@ -85,6 +88,12 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
85root_name: []u8,88root_name: []u8,
86keep_source_files_loaded: bool,89keep_source_files_loaded: bool,
87use_clang: bool,90use_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
89/// Error tags and their values, tag names are duped with mod.gpa.98/// Error tags and their values, tag names are duped with mod.gpa.
90global_error_set: std.StringHashMapUnmanaged(u16) = .{},99global_error_set: std.StringHashMapUnmanaged(u16) = .{},
...@@ -92,6 +101,12 @@ global_error_set: std.StringHashMapUnmanaged(u16) = .{},...@@ -92,6 +101,12 @@ global_error_set: std.StringHashMapUnmanaged(u16) = .{},
92c_source_files: []const []const u8,101c_source_files: []const []const u8,
93clang_argv: []const []const u8,102clang_argv: []const []const u8,
94cache: std.cache_hash.CacheHash,103cache: 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
96pub const InnerError = error{ OutOfMemory, AnalysisFail };111pub const InnerError = error{ OutOfMemory, AnalysisFail };
97112
...@@ -913,10 +928,12 @@ pub const AllErrors = struct {...@@ -913,10 +928,12 @@ pub const AllErrors = struct {
913};928};
914929
915pub const InitOptions = struct {930pub const InitOptions = struct {
916 target: std.Target,931 zig_lib_dir: []const u8,
932 target: Target,
917 root_name: []const u8,933 root_name: []const u8,
918 root_pkg: ?*Package,934 root_pkg: ?*Package,
919 output_mode: std.builtin.OutputMode,935 output_mode: std.builtin.OutputMode,
936 rand: *std.rand.Random,
920 bin_file_dir: ?std.fs.Dir = null,937 bin_file_dir: ?std.fs.Dir = null,
921 bin_file_path: []const u8,938 bin_file_path: []const u8,
922 emit_h: ?[]const u8 = null,939 emit_h: ?[]const u8 = null,
...@@ -932,8 +949,8 @@ pub const InitOptions = struct {...@@ -932,8 +949,8 @@ pub const InitOptions = struct {
932 framework_dirs: []const []const u8 = &[0][]const u8{},949 framework_dirs: []const []const u8 = &[0][]const u8{},
933 frameworks: []const []const u8 = &[0][]const u8{},950 frameworks: []const []const u8 = &[0][]const u8{},
934 system_libs: []const []const u8 = &[0][]const u8{},951 system_libs: []const []const u8 = &[0][]const u8{},
935 have_libc: bool = false,952 link_libc: bool = false,
936 have_libcpp: bool = false,953 link_libcpp: bool = false,
937 want_pic: ?bool = null,954 want_pic: ?bool = null,
938 want_sanitize_c: ?bool = null,955 want_sanitize_c: ?bool = null,
939 use_llvm: ?bool = null,956 use_llvm: ?bool = null,
...@@ -943,170 +960,232 @@ pub const InitOptions = struct {...@@ -943,170 +960,232 @@ pub const InitOptions = struct {
943 strip: bool = false,960 strip: bool = false,
944 linker_script: ?[]const u8 = null,961 linker_script: ?[]const u8 = null,
945 version_script: ?[]const u8 = null,962 version_script: ?[]const u8 = null,
946 disable_c_depfile: bool = false,
947 override_soname: ?[]const u8 = null,963 override_soname: ?[]const u8 = null,
948 linker_optimization: ?[]const u8 = null,964 linker_optimization: ?[]const u8 = null,
949 linker_gc_sections: ?bool = null,965 linker_gc_sections: ?bool = null,
966 function_sections: ?bool = null,
950 linker_allow_shlib_undefined: ?bool = null,967 linker_allow_shlib_undefined: ?bool = null,
951 linker_bind_global_refs_locally: ?bool = null,968 linker_bind_global_refs_locally: ?bool = null,
969 disable_c_depfile: bool = false,
952 linker_z_nodelete: bool = false,970 linker_z_nodelete: bool = false,
953 linker_z_defs: bool = false,971 linker_z_defs: bool = false,
972 clang_passthrough_mode: bool = false,
954 stack_size_override: u64 = 0,973 stack_size_override: u64 = 0,
974 self_exe_path: ?[]const u8 = null,
955};975};
956976
957pub fn init(gpa: *Allocator, options: InitOptions) !Module {977pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
958 const root_name = try gpa.dupe(u8, options.root_name);978 const mod: *Module = mod: {
959 errdefer gpa.free(root_name);979 // For allocations that have the same lifetime as Module. This arena is used only during this
960980 // initialization and then is freed in deinit().
961 const ofmt = options.object_format orelse options.target.getObjectFormat();981 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
962982 errdefer arena_allocator.deinit();
963 // Make a decision on whether to use LLD or our own linker.983 const arena = &arena_allocator.allocator;
964 const use_lld = if (options.use_lld) |explicit| explicit else blk: {984
965 if (!build_options.have_llvm)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 }
966 break :blk false;1010 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.
969 break :blk false;1018 break :blk false;
1019 };
9701020
971 // Our linker can't handle objects or most advanced options yet.1021 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
972 if (options.link_objects.len != 0 or1022 const bin_file = try link.File.openPath(gpa, bin_file_dir, options.bin_file_path, .{
973 options.c_source_files.len != 0 or1023 .root_name = root_name,
974 options.frameworks.len != 0 or1024 .root_pkg = options.root_pkg,
975 options.system_libs.len != 0 or1025 .target = options.target,
976 options.have_libc or options.have_libcpp or1026 .output_mode = options.output_mode,
977 options.linker_script != null or options.version_script != null)1027 .link_mode = options.link_mode orelse .Static,
978 {1028 .object_format = ofmt,
979 break :blk true;1029 .optimize_mode = options.optimize_mode,
980 }1030 .use_lld = use_lld,
981 break :blk false;1031 .use_llvm = use_llvm,
982 };1032 .link_libc = options.link_libc,
9831033 .link_libcpp = options.link_libcpp,
984 // Make a decision on whether to use LLVM or our own backend.1034 .objects = options.link_objects,
985 const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {1035 .frameworks = options.frameworks,
986 // We would want to prefer LLVM for release builds when it is available, however1036 .framework_dirs = options.framework_dirs,
987 // we don't have an LLVM backend yet :)1037 .system_libs = options.system_libs,
988 // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.1038 .lib_dirs = options.lib_dirs,
989 break :blk false;1039 .rpath_list = options.rpath_list,
990 };1040 .strip = options.strip,
9911041 .function_sections = options.function_sections orelse false,
992 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();1042 });
993 const bin_file = try link.File.openPath(gpa, bin_file_dir, options.bin_file_path, .{1043 errdefer bin_file.destroy();
994 .root_name = root_name,1044
995 .root_pkg = options.root_pkg,1045 // We arena-allocate the root scope so there is no free needed.
996 .target = options.target,1046 const root_scope = blk: {
997 .output_mode = options.output_mode,1047 if (options.root_pkg) |root_pkg| {
998 .link_mode = options.link_mode orelse .Static,1048 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
999 .object_format = ofmt,1049 const root_scope = try gpa.create(Scope.File);
1000 .optimize_mode = options.optimize_mode,1050 root_scope.* = .{
1001 .use_lld = use_lld,1051 .sub_file_path = root_pkg.root_src_path,
1002 .use_llvm = use_llvm,1052 .source = .{ .unloaded = {} },
1003 .objects = options.link_objects,1053 .contents = .{ .not_available = {} },
1004 .frameworks = options.frameworks,1054 .status = .never_loaded,
1005 .framework_dirs = options.framework_dirs,1055 .root_container = .{
1006 .system_libs = options.system_libs,1056 .file_scope = root_scope,
1007 .lib_dirs = options.lib_dirs,1057 .decls = .{},
1008 .rpath_list = options.rpath_list,1058 },
1009 .strip = options.strip,1059 };
1010 });1060 break :blk &root_scope.base;
1011 errdefer bin_file.destroy();1061 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
10121062 const root_scope = try gpa.create(Scope.ZIRModule);
1013 const root_scope = blk: {1063 root_scope.* = .{
1014 if (options.root_pkg) |root_pkg| {1064 .sub_file_path = root_pkg.root_src_path,
1015 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {1065 .source = .{ .unloaded = {} },
1016 const root_scope = try gpa.create(Scope.File);1066 .contents = .{ .not_available = {} },
1017 root_scope.* = .{1067 .status = .never_loaded,
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,
1024 .decls = .{},1068 .decls = .{},
1025 },1069 };
1026 };1070 break :blk &root_scope.base;
1027 break :blk &root_scope.base;1071 } else {
1028 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {1072 unreachable;
1029 const root_scope = try gpa.create(Scope.ZIRModule);1073 }
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;
1038 } else {1074 } else {
1039 unreachable;1075 const root_scope = try gpa.create(Scope.None);
1076 root_scope.* = .{};
1077 break :blk &root_scope.base;
1040 }1078 }
1041 } else {1079 };
1042 const root_scope = try gpa.create(Scope.None);
1043 root_scope.* = .{};
1044 break :blk &root_scope.base;
1045 }
1046 };
10471080
1048 // We put everything into the cache hash except for the root source file, because we want to1081 // 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.1082 // 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 solving1083 // 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.1084 // 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();1085 const cache_parent_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");1086 var cache_dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
1054 errdefer cache.release();1087 defer cache_dir.close();
10551088
1056 // Now we will prepare hash state initializations to avoid redundantly computing hashes.1089 try cache_dir.makePath("tmp");
1057 // First we add common things between things that apply to zig source and all c source files.1090 try cache_dir.makePath("o");
1058 cache.addBytes(build_options.version);1091 // We need this string because of sending paths to clang as a child process.
1059 cache.add(options.optimize_mode);1092 const zig_cache_dir_path = if (options.root_pkg) |root_pkg|
1060 cache.add(options.target.cpu.arch);1093 try std.fmt.allocPrint(arena, "{}" ++ std.fs.path.sep_str ++ "zig-cache", .{root_pkg.root_src_dir_path})
1061 cache.addBytes(options.target.cpu.model.name);1094 else
1062 cache.add(options.target.cpu.features.ints);1095 "zig-cache";
1063 cache.add(options.target.os.tag);1096
1064 switch (options.target.os.tag) {1097 var cache = try std.cache_hash.CacheHash.init(gpa, cache_dir, "h");
1065 .linux => {1098 errdefer cache.release();
1066 cache.add(options.target.os.version_range.linux.range.min);1099
1067 cache.add(options.target.os.version_range.linux.range.max);1100 // Now we will prepare hash state initializations to avoid redundantly computing hashes.
1068 cache.add(options.target.os.version_range.linux.glibc);1101 // First we add common things between things that apply to zig source and all c source files.
1069 },1102 cache.addBytes(build_options.version);
1070 .windows => {1103 cache.add(options.optimize_mode);
1071 cache.add(options.target.os.version_range.windows.min);1104 cache.add(options.target.cpu.arch);
1072 cache.add(options.target.os.version_range.windows.max);1105 cache.addBytes(options.target.cpu.model.name);
1073 },1106 cache.add(options.target.cpu.features.ints);
1074 .freebsd,1107 cache.add(options.target.os.tag);
1075 .macosx,1108 switch (options.target.os.tag) {
1076 .ios,1109 .linux => {
1077 .tvos,1110 cache.add(options.target.os.version_range.linux.range.min);
1078 .watchos,1111 cache.add(options.target.os.version_range.linux.range.max);
1079 .netbsd,1112 cache.add(options.target.os.version_range.linux.glibc);
1080 .openbsd,1113 },
1081 .dragonfly,1114 .windows => {
1082 => {1115 cache.add(options.target.os.version_range.windows.min);
1083 cache.add(options.target.os.version_range.semver.min);1116 cache.add(options.target.os.version_range.windows.max);
1084 cache.add(options.target.os.version_range.semver.max);1117 },
1085 },1118 .freebsd,
1086 else => {},1119 .macosx,
1087 }1120 .ios,
1088 cache.add(options.target.abi);1121 .tvos,
1089 cache.add(ofmt);1122 .watchos,
1090 // TODO PIC (see detect_pic from codegen.cpp)1123 .netbsd,
1091 cache.add(bin_file.options.link_mode);1124 .openbsd,
1092 cache.add(options.strip);1125 .dragonfly,
10931126 => {
1094 // Make a decision on whether to use Clang for translate-c and compiling C files.1127 cache.add(options.target.os.version_range.semver.min);
1095 const use_clang = if (options.use_clang) |explicit| explicit else blk: {1128 cache.add(options.target.os.version_range.semver.max);
1096 if (build_options.have_llvm) {1129 },
1097 // Can't use it if we don't have it!1130 else => {},
1098 break :blk false;
1099 }1131 }
1100 // It's not planned to do our own translate-c or C compilation.1132 cache.add(options.target.abi);
1101 break :blk true;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;
1102 };1184 };
1103 var c_object_table = std.AutoArrayHashMapUnmanaged(*CObject, void){};1185 errdefer mod.destroy();
1104 errdefer {1186
1105 for (c_object_table.items()) |entry| entry.key.destroy(gpa);
1106 c_object_table.deinit(gpa);
1107 }
1108 // Add a `CObject` for each `c_source_files`.1187 // 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);
1110 for (options.c_source_files) |c_source_file| {1189 for (options.c_source_files) |c_source_file| {
1111 var local_arena = std.heap.ArenaAllocator.init(gpa);1190 var local_arena = std.heap.ArenaAllocator.init(gpa);
1112 errdefer local_arena.deinit();1191 errdefer local_arena.deinit();
...@@ -1120,31 +1199,15 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {...@@ -1120,31 +1199,15 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
1120 .extra_flags = &[0][]const u8{},1199 .extra_flags = &[0][]const u8{},
1121 .arena = local_arena.state,1200 .arena = local_arena.state,
1122 };1201 };
1123 c_object_table.putAssumeCapacityNoClobber(c_object, {});1202 mod.c_object_table.putAssumeCapacityNoClobber(c_object, {});
1124 }1203 }
11251204
1126 return Module{1205 return mod;
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 };
1142}1206}
11431207
1144pub fn deinit(self: *Module) void {1208pub fn destroy(self: *Module) void {
1145 self.bin_file.destroy();1209 self.bin_file.destroy();
1146 const gpa = self.gpa;1210 const gpa = self.gpa;
1147 self.gpa.free(self.root_name);
1148 self.deletion_set.deinit(gpa);1211 self.deletion_set.deinit(gpa);
1149 self.work_queue.deinit();1212 self.work_queue.deinit();
11501213
...@@ -1198,7 +1261,9 @@ pub fn deinit(self: *Module) void {...@@ -1198,7 +1261,9 @@ pub fn deinit(self: *Module) void {
1198 }1261 }
1199 self.global_error_set.deinit(gpa);1262 self.global_error_set.deinit(gpa);
1200 self.cache.release();1263 self.cache.release();
1201 self.* = undefined;1264
1265 // This destroys `self`.
1266 self.arena_state.promote(gpa).deinit();
1202}1267}
12031268
1204fn freeExportList(gpa: *Allocator, export_list: []*Export) void {1269fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
...@@ -1209,7 +1274,7 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {...@@ -1209,7 +1274,7 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
1209 gpa.free(export_list);1274 gpa.free(export_list);
1210}1275}
12111276
1212pub fn target(self: Module) std.Target {1277pub fn getTarget(self: Module) Target {
1213 return self.bin_file.options.target;1278 return self.bin_file.options.target;
1214}1279}
12151280
...@@ -1440,29 +1505,335 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -1440,29 +1505,335 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
1440 c_object.status = .{ .new = {} };1505 c_object.status = .{ .new = {} };
1441 },1506 },
1442 }1507 }
1443 if (!build_options.have_llvm) {1508 self.buildCObject(c_object) catch |err| switch (err) {
1444 try self.failed_c_objects.ensureCapacity(self.gpa, self.failed_c_objects.items().len + 1);1509 error.AnalysisFail => continue,
1445 self.failed_c_objects.putAssumeCapacityNoClobber(c_object, try ErrorMsg.create(1510 else => {
1446 self.gpa,1511 try self.failed_c_objects.ensureCapacity(self.gpa, self.failed_c_objects.items().len + 1);
1447 0,1512 self.failed_c_objects.putAssumeCapacityNoClobber(c_object, try ErrorMsg.create(
1448 "clang not available: compiler not built with LLVM extensions enabled",1513 self.gpa,
1449 .{},1514 0,
1450 ));1515 "unable to build C object: {}",
1451 c_object.status = .{ .failure = "" };1516 .{@errorName(err)},
1452 continue;1517 ));
1453 }1518 c_object.status = .{ .failure = "" };
1454 try self.failed_c_objects.ensureCapacity(self.gpa, self.failed_c_objects.items().len + 1);1519 },
1455 self.failed_c_objects.putAssumeCapacityNoClobber(c_object, try ErrorMsg.create(1520 };
1456 self.gpa,
1457 0,
1458 "TODO: implement invoking clang to compile C source files",
1459 .{},
1460 ));
1461 c_object.status = .{ .failure = "" };
1462 },1521 },
1463 };1522 };
1464}1523}
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
1466pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {1837pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
1467 const tracy = trace(@src());1838 const tracy = trace(@src());
1468 defer tracy.end();1839 defer tracy.end();
...@@ -3041,7 +3412,7 @@ pub fn cmpNumeric(...@@ -3041,7 +3412,7 @@ pub fn cmpNumeric(
3041 } else if (rhs_ty_tag == .ComptimeFloat) {3412 } else if (rhs_ty_tag == .ComptimeFloat) {
3042 break :x lhs.ty;3413 break :x lhs.ty;
3043 }3414 }
3044 if (lhs.ty.floatBits(self.target()) >= rhs.ty.floatBits(self.target())) {3415 if (lhs.ty.floatBits(self.getTarget()) >= rhs.ty.floatBits(self.getTarget())) {
3045 break :x lhs.ty;3416 break :x lhs.ty;
3046 } else {3417 } else {
3047 break :x rhs.ty;3418 break :x rhs.ty;
...@@ -3100,7 +3471,7 @@ pub fn cmpNumeric(...@@ -3100,7 +3471,7 @@ pub fn cmpNumeric(
3100 } else if (lhs_is_float) {3471 } else if (lhs_is_float) {
3101 dest_float_type = lhs.ty;3472 dest_float_type = lhs.ty;
3102 } else {3473 } else {
3103 const int_info = lhs.ty.intInfo(self.target());3474 const int_info = lhs.ty.intInfo(self.getTarget());
3104 lhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);3475 lhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
3105 }3476 }
31063477
...@@ -3135,7 +3506,7 @@ pub fn cmpNumeric(...@@ -3135,7 +3506,7 @@ pub fn cmpNumeric(
3135 } else if (rhs_is_float) {3506 } else if (rhs_is_float) {
3136 dest_float_type = rhs.ty;3507 dest_float_type = rhs.ty;
3137 } else {3508 } else {
3138 const int_info = rhs.ty.intInfo(self.target());3509 const int_info = rhs.ty.intInfo(self.getTarget());
3139 rhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);3510 rhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
3140 }3511 }
31413512
...@@ -3200,13 +3571,13 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty...@@ -3200,13 +3571,13 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
3200 next_inst.ty.isInt() and3571 next_inst.ty.isInt() and
3201 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())3572 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())
3202 {3573 {
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) {
3204 prev_inst = next_inst;3575 prev_inst = next_inst;
3205 }3576 }
3206 continue;3577 continue;
3207 }3578 }
3208 if (prev_inst.ty.isFloat() and next_inst.ty.isFloat()) {3579 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())) {
3210 prev_inst = next_inst;3581 prev_inst = next_inst;
3211 }3582 }
3212 continue;3583 continue;
...@@ -3274,8 +3645,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst...@@ -3274,8 +3645,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
3274 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {3645 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
3275 assert(inst.value() == null); // handled above3646 assert(inst.value() == null); // handled above
32763647
3277 const src_info = inst.ty.intInfo(self.target());3648 const src_info = inst.ty.intInfo(self.getTarget());
3278 const dst_info = dest_type.intInfo(self.target());3649 const dst_info = dest_type.intInfo(self.getTarget());
3279 if ((src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) or3650 if ((src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) or
3280 // small enough unsigned ints can get casted to large enough signed ints3651 // small enough unsigned ints can get casted to large enough signed ints
3281 (src_info.signed and !dst_info.signed and dst_info.bits > src_info.bits))3652 (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...@@ -3289,8 +3660,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
3289 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {3660 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
3290 assert(inst.value() == null); // handled above3661 assert(inst.value() == null); // handled above
32913662
3292 const src_bits = inst.ty.floatBits(self.target());3663 const src_bits = inst.ty.floatBits(self.getTarget());
3293 const dst_bits = dest_type.floatBits(self.target());3664 const dst_bits = dest_type.floatBits(self.getTarget());
3294 if (dst_bits >= src_bits) {3665 if (dst_bits >= src_bits) {
3295 const b = try self.requireRuntimeBlock(scope, inst.src);3666 const b = try self.requireRuntimeBlock(scope, inst.src);
3296 return self.addUnOp(b, inst.src, dest_type, .floatcast, inst);3667 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) !?*...@@ -3312,14 +3683,14 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*
3312 }3683 }
3313 return self.fail(scope, inst.src, "TODO float to int", .{});3684 return self.fail(scope, inst.src, "TODO float to int", .{});
3314 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {3685 } 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())) {
3316 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });3687 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
3317 }3688 }
3318 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });3689 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3319 }3690 }
3320 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {3691 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
3321 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {3692 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) {
3323 error.Overflow => return self.fail(3694 error.Overflow => return self.fail(
3324 scope,3695 scope,
3325 inst.src,3696 inst.src,
...@@ -3370,6 +3741,22 @@ fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *I...@@ -3370,6 +3741,22 @@ fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *I
3370 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});3741 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
3371}3742}
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
3373pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {3760pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {
3374 @setCold(true);3761 @setCold(true);
3375 const err_msg = try ErrorMsg.create(self.gpa, src, format, args);3762 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 {...@@ -3560,7 +3947,7 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
3560pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {3947pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
3561 var bit_count = switch (float_type.tag()) {3948 var bit_count = switch (float_type.tag()) {
3562 .comptime_float => 128,3949 .comptime_float => 128,
3563 else => float_type.floatBits(self.target()),3950 else => float_type.floatBits(self.getTarget()),
3564 };3951 };
35653952
3566 const allocator = scope.arena();3953 const allocator = scope.arena();
...@@ -3594,7 +3981,7 @@ pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:...@@ -3594,7 +3981,7 @@ pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
3594pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {3981pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
3595 var bit_count = switch (float_type.tag()) {3982 var bit_count = switch (float_type.tag()) {
3596 .comptime_float => 128,3983 .comptime_float => 128,
3597 else => float_type.floatBits(self.target()),3984 else => float_type.floatBits(self.getTarget()),
3598 };3985 };
35993986
3600 const allocator = scope.arena();3987 const allocator = scope.arena();
...@@ -3865,3 +4252,106 @@ pub fn safetyPanic(mod: *Module, block: *Scope.Block, src: usize, panic_id: Pani...@@ -3865,3 +4252,106 @@ pub fn safetyPanic(mod: *Module, block: *Scope.Block, src: usize, panic_id: Pani
3865 _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint);4252 _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint);
3866 return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach);4253 return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach);
3867}4254}
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 {...@@ -93,46 +93,3 @@ pub fn openGlobalCacheDir() !fs.Dir {
93 const path_name = try resolveGlobalCacheDir(&fba.allocator);93 const path_name = try resolveGlobalCacheDir(&fba.allocator);
94 return fs.cwd().makeOpenPath(path_name, .{});94 return fs.cwd().makeOpenPath(path_name, .{});
95}95}
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 {...@@ -35,6 +35,9 @@ pub const Options = struct {
35 /// other objects.35 /// other objects.
36 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.36 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.
37 use_llvm: bool = false,37 use_llvm: bool = false,
38 link_libc: bool = false,
39 link_libcpp: bool = false,
40 function_sections: bool = false,
3841
39 objects: []const []const u8 = &[0][]const u8{},42 objects: []const []const u8 = &[0][]const u8{},
40 framework_dirs: []const []const u8 = &[0][]const u8{},43 framework_dirs: []const []const u8 = &[0][]const u8{},
src-self-hosted/link/Elf.zig+19-3
...@@ -219,8 +219,11 @@ pub const SrcFn = struct {...@@ -219,8 +219,11 @@ pub const SrcFn = struct {
219pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File {219pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File {
220 assert(options.object_format == .elf);220 assert(options.object_format == .elf);
221221
222 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForELF; // TODO222 if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO
223 if (options.use_lld) return error.LLD_LinkingIsTODOForELF; // TODO223
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
225 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options) });228 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options) });
226 errdefer file.close();229 errdefer file.close();
...@@ -741,8 +744,21 @@ pub const abbrev_base_type = 4;...@@ -741,8 +744,21 @@ pub const abbrev_base_type = 4;
741pub const abbrev_pad1 = 5;744pub const abbrev_pad1 = 5;
742pub const abbrev_parameter = 6;745pub const abbrev_parameter = 6;
743746
744/// Commit pending changes and write headers.
745pub fn flush(self: *Elf, module: *Module) !void {747pub 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 {
746 const target_endian = self.base.options.target.cpu.arch.endian();762 const target_endian = self.base.options.target.cpu.arch.endian();
747 const foreign_endian = target_endian != std.Target.current.cpu.arch.endian();763 const foreign_endian = target_endian != std.Target.current.cpu.arch.endian();
748 const ptr_width_bytes: u8 = self.ptrWidthBytes();764 const ptr_width_bytes: u8 = self.ptrWidthBytes();
src-self-hosted/main.zig+93-101
...@@ -33,13 +33,14 @@ const usage =...@@ -33,13 +33,14 @@ const usage =
33 \\33 \\
34 \\Commands:34 \\Commands:
35 \\35 \\
36 \\ build-exe [source] Create executable from source or object files36 \\ build-exe [source] Create executable from source or object files
37 \\ build-lib [source] Create library from source or object files37 \\ build-lib [source] Create library from source or object files
38 \\ build-obj [source] Create object from source or assembly38 \\ build-obj [source] Create object from source or assembly
39 \\ cc Use Zig as a drop-in C compiler39 \\ cc Use Zig as a drop-in C compiler
40 \\ c++ Use Zig as a drop-in C++ compiler40 \\ c++ Use Zig as a drop-in C++ compiler
41 \\ env Print lib path, std path, compiler id and version41 \\ env Print lib path, std path, compiler id and version
42 \\ fmt [source] Parse file and render in canonical zig format42 \\ fmt [source] Parse file and render in canonical zig format
43 \\ translate-c [source] Convert C code to Zig code
43 \\ targets List available compilation targets44 \\ targets List available compilation targets
44 \\ version Print version number and exit45 \\ version Print version number and exit
45 \\ zen Print zen of zig and exit46 \\ zen Print zen of zig and exit
...@@ -47,15 +48,21 @@ const usage =...@@ -47,15 +48,21 @@ const usage =
47 \\48 \\
48;49;
4950
51pub const log_level: std.log.Level = switch (std.builtin.mode) {
52 .Debug => .debug,
53 .ReleaseSafe, .ReleaseFast => .info,
54 .ReleaseSmall => .crit,
55};
56
50pub fn log(57pub fn log(
51 comptime level: std.log.Level,58 comptime level: std.log.Level,
52 comptime scope: @TypeOf(.EnumLiteral),59 comptime scope: @TypeOf(.EnumLiteral),
53 comptime format: []const u8,60 comptime format: []const u8,
54 args: anytype,61 args: anytype,
55) void {62) void {
56 // Hide anything more verbose than warn unless it was added with `-Dlog=foo`.63 // Hide debug messages unless added with `-Dlog=foo`.
57 if (@enumToInt(level) > @enumToInt(std.log.level) or64 if (@enumToInt(level) > @enumToInt(std.log.level) or
58 @enumToInt(level) > @enumToInt(std.log.Level.warn))65 @enumToInt(level) > @enumToInt(std.log.Level.info))
59 {66 {
60 const scope_name = @tagName(scope);67 const scope_name = @tagName(scope);
61 const ok = comptime for (build_options.log_scopes) |log_scope| {68 const ok = comptime for (build_options.log_scopes) |log_scope| {
...@@ -67,13 +74,15 @@ pub fn log(...@@ -67,13 +74,15 @@ pub fn log(
67 return;74 return;
68 }75 }
6976
77 // We only recognize 4 log levels in this application.
70 const level_txt = switch (level) {78 const level_txt = switch (level) {
71 .emerg => "error",79 .emerg, .alert, .crit => "error",
72 .warn => "warning",80 .err, .warn => "warning",
73 else => @tagName(level),81 .notice, .info => "info",
82 .debug => "debug",
74 };83 };
75 const prefix1 = level_txt ++ ": ";84 const prefix1 = level_txt;
76 const prefix2 = if (scope == .default) "" else "(" ++ @tagName(scope) ++ "): ";85 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
7786
78 // Print the message to stderr, silently ignoring any errors87 // Print the message to stderr, silently ignoring any errors
79 std.debug.print(prefix1 ++ prefix2 ++ format ++ "\n", args);88 std.debug.print(prefix1 ++ prefix2 ++ format ++ "\n", args);
...@@ -93,8 +102,8 @@ pub fn main() !void {...@@ -93,8 +102,8 @@ pub fn main() !void {
93 const args = try process.argsAlloc(arena);102 const args = try process.argsAlloc(arena);
94103
95 if (args.len <= 1) {104 if (args.len <= 1) {
96 std.debug.print("expected command argument\n\n{}", .{usage});105 std.log.info("{}", .{usage});
97 process.exit(1);106 fatal("expected command argument", .{});
98 }107 }
99108
100 const cmd = args[1];109 const cmd = args[1];
...@@ -109,6 +118,8 @@ pub fn main() !void {...@@ -109,6 +118,8 @@ pub fn main() !void {
109 return buildOutputType(gpa, arena, args, .cc);118 return buildOutputType(gpa, arena, args, .cc);
110 } else if (mem.eql(u8, cmd, "c++")) {119 } else if (mem.eql(u8, cmd, "c++")) {
111 return buildOutputType(gpa, arena, args, .cpp);120 return buildOutputType(gpa, arena, args, .cpp);
121 } else if (mem.eql(u8, cmd, "translate-c")) {
122 return buildOutputType(gpa, arena, args, .translate_c);
112 } else if (mem.eql(u8, cmd, "clang") or123 } else if (mem.eql(u8, cmd, "clang") or
113 mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))124 mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
114 {125 {
...@@ -128,8 +139,8 @@ pub fn main() !void {...@@ -128,8 +139,8 @@ pub fn main() !void {
128 } else if (mem.eql(u8, cmd, "help")) {139 } else if (mem.eql(u8, cmd, "help")) {
129 try io.getStdOut().writeAll(usage);140 try io.getStdOut().writeAll(usage);
130 } else {141 } else {
131 std.debug.print("unknown command: {}\n\n{}", .{ args[1], usage });142 std.log.info("{}", .{usage});
132 process.exit(1);143 fatal("unknown command: {}", .{args[1]});
133 }144 }
134}145}
135146
...@@ -223,6 +234,7 @@ pub fn buildOutputType(...@@ -223,6 +234,7 @@ pub fn buildOutputType(
223 build: std.builtin.OutputMode,234 build: std.builtin.OutputMode,
224 cc,235 cc,
225 cpp,236 cpp,
237 translate_c,
226 },238 },
227) !void {239) !void {
228 var color: Color = .Auto;240 var color: Color = .Auto;
...@@ -251,8 +263,8 @@ pub fn buildOutputType(...@@ -251,8 +263,8 @@ pub fn buildOutputType(
251 var emit_h: Emit = undefined;263 var emit_h: Emit = undefined;
252 var ensure_libc_on_non_freestanding = false;264 var ensure_libc_on_non_freestanding = false;
253 var ensure_libcpp_on_non_freestanding = false;265 var ensure_libcpp_on_non_freestanding = false;
254 var have_libc = false;266 var link_libc = false;
255 var have_libcpp = false;267 var link_libcpp = false;
256 var want_native_include_dirs = false;268 var want_native_include_dirs = false;
257 var enable_cache: ?bool = null;269 var enable_cache: ?bool = null;
258 var want_pic: ?bool = null;270 var want_pic: ?bool = null;
...@@ -298,13 +310,20 @@ pub fn buildOutputType(...@@ -298,13 +310,20 @@ pub fn buildOutputType(
298 var frameworks = std.ArrayList([]const u8).init(gpa);310 var frameworks = std.ArrayList([]const u8).init(gpa);
299 defer frameworks.deinit();311 defer frameworks.deinit();
300312
301 if (arg_mode == .build) {313 if (arg_mode == .build or arg_mode == .translate_c) {
302 output_mode = arg_mode.build;314 output_mode = switch (arg_mode) {
303 emit_h = switch (output_mode) {315 .build => |m| m,
304 .Exe => .no,316 .translate_c => .Obj,
305 .Obj, .Lib => .yes_default_path,317 else => unreachable,
306 };318 };
307319 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 }
308 const args = all_args[2..];327 const args = all_args[2..];
309 var i: usize = 0;328 var i: usize = 0;
310 while (i < args.len) : (i += 1) {329 while (i < args.len) : (i += 1) {
...@@ -499,7 +518,7 @@ pub fn buildOutputType(...@@ -499,7 +518,7 @@ pub fn buildOutputType(
499 mem.endsWith(u8, arg, ".lib"))518 mem.endsWith(u8, arg, ".lib"))
500 {519 {
501 try link_objects.append(arg);520 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)) {
503 try c_source_files.append(arg);522 try c_source_files.append(arg);
504 } else if (mem.endsWith(u8, arg, ".so") or523 } else if (mem.endsWith(u8, arg, ".so") or
505 mem.endsWith(u8, arg, ".dylib") or524 mem.endsWith(u8, arg, ".dylib") or
...@@ -543,7 +562,7 @@ pub fn buildOutputType(...@@ -543,7 +562,7 @@ pub fn buildOutputType(
543 try clang_argv.appendSlice(it.other_args);562 try clang_argv.appendSlice(it.other_args);
544 },563 },
545 .positional => {564 .positional => {
546 const file_ext = classify_file_ext(mem.spanZ(it.only_arg));565 const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg));
547 switch (file_ext) {566 switch (file_ext) {
548 .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg),567 .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg),
549 .unknown => try link_objects.append(it.only_arg),568 .unknown => try link_objects.append(it.only_arg),
...@@ -819,28 +838,28 @@ pub fn buildOutputType(...@@ -819,28 +838,28 @@ pub fn buildOutputType(
819 .diagnostics = &diags,838 .diagnostics = &diags,
820 }) catch |err| switch (err) {839 }) catch |err| switch (err) {
821 error.UnknownCpuModel => {840 error.UnknownCpuModel => {
822 std.debug.print("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{841 help: {
823 diags.cpu_name.?,842 var help_text = std.ArrayList(u8).init(arena);
824 @tagName(diags.arch.?),843 for (diags.arch.?.allCpuModels()) |cpu| {
825 });844 help_text.writer().print(" {}\n", .{cpu.name}) catch break :help;
826 for (diags.arch.?.allCpuModels()) |cpu| {845 }
827 std.debug.print(" {}\n", .{cpu.name});846 std.log.info("Available CPUs for architecture '{}': {}", .{
847 @tagName(diags.arch.?), help_text.items,
848 });
828 }849 }
829 process.exit(1);850 fatal("Unknown CPU: '{}'", .{diags.cpu_name.?});
830 },851 },
831 error.UnknownCpuFeature => {852 error.UnknownCpuFeature => {
832 std.debug.print(853 help: {
833 \\Unknown CPU feature: '{}'854 var help_text = std.ArrayList(u8).init(arena);
834 \\Available CPU features for architecture '{}':855 for (diags.arch.?.allFeaturesList()) |feature| {
835 \\856 help_text.writer().print(" {}: {}\n", .{ feature.name, feature.description }) catch break :help;
836 , .{857 }
837 diags.unknown_feature_name,858 std.log.info("Available CPU features for architecture '{}': {}", .{
838 @tagName(diags.arch.?),859 @tagName(diags.arch.?), help_text.items,
839 });860 });
840 for (diags.arch.?.allFeaturesList()) |feature| {
841 std.debug.print(" {}: {}\n", .{ feature.name, feature.description });
842 }861 }
843 process.exit(1);862 fatal("Unknown CPU feature: '{}'", .{diags.unknown_feature_name});
844 },863 },
845 else => |e| return e,864 else => |e| return e,
846 };865 };
...@@ -849,14 +868,16 @@ pub fn buildOutputType(...@@ -849,14 +868,16 @@ pub fn buildOutputType(
849 if (target_info.cpu_detection_unimplemented) {868 if (target_info.cpu_detection_unimplemented) {
850 // TODO We want to just use detected_info.target but implementing869 // TODO We want to just use detected_info.target but implementing
851 // CPU model & feature detection is todo so here we rely on LLVM.870 // 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.
852 fatal("CPU features detection is not yet available for this system without LLVM extensions", .{});873 fatal("CPU features detection is not yet available for this system without LLVM extensions", .{});
853 }874 }
854875
855 if (target_info.target.os.tag != .freestanding) {876 if (target_info.target.os.tag != .freestanding) {
856 if (ensure_libc_on_non_freestanding)877 if (ensure_libc_on_non_freestanding)
857 have_libc = true;878 link_libc = true;
858 if (ensure_libcpp_on_non_freestanding)879 if (ensure_libcpp_on_non_freestanding)
859 have_libcpp = true;880 link_libcpp = true;
860 }881 }
861882
862 // Now that we have target info, we can find out if any of the system libraries883 // Now that we have target info, we can find out if any of the system libraries
...@@ -867,12 +888,12 @@ pub fn buildOutputType(...@@ -867,12 +888,12 @@ pub fn buildOutputType(
867 while (i < system_libs.items.len) {888 while (i < system_libs.items.len) {
868 const lib_name = system_libs.items[i];889 const lib_name = system_libs.items[i];
869 if (is_libc_lib_name(target_info.target, lib_name)) {890 if (is_libc_lib_name(target_info.target, lib_name)) {
870 have_libc = true;891 link_libc = true;
871 _ = system_libs.orderedRemove(i);892 _ = system_libs.orderedRemove(i);
872 continue;893 continue;
873 }894 }
874 if (is_libcpp_lib_name(target_info.target, lib_name)) {895 if (is_libcpp_lib_name(target_info.target, lib_name)) {
875 have_libcpp = true;896 link_libcpp = true;
876 _ = system_libs.orderedRemove(i);897 _ = system_libs.orderedRemove(i);
877 continue;898 continue;
878 }899 }
...@@ -960,7 +981,21 @@ pub fn buildOutputType(...@@ -960,7 +981,21 @@ pub fn buildOutputType(
960 .yes_default_path => try std.fmt.allocPrint(arena, "{}.h", .{root_name}),981 .yes_default_path => try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
961 };982 };
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,
964 .root_name = root_name,999 .root_name = root_name,
965 .target = target_info.target,1000 .target = target_info.target,
966 .output_mode = output_mode,1001 .output_mode = output_mode,
...@@ -980,8 +1015,8 @@ pub fn buildOutputType(...@@ -980,8 +1015,8 @@ pub fn buildOutputType(
980 .frameworks = frameworks.items,1015 .frameworks = frameworks.items,
981 .system_libs = system_libs.items,1016 .system_libs = system_libs.items,
982 .emit_h = emit_h_path,1017 .emit_h = emit_h_path,
983 .have_libc = have_libc,1018 .link_libc = link_libc,
984 .have_libcpp = have_libcpp,1019 .link_libcpp = link_libcpp,
985 .want_pic = want_pic,1020 .want_pic = want_pic,
986 .want_sanitize_c = want_sanitize_c,1021 .want_sanitize_c = want_sanitize_c,
987 .use_llvm = use_llvm,1022 .use_llvm = use_llvm,
...@@ -1000,16 +1035,19 @@ pub fn buildOutputType(...@@ -1000,16 +1035,19 @@ pub fn buildOutputType(
1000 .linker_z_defs = linker_z_defs,1035 .linker_z_defs = linker_z_defs,
1001 .stack_size_override = stack_size_override,1036 .stack_size_override = stack_size_override,
1002 .strip = strip,1037 .strip = strip,
1038 .self_exe_path = self_exe_path,
1039 .rand = &default_prng.random,
1040 .clang_passthrough_mode = arg_mode != .build,
1003 }) catch |err| {1041 }) catch |err| {
1004 fatal("unable to initialize module: {}", .{@errorName(err)});1042 fatal("unable to create module: {}", .{@errorName(err)});
1005 };1043 };
1006 defer module.deinit();1044 defer module.destroy();
10071045
1008 const stdin = std.io.getStdIn().inStream();1046 const stdin = std.io.getStdIn().inStream();
1009 const stderr = std.io.getStdErr().outStream();1047 const stderr = std.io.getStdErr().outStream();
1010 var repl_buf: [1024]u8 = undefined;1048 var repl_buf: [1024]u8 = undefined;
10111049
1012 try updateModule(gpa, &module, zir_out_path);1050 try updateModule(gpa, module, zir_out_path);
10131051
1014 if (build_options.have_llvm and only_pp_or_asm) {1052 if (build_options.have_llvm and only_pp_or_asm) {
1015 // this may include dumping the output to stdout1053 // this may include dumping the output to stdout
...@@ -1031,7 +1069,7 @@ pub fn buildOutputType(...@@ -1031,7 +1069,7 @@ pub fn buildOutputType(
1031 if (output_mode == .Exe) {1069 if (output_mode == .Exe) {
1032 try module.makeBinFileWritable();1070 try module.makeBinFileWritable();
1033 }1071 }
1034 try updateModule(gpa, &module, zir_out_path);1072 try updateModule(gpa, module, zir_out_path);
1035 } else if (mem.eql(u8, actual_line, "exit")) {1073 } else if (mem.eql(u8, actual_line, "exit")) {
1036 break;1074 break;
1037 } else if (mem.eql(u8, actual_line, "help")) {1075 } else if (mem.eql(u8, actual_line, "help")) {
...@@ -1062,12 +1100,10 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo...@@ -1062,12 +1100,10 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo
1062 full_err_msg.msg,1100 full_err_msg.msg,
1063 });1101 });
1064 }1102 }
1065 } else {
1066 std.log.info("Update completed in {} ms", .{update_nanos / std.time.ns_per_ms});
1067 }1103 }
10681104
1069 if (zir_out_path) |zop| {1105 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);
1071 defer new_zir_module.deinit(gpa);1107 defer new_zir_module.deinit(gpa);
10721108
1073 const baf = try io.BufferedAtomicFile.create(gpa, fs.cwd(), zop, .{});1109 const baf = try io.BufferedAtomicFile.create(gpa, fs.cwd(), zop, .{});
...@@ -1422,50 +1458,6 @@ pub const info_zen =...@@ -1422,50 +1458,6 @@ pub const info_zen =
1422 \\1458 \\
1423;1459;
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
1469extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;1461extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
14701462
1471/// TODO make it so the return value can be !noreturn1463/// 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;...@@ -4,60 +4,11 @@ const io = std.io;
4const mem = std.mem;4const mem = std.mem;
5const Allocator = mem.Allocator;5const Allocator = mem.Allocator;
6const Target = std.Target;6const Target = std.Target;
7const target = @import("target.zig");
7const assert = std.debug.assert;8const assert = std.debug.assert;
89
9const introspect = @import("introspect.zig");10const 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
61pub fn cmdTargets(12pub fn cmdTargets(
62 allocator: *Allocator,13 allocator: *Allocator,
63 args: []const []const u8,14 args: []const []const u8,
...@@ -127,9 +78,13 @@ pub fn cmdTargets(...@@ -127,9 +78,13 @@ pub fn cmdTargets(
12778
128 try jws.objectField("libc");79 try jws.objectField("libc");
129 try jws.beginArray();80 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);
131 try jws.arrayElem();86 try jws.arrayElem();
132 try jws.emitString(libc);87 try jws.emitString(tmp);
133 }88 }
134 try jws.endArray();89 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");...@@ -4,6 +4,7 @@ const Module = @import("Module.zig");
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const zir = @import("zir.zig");5const zir = @import("zir.zig");
6const Package = @import("Package.zig");6const Package = @import("Package.zig");
7const introspect = @import("introspect.zig");
7const build_options = @import("build_options");8const build_options = @import("build_options");
8const enable_qemu: bool = build_options.enable_qemu;9const enable_qemu: bool = build_options.enable_qemu;
9const enable_wine: bool = build_options.enable_wine;10const enable_wine: bool = build_options.enable_wine;
...@@ -406,6 +407,16 @@ pub const TestContext = struct {...@@ -406,6 +407,16 @@ pub const TestContext = struct {
406 const root_node = try progress.start("tests", self.cases.items.len);407 const root_node = try progress.start("tests", self.cases.items.len);
407 defer root_node.end();408 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
409 for (self.cases.items) |case| {420 for (self.cases.items) |case| {
410 var prg_node = root_node.start(case.name, case.updates.items.len);421 var prg_node = root_node.start(case.name, case.updates.items.len);
411 prg_node.activate();422 prg_node.activate();
...@@ -416,11 +427,18 @@ pub const TestContext = struct {...@@ -416,11 +427,18 @@ pub const TestContext = struct {
416 progress.initial_delay_ns = 0;427 progress.initial_delay_ns = 0;
417 progress.refresh_rate_ns = 0;428 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);
420 }431 }
421 }432 }
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 {
424 const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);442 const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);
425 const target = target_info.target;443 const target = target_info.target;
426444
...@@ -438,7 +456,9 @@ pub const TestContext = struct {...@@ -438,7 +456,9 @@ pub const TestContext = struct {
438 const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null;456 const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null;
439 const bin_name = try std.zig.binNameAlloc(arena, "test_case", target, case.output_mode, null, ofmt);457 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,
442 .root_name = "test_case",462 .root_name = "test_case",
443 .target = target,463 .target = target,
444 // TODO: support tests for object file building, and library builds464 // TODO: support tests for object file building, and library builds
...@@ -453,7 +473,7 @@ pub const TestContext = struct {...@@ -453,7 +473,7 @@ pub const TestContext = struct {
453 .keep_source_files_loaded = true,473 .keep_source_files_loaded = true,
454 .object_format = ofmt,474 .object_format = ofmt,
455 });475 });
456 defer module.deinit();476 defer module.destroy();
457477
458 for (case.updates.items) |update, update_index| {478 for (case.updates.items) |update, update_index| {
459 var update_node = root_node.start("update", 3);479 var update_node = root_node.start("update", 3);
src-self-hosted/zir.zig+3-3
...@@ -1700,12 +1700,12 @@ const Parser = struct {...@@ -1700,12 +1700,12 @@ const Parser = struct {
1700 }1700 }
1701};1701};
17021702
1703pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {1703pub fn emit(allocator: *Allocator, old_module: *IrModule) !Module {
1704 var ctx: EmitZIR = .{1704 var ctx: EmitZIR = .{
1705 .allocator = allocator,1705 .allocator = allocator,
1706 .decls = .{},1706 .decls = .{},
1707 .arena = std.heap.ArenaAllocator.init(allocator),1707 .arena = std.heap.ArenaAllocator.init(allocator),
1708 .old_module = &old_module,1708 .old_module = old_module,
1709 .next_auto_name = 0,1709 .next_auto_name = 0,
1710 .names = std.StringArrayHashMap(void).init(allocator),1710 .names = std.StringArrayHashMap(void).init(allocator),
1711 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),1711 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
...@@ -2539,7 +2539,7 @@ const EmitZIR = struct {...@@ -2539,7 +2539,7 @@ const EmitZIR = struct {
2539 return self.emitUnnamedDecl(&fntype_inst.base);2539 return self.emitUnnamedDecl(&fntype_inst.base);
2540 },2540 },
2541 .Int => {2541 .Int => {
2542 const info = ty.intInfo(self.old_module.target());2542 const info = ty.intInfo(self.old_module.getTarget());
2543 const signed = try self.emitPrimitive(src, if (info.signed) .@"true" else .@"false");2543 const signed = try self.emitPrimitive(src, if (info.signed) .@"true" else .@"false");
2544 const bits_payload = try self.arena.allocator.create(Value.Payload.Int_u64);2544 const bits_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
2545 bits_payload.* = .{ .int = info.bits };2545 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) {...@@ -78,7 +78,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
78 " -fno-emit-asm (default) do not output .s (assembly code)\n"78 " -fno-emit-asm (default) do not output .s (assembly code)\n"
79 " -femit-llvm-ir produce a .ll file with LLVM IR\n"79 " -femit-llvm-ir produce a .ll file with LLVM IR\n"
80 " -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n"80 " -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"
82 " -fno-emit-h (default) do not generate a C header file (.h)\n"82 " -fno-emit-h (default) do not generate a C header file (.h)\n"
83 " --libc [file] Provide a file which specifies libc paths\n"83 " --libc [file] Provide a file which specifies libc paths\n"
84 " --name [name] override output name\n"84 " --name [name] override output name\n"