authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-12 00:51:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-12 00:51:06-07:00
log03a23418ff13e6ff64cdeed3ef4b54f99c533d88
tree90b53580d9f1fe74e8598f10dc86dfc490ee230e
parent8374be1a1c6cba12ec01d7a6301a8da0a00907f4

stage2: linking with LLD and building glibc static CRT files

* implement --debug-cc and --debug-link * implement C source files having extra flags - TODO a way to pass them on the CLI * introduce the Directory abstraction which contains both an open file descriptor and a file path name. The former is preferred but the latter is needed when communicating paths over a command line (e.g. to Clang or LLD). * use the cache hash to choose an artifact directory - TODO: use separate cache hash instances for the zig module and each C object * Module: introduce the crt_files table for keeping track of built libc artifacts for linking. * Add the ability to build 4/6 of the glibc static CRT lib files. * The zig-cache directory is now passed as a parameter to Module. * Implement the CLI logic of -femit-bin and -femit-h - TODO: respect -fno-emit-bin - TODO: the emit .h feature * Add the -fvalgrind, -fstack-check, and --single-threaded CLI options. * Implement the logic for auto detecting whether to enable PIC, sanitize-C, stack-check, valgrind, and single-threaded. * Properly add PIC args (or not) to clang argv. * Implement renaming clang-compiled object files into their proper place within the cache artifact directory. - TODO: std lib needs a proper higher level abstraction for std.os.renameat. * Package is cleaned up to use the "Unmanaged" StringHashMap and use the new Directory abstraction. * Clean up zig lib directory detection to make proper use of directory handles. * Linker code invokes LLD. - TODO properly deal with the stdout and stderr that we get from it and expose diagnostics from the Module API that match the expected error message format. * Delete the bitrotted LLVM C ABI bindings. We'll resurrect just the functions we need as we introduce dependencies on them. So far it only has ZigLLDLink in it. * Remove dead timer code. * `zig env` now prints the path to the zig executable as well.

16 files changed, 1006 insertions(+), 573 deletions(-)

src-self-hosted/Module.zig+251-115
...@@ -25,6 +25,8 @@ const astgen = @import("astgen.zig");...@@ -25,6 +25,8 @@ const astgen = @import("astgen.zig");
25const zir_sema = @import("zir_sema.zig");25const zir_sema = @import("zir_sema.zig");
26const build_options = @import("build_options");26const build_options = @import("build_options");
27const LibCInstallation = @import("libc_installation.zig").LibCInstallation;27const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
28const glibc = @import("glibc.zig");
29const fatal = @import("main.zig").fatal;
2830
29/// General-purpose allocator. Used for both temporary and long-term storage.31/// General-purpose allocator. Used for both temporary and long-term storage.
30gpa: *Allocator,32gpa: *Allocator,
...@@ -91,17 +93,20 @@ sanitize_c: bool,...@@ -91,17 +93,20 @@ sanitize_c: bool,
91/// Otherwise we attempt to parse the error messages and expose them via the Module API.93/// Otherwise we attempt to parse the error messages and expose them via the Module API.
92/// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`.94/// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`.
93clang_passthrough_mode: bool,95clang_passthrough_mode: bool,
96/// Whether to print clang argvs to stdout.
97debug_cc: bool,
9498
95/// Error tags and their values, tag names are duped with mod.gpa.99/// Error tags and their values, tag names are duped with mod.gpa.
96global_error_set: std.StringHashMapUnmanaged(u16) = .{},100global_error_set: std.StringHashMapUnmanaged(u16) = .{},
97101
98c_source_files: []const []const u8,102c_source_files: []const CSourceFile,
99clang_argv: []const []const u8,103clang_argv: []const []const u8,
100cache: std.cache_hash.CacheHash,104cache: std.cache_hash.CacheHash,
101/// Path to own executable for invoking `zig clang`.105/// Path to own executable for invoking `zig clang`.
102self_exe_path: ?[]const u8,106self_exe_path: ?[]const u8,
103zig_lib_dir: []const u8,107zig_lib_directory: Directory,
104zig_cache_dir_path: []const u8,108zig_cache_directory: Directory,
109zig_cache_artifact_directory: Directory,
105libc_include_dir_list: []const []const u8,110libc_include_dir_list: []const []const u8,
106rand: *std.rand.Random,111rand: *std.rand.Random,
107112
...@@ -118,8 +123,19 @@ libunwind_static_lib: ?[]const u8 = null,...@@ -118,8 +123,19 @@ libunwind_static_lib: ?[]const u8 = null,
118/// and resolved before calling linker.flush().123/// and resolved before calling linker.flush().
119libc_static_lib: ?[]const u8 = null,124libc_static_lib: ?[]const u8 = null,
120125
126/// For example `Scrt1.o` and `libc.so.6`. These are populated after building libc from source,
127/// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
128/// The key is the basename, and the value is the absolute path to the completed build artifact.
129crt_files: std.StringHashMapUnmanaged([]const u8) = .{},
130
121pub const InnerError = error{ OutOfMemory, AnalysisFail };131pub const InnerError = error{ OutOfMemory, AnalysisFail };
122132
133/// For passing to a C compiler.
134pub const CSourceFile = struct {
135 src_path: []const u8,
136 extra_flags: []const []const u8 = &[0][]const u8{},
137};
138
123const WorkItem = union(enum) {139const WorkItem = union(enum) {
124 /// Write the machine code for a Decl to the output file.140 /// Write the machine code for a Decl to the output file.
125 codegen_decl: *Decl,141 codegen_decl: *Decl,
...@@ -133,6 +149,11 @@ const WorkItem = union(enum) {...@@ -133,6 +149,11 @@ const WorkItem = union(enum) {
133 /// Invoke the Clang compiler to create an object file, which gets linked149 /// Invoke the Clang compiler to create an object file, which gets linked
134 /// with the Module.150 /// with the Module.
135 c_object: *CObject,151 c_object: *CObject,
152
153 /// one of the glibc static objects
154 glibc_crt_file: glibc.CRTFile,
155 /// one of the glibc shared objects
156 glibc_so: *const glibc.Lib,
136};157};
137158
138pub const Export = struct {159pub const Export = struct {
...@@ -701,7 +722,7 @@ pub const Scope = struct {...@@ -701,7 +722,7 @@ pub const Scope = struct {
701 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {722 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {
702 switch (self.source) {723 switch (self.source) {
703 .unloaded => {724 .unloaded => {
704 const source = try module.root_pkg.?.root_src_dir.readFileAllocOptions(725 const source = try module.root_pkg.?.root_src_directory.handle.readFileAllocOptions(
705 module.gpa,726 module.gpa,
706 self.sub_file_path,727 self.sub_file_path,
707 std.math.maxInt(u32),728 std.math.maxInt(u32),
...@@ -805,7 +826,7 @@ pub const Scope = struct {...@@ -805,7 +826,7 @@ pub const Scope = struct {
805 pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {826 pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {
806 switch (self.source) {827 switch (self.source) {
807 .unloaded => {828 .unloaded => {
808 const source = try module.root_pkg.?.root_src_dir.readFileAllocOptions(829 const source = try module.root_pkg.?.root_src_directory.handle.readFileAllocOptions(
809 module.gpa,830 module.gpa,
810 self.sub_file_path,831 self.sub_file_path,
811 std.math.maxInt(u32),832 std.math.maxInt(u32),
...@@ -937,18 +958,35 @@ pub const AllErrors = struct {...@@ -937,18 +958,35 @@ pub const AllErrors = struct {
937 }958 }
938};959};
939960
961pub const Directory = struct {
962 /// This field is redundant for operations that can act on the open directory handle
963 /// directly, but it is needed when passing the directory to a child process.
964 /// `null` means cwd.
965 path: ?[]const u8,
966 handle: std.fs.Dir,
967};
968
969pub const EmitLoc = struct {
970 /// If this is `null` it means the file will be output to the cache directory.
971 /// When provided, both the open file handle and the path name must outlive the `Module`.
972 directory: ?Module.Directory,
973 /// This may not have sub-directories in it.
974 basename: []const u8,
975};
976
940pub const InitOptions = struct {977pub const InitOptions = struct {
941 zig_lib_dir: []const u8,978 zig_lib_directory: Directory,
979 zig_cache_directory: Directory,
942 target: Target,980 target: Target,
943 root_name: []const u8,981 root_name: []const u8,
944 root_pkg: ?*Package,982 root_pkg: ?*Package,
945 output_mode: std.builtin.OutputMode,983 output_mode: std.builtin.OutputMode,
946 rand: *std.rand.Random,984 rand: *std.rand.Random,
947 dynamic_linker: ?[]const u8 = null,985 dynamic_linker: ?[]const u8 = null,
948 bin_file_dir_path: ?[]const u8 = null,986 /// `null` means to not emit a binary file.
949 bin_file_dir: ?std.fs.Dir = null,987 emit_bin: ?EmitLoc,
950 bin_file_path: []const u8,988 /// `null` means to not emit a C header file.
951 emit_h: ?[]const u8 = null,989 emit_h: ?EmitLoc = null,
952 link_mode: ?std.builtin.LinkMode = null,990 link_mode: ?std.builtin.LinkMode = null,
953 object_format: ?std.builtin.ObjectFormat = null,991 object_format: ?std.builtin.ObjectFormat = null,
954 optimize_mode: std.builtin.Mode = .Debug,992 optimize_mode: std.builtin.Mode = .Debug,
...@@ -957,7 +995,7 @@ pub const InitOptions = struct {...@@ -957,7 +995,7 @@ pub const InitOptions = struct {
957 lld_argv: []const []const u8 = &[0][]const u8{},995 lld_argv: []const []const u8 = &[0][]const u8{},
958 lib_dirs: []const []const u8 = &[0][]const u8{},996 lib_dirs: []const []const u8 = &[0][]const u8{},
959 rpath_list: []const []const u8 = &[0][]const u8{},997 rpath_list: []const []const u8 = &[0][]const u8{},
960 c_source_files: []const []const u8 = &[0][]const u8{},998 c_source_files: []const CSourceFile = &[0]CSourceFile{},
961 link_objects: []const []const u8 = &[0][]const u8{},999 link_objects: []const []const u8 = &[0][]const u8{},
962 framework_dirs: []const []const u8 = &[0][]const u8{},1000 framework_dirs: []const []const u8 = &[0][]const u8{},
963 frameworks: []const []const u8 = &[0][]const u8{},1001 frameworks: []const []const u8 = &[0][]const u8{},
...@@ -966,11 +1004,14 @@ pub const InitOptions = struct {...@@ -966,11 +1004,14 @@ pub const InitOptions = struct {
966 link_libcpp: bool = false,1004 link_libcpp: bool = false,
967 want_pic: ?bool = null,1005 want_pic: ?bool = null,
968 want_sanitize_c: ?bool = null,1006 want_sanitize_c: ?bool = null,
1007 want_stack_check: ?bool = null,
1008 want_valgrind: ?bool = null,
969 use_llvm: ?bool = null,1009 use_llvm: ?bool = null,
970 use_lld: ?bool = null,1010 use_lld: ?bool = null,
971 use_clang: ?bool = null,1011 use_clang: ?bool = null,
972 rdynamic: bool = false,1012 rdynamic: bool = false,
973 strip: bool = false,1013 strip: bool = false,
1014 single_threaded: bool = false,
974 is_native_os: bool,1015 is_native_os: bool,
975 link_eh_frame_hdr: bool = false,1016 link_eh_frame_hdr: bool = false,
976 linker_script: ?[]const u8 = null,1017 linker_script: ?[]const u8 = null,
...@@ -984,6 +1025,8 @@ pub const InitOptions = struct {...@@ -984,6 +1025,8 @@ pub const InitOptions = struct {
984 linker_z_nodelete: bool = false,1025 linker_z_nodelete: bool = false,
985 linker_z_defs: bool = false,1026 linker_z_defs: bool = false,
986 clang_passthrough_mode: bool = false,1027 clang_passthrough_mode: bool = false,
1028 debug_cc: bool = false,
1029 debug_link: bool = false,
987 stack_size_override: ?u64 = null,1030 stack_size_override: ?u64 = null,
988 self_exe_path: ?[]const u8 = null,1031 self_exe_path: ?[]const u8 = null,
989 version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 },1032 version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 },
...@@ -1057,17 +1100,126 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {...@@ -1057,17 +1100,126 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
10571100
1058 const libc_dirs = try detectLibCIncludeDirs(1101 const libc_dirs = try detectLibCIncludeDirs(
1059 arena,1102 arena,
1060 options.zig_lib_dir,1103 options.zig_lib_directory.path.?,
1061 options.target,1104 options.target,
1062 options.is_native_os,1105 options.is_native_os,
1063 options.link_libc,1106 options.link_libc,
1064 options.libc_installation,1107 options.libc_installation,
1065 );1108 );
10661109
1110 const must_pic: bool = b: {
1111 if (target_util.requiresPIC(options.target, options.link_libc))
1112 break :b true;
1113 break :b link_mode == .Dynamic;
1114 };
1115 const pic = options.want_pic orelse must_pic;
1116
1117 if (options.emit_h != null) fatal("-femit-h not supported yet", .{}); // TODO
1118
1119 const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO
1120
1121 // Make a decision on whether to use Clang for translate-c and compiling C files.
1122 const use_clang = if (options.use_clang) |explicit| explicit else blk: {
1123 if (build_options.have_llvm) {
1124 // Can't use it if we don't have it!
1125 break :blk false;
1126 }
1127 // It's not planned to do our own translate-c or C compilation.
1128 break :blk true;
1129 };
1130
1131 const is_safe_mode = switch (options.optimize_mode) {
1132 .Debug, .ReleaseSafe => true,
1133 .ReleaseFast, .ReleaseSmall => false,
1134 };
1135
1136 const sanitize_c = options.want_sanitize_c orelse is_safe_mode;
1137
1138 const stack_check: bool = b: {
1139 if (!target_util.supportsStackProbing(options.target))
1140 break :b false;
1141 break :b options.want_stack_check orelse is_safe_mode;
1142 };
1143
1144 const valgrind: bool = b: {
1145 if (!target_util.hasValgrindSupport(options.target))
1146 break :b false;
1147 break :b options.want_valgrind orelse (options.optimize_mode == .Debug);
1148 };
1149
1150 const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);
1151
1152 // We put everything into the cache hash that *cannot be modified during an incremental update*.
1153 // For example, one cannot change the target between updates, but one can change source files,
1154 // so the target goes into the cache hash, but source files do not. This is so that we can
1155 // find the same binary and incrementally update it even if there are modified source files.
1156 // We do this even if outputting to the current directory because (1) this cache_hash instance
1157 // will be the "parent" of other cache_hash instances such as for C objects, (2) we need
1158 // a place for intermediate build artifacts, such as a .o file to be linked with LLD, and (3)
1159 // we need somewhere to store serialization of incremental compilation metadata.
1160 var cache = try std.cache_hash.CacheHash.init(gpa, options.zig_cache_directory.handle, "h");
1161 errdefer cache.release();
1162
1163 // Now we will prepare hash state initializations to avoid redundantly computing hashes.
1164 // First we add common things between things that apply to zig source and all c source files.
1165 cache.addBytes(build_options.version);
1166 cache.add(options.optimize_mode);
1167 cache.add(options.target.cpu.arch);
1168 cache.addBytes(options.target.cpu.model.name);
1169 cache.add(options.target.cpu.features.ints);
1170 cache.add(options.target.os.tag);
1171 switch (options.target.os.tag) {
1172 .linux => {
1173 cache.add(options.target.os.version_range.linux.range.min);
1174 cache.add(options.target.os.version_range.linux.range.max);
1175 cache.add(options.target.os.version_range.linux.glibc);
1176 },
1177 .windows => {
1178 cache.add(options.target.os.version_range.windows.min);
1179 cache.add(options.target.os.version_range.windows.max);
1180 },
1181 .freebsd,
1182 .macosx,
1183 .ios,
1184 .tvos,
1185 .watchos,
1186 .netbsd,
1187 .openbsd,
1188 .dragonfly,
1189 => {
1190 cache.add(options.target.os.version_range.semver.min);
1191 cache.add(options.target.os.version_range.semver.max);
1192 },
1193 else => {},
1194 }
1195 cache.add(options.target.abi);
1196 cache.add(ofmt);
1197 cache.add(pic);
1198 cache.add(stack_check);
1199 cache.add(sanitize_c);
1200 cache.add(valgrind);
1201 cache.add(link_mode);
1202 cache.add(options.strip);
1203 cache.add(single_threaded);
1204 // TODO audit this and make sure everything is in it
1205
1206 // We don't care whether we find something there, just show us the digest.
1207 const digest = (try cache.hit()) orelse cache.final();
1208
1209 const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
1210 var artifact_dir = try options.zig_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
1211 errdefer artifact_dir.close();
1212 const zig_cache_artifact_directory: Directory = .{
1213 .handle = artifact_dir,
1214 .path = if (options.zig_cache_directory.path) |p|
1215 try std.fs.path.join(arena, &[_][]const u8{ p, artifact_sub_dir })
1216 else
1217 artifact_sub_dir,
1218 };
1219
1067 const bin_file = try link.File.openPath(gpa, .{1220 const bin_file = try link.File.openPath(gpa, .{
1068 .dir = options.bin_file_dir orelse std.fs.cwd(),1221 .directory = emit_bin.directory orelse zig_cache_artifact_directory,
1069 .dir_path = options.bin_file_dir_path,1222 .sub_path = emit_bin.basename,
1070 .sub_path = options.bin_file_path,
1071 .root_name = root_name,1223 .root_name = root_name,
1072 .root_pkg = options.root_pkg,1224 .root_pkg = options.root_pkg,
1073 .target = options.target,1225 .target = options.target,
...@@ -1103,6 +1255,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {...@@ -1103,6 +1255,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
1103 .override_soname = options.override_soname,1255 .override_soname = options.override_soname,
1104 .version = options.version,1256 .version = options.version,
1105 .libc_installation = libc_dirs.libc_installation,1257 .libc_installation = libc_dirs.libc_installation,
1258 .pic = pic,
1259 .valgrind = valgrind,
1260 .stack_check = stack_check,
1261 .single_threaded = single_threaded,
1262 .debug_link = options.debug_link,
1106 });1263 });
1107 errdefer bin_file.destroy();1264 errdefer bin_file.destroy();
11081265
...@@ -1142,83 +1299,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {...@@ -1142,83 +1299,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
1142 }1299 }
1143 };1300 };
11441301
1145 // We put everything into the cache hash except for the root source file, because we want to
1146 // find the same binary and incrementally update it even if the file contents changed.
1147 // TODO Look into storing this information in memory rather than on disk and solving
1148 // serialization/deserialization of *all* incremental compilation state in a more generic way.
1149 const cache_parent_dir = if (options.root_pkg) |root_pkg| root_pkg.root_src_dir else std.fs.cwd();
1150 var cache_dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
1151 defer cache_dir.close();
1152
1153 try cache_dir.makePath("tmp");
1154 try cache_dir.makePath("o");
1155 // We need this string because of sending paths to clang as a child process.
1156 const zig_cache_dir_path = if (options.root_pkg) |root_pkg|
1157 try std.fmt.allocPrint(arena, "{}" ++ std.fs.path.sep_str ++ "zig-cache", .{root_pkg.root_src_dir_path})
1158 else
1159 "zig-cache";
1160
1161 var cache = try std.cache_hash.CacheHash.init(gpa, cache_dir, "h");
1162 errdefer cache.release();
1163
1164 // Now we will prepare hash state initializations to avoid redundantly computing hashes.
1165 // First we add common things between things that apply to zig source and all c source files.
1166 cache.addBytes(build_options.version);
1167 cache.add(options.optimize_mode);
1168 cache.add(options.target.cpu.arch);
1169 cache.addBytes(options.target.cpu.model.name);
1170 cache.add(options.target.cpu.features.ints);
1171 cache.add(options.target.os.tag);
1172 switch (options.target.os.tag) {
1173 .linux => {
1174 cache.add(options.target.os.version_range.linux.range.min);
1175 cache.add(options.target.os.version_range.linux.range.max);
1176 cache.add(options.target.os.version_range.linux.glibc);
1177 },
1178 .windows => {
1179 cache.add(options.target.os.version_range.windows.min);
1180 cache.add(options.target.os.version_range.windows.max);
1181 },
1182 .freebsd,
1183 .macosx,
1184 .ios,
1185 .tvos,
1186 .watchos,
1187 .netbsd,
1188 .openbsd,
1189 .dragonfly,
1190 => {
1191 cache.add(options.target.os.version_range.semver.min);
1192 cache.add(options.target.os.version_range.semver.max);
1193 },
1194 else => {},
1195 }
1196 cache.add(options.target.abi);
1197 cache.add(ofmt);
1198 // TODO PIC (see detect_pic from codegen.cpp)
1199 cache.add(bin_file.options.link_mode);
1200 cache.add(options.strip);
1201
1202 // Make a decision on whether to use Clang for translate-c and compiling C files.
1203 const use_clang = if (options.use_clang) |explicit| explicit else blk: {
1204 if (build_options.have_llvm) {
1205 // Can't use it if we don't have it!
1206 break :blk false;
1207 }
1208 // It's not planned to do our own translate-c or C compilation.
1209 break :blk true;
1210 };
1211
1212 const sanitize_c: bool = options.want_sanitize_c orelse switch (options.optimize_mode) {
1213 .Debug, .ReleaseSafe => true,
1214 .ReleaseSmall, .ReleaseFast => false,
1215 };
1216
1217 mod.* = .{1302 mod.* = .{
1218 .gpa = gpa,1303 .gpa = gpa,
1219 .arena_state = arena_allocator.state,1304 .arena_state = arena_allocator.state,
1220 .zig_lib_dir = options.zig_lib_dir,1305 .zig_lib_directory = options.zig_lib_directory,
1221 .zig_cache_dir_path = zig_cache_dir_path,1306 .zig_cache_directory = options.zig_cache_directory,
1307 .zig_cache_artifact_directory = zig_cache_artifact_directory,
1222 .root_pkg = options.root_pkg,1308 .root_pkg = options.root_pkg,
1223 .root_scope = root_scope,1309 .root_scope = root_scope,
1224 .bin_file = bin_file,1310 .bin_file = bin_file,
...@@ -1233,6 +1319,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {...@@ -1233,6 +1319,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
1233 .sanitize_c = sanitize_c,1319 .sanitize_c = sanitize_c,
1234 .rand = options.rand,1320 .rand = options.rand,
1235 .clang_passthrough_mode = options.clang_passthrough_mode,1321 .clang_passthrough_mode = options.clang_passthrough_mode,
1322 .debug_cc = options.debug_cc,
1236 };1323 };
1237 break :mod mod;1324 break :mod mod;
1238 };1325 };
...@@ -1245,22 +1332,21 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {...@@ -1245,22 +1332,21 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
1245 errdefer local_arena.deinit();1332 errdefer local_arena.deinit();
12461333
1247 const c_object = try local_arena.allocator.create(CObject);1334 const c_object = try local_arena.allocator.create(CObject);
1248 const src_path = try local_arena.allocator.dupe(u8, c_source_file);
12491335
1250 c_object.* = .{1336 c_object.* = .{
1251 .status = .{ .new = {} },1337 .status = .{ .new = {} },
1252 .src_path = src_path,1338 // TODO why are we duplicating this memory? do we need to?
1253 .extra_flags = &[0][]const u8{},1339 // look into refactoring to turn these 2 fields simply into a CSourceFile
1340 .src_path = try local_arena.allocator.dupe(u8, c_source_file.src_path),
1341 .extra_flags = try local_arena.allocator.dupe([]const u8, c_source_file.extra_flags),
1254 .arena = local_arena.state,1342 .arena = local_arena.state,
1255 };1343 };
1256 mod.c_object_table.putAssumeCapacityNoClobber(c_object, {});1344 mod.c_object_table.putAssumeCapacityNoClobber(c_object, {});
1257 }1345 }
12581346
1259 // If we need to build glibc for the target, add work items for it.1347 // If we need to build glibc for the target, add work items for it.
1260 if (mod.bin_file.options.link_libc and1348 // We go through the work queue so that building can be done in parallel.
1261 mod.bin_file.options.libc_installation == null and1349 if (mod.wantBuildGLibCFromSource()) {
1262 mod.bin_file.options.target.isGnuLibC())
1263 {
1264 try mod.addBuildingGLibCWorkItems();1350 try mod.addBuildingGLibCWorkItems();
1265 }1351 }
12661352
...@@ -1273,6 +1359,15 @@ pub fn destroy(self: *Module) void {...@@ -1273,6 +1359,15 @@ pub fn destroy(self: *Module) void {
1273 self.deletion_set.deinit(gpa);1359 self.deletion_set.deinit(gpa);
1274 self.work_queue.deinit();1360 self.work_queue.deinit();
12751361
1362 {
1363 var it = self.crt_files.iterator();
1364 while (it.next()) |entry| {
1365 gpa.free(entry.key);
1366 gpa.free(entry.value);
1367 }
1368 self.crt_files.deinit(gpa);
1369 }
1370
1276 for (self.decl_table.items()) |entry| {1371 for (self.decl_table.items()) |entry| {
1277 entry.value.destroy(gpa);1372 entry.value.destroy(gpa);
1278 }1373 }
...@@ -1322,6 +1417,8 @@ pub fn destroy(self: *Module) void {...@@ -1322,6 +1417,8 @@ pub fn destroy(self: *Module) void {
1322 gpa.free(entry.key);1417 gpa.free(entry.key);
1323 }1418 }
1324 self.global_error_set.deinit(gpa);1419 self.global_error_set.deinit(gpa);
1420
1421 self.zig_cache_artifact_directory.handle.close();
1325 self.cache.release();1422 self.cache.release();
13261423
1327 // This destroys `self`.1424 // This destroys `self`.
...@@ -1458,7 +1555,7 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -1458,7 +1555,7 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
1458 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {1555 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
1459 const global_err_src_path = blk: {1556 const global_err_src_path = blk: {
1460 if (self.root_pkg) |root_pkg| break :blk root_pkg.root_src_path;1557 if (self.root_pkg) |root_pkg| break :blk root_pkg.root_src_path;
1461 if (self.c_source_files.len != 0) break :blk self.c_source_files[0];1558 if (self.c_source_files.len != 0) break :blk self.c_source_files[0].src_path;
1462 if (self.bin_file.options.objects.len != 0) break :blk self.bin_file.options.objects[0];1559 if (self.bin_file.options.objects.len != 0) break :blk self.bin_file.options.objects[0];
1463 break :blk "(no file)";1560 break :blk "(no file)";
1464 };1561 };
...@@ -1581,6 +1678,17 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -1581,6 +1678,17 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
1581 },1678 },
1582 };1679 };
1583 },1680 },
1681 .glibc_crt_file => |crt_file| {
1682 glibc.buildCRTFile(self, crt_file) catch |err| {
1683 // This is a problem with the Zig installation. It's mostly OK to crash here,
1684 // but TODO because it would be even better if we could recover gracefully
1685 // from temporary problems such as out-of-disk-space.
1686 fatal("unable to build glibc CRT file: {}", .{@errorName(err)});
1687 };
1688 },
1689 .glibc_so => |glibc_lib| {
1690 fatal("TODO build glibc shared object '{}.so.{}'", .{ glibc_lib.name, glibc_lib.sover });
1691 },
1584 };1692 };
1585}1693}
15861694
...@@ -1588,6 +1696,8 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {...@@ -1588,6 +1696,8 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
1588 const tracy = trace(@src());1696 const tracy = trace(@src());
1589 defer tracy.end();1697 defer tracy.end();
15901698
1699 // TODO this C source file needs its own cache hash instance
1700
1591 if (!build_options.have_llvm) {1701 if (!build_options.have_llvm) {
1592 return mod.failCObj(c_object, "clang not available: compiler not built with LLVM extensions enabled", .{});1702 return mod.failCObj(c_object, "clang not available: compiler not built with LLVM extensions enabled", .{});
1593 }1703 }
...@@ -1616,6 +1726,9 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {...@@ -1616,6 +1726,9 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
1616 // We can't know the digest until we do the C compiler invocation, so we need a temporary filename.1726 // We can't know the digest until we do the C compiler invocation, so we need a temporary filename.
1617 const out_obj_path = try mod.tmpFilePath(arena, o_basename);1727 const out_obj_path = try mod.tmpFilePath(arena, o_basename);
16181728
1729 var zig_cache_tmp_dir = try mod.zig_cache_directory.handle.makeOpenPath("tmp", .{});
1730 defer zig_cache_tmp_dir.close();
1731
1619 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang", "-c" });1732 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang", "-c" });
16201733
1621 const ext = classifyFileExt(c_object.src_path);1734 const ext = classifyFileExt(c_object.src_path);
...@@ -1628,9 +1741,12 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {...@@ -1628,9 +1741,12 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
1628 try argv.append(c_object.src_path);1741 try argv.append(c_object.src_path);
1629 try argv.appendSlice(c_object.extra_flags);1742 try argv.appendSlice(c_object.extra_flags);
16301743
1631 //for (argv.items) |arg| {1744 if (mod.debug_cc) {
1632 // std.debug.print("{} ", .{arg});1745 for (argv.items[0 .. argv.items.len - 1]) |arg| {
1633 //}1746 std.debug.print("{} ", .{arg});
1747 }
1748 std.debug.print("{}\n", .{argv.items[argv.items.len - 1]});
1749 }
16341750
1635 const child = try std.ChildProcess.init(argv.items, arena);1751 const child = try std.ChildProcess.init(argv.items, arena);
1636 defer child.deinit();1752 defer child.deinit();
...@@ -1689,11 +1805,13 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {...@@ -1689,11 +1805,13 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
16891805
1690 // TODO handle .d files1806 // TODO handle .d files
16911807
1692 // TODO rename into place1808 // TODO Add renameat capabilities to the std lib in a higher layer than the posix layer.
1693 std.debug.print("TODO rename {} into cache dir\n", .{out_obj_path});1809 const tmp_basename = std.fs.path.basename(out_obj_path);
1810 try std.os.renameat(zig_cache_tmp_dir.fd, tmp_basename, mod.zig_cache_artifact_directory.handle.fd, o_basename);
16941811
1695 // TODO use the cache file name instead of tmp file name1812 const success_file_path = try std.fs.path.join(mod.gpa, &[_][]const u8{
1696 const success_file_path = try mod.gpa.dupe(u8, out_obj_path);1813 mod.zig_cache_artifact_directory.path.?, o_basename,
1814 });
1697 c_object.status = .{ .success = success_file_path };1815 c_object.status = .{ .success = success_file_path };
1698}1816}
16991817
...@@ -1702,7 +1820,7 @@ fn tmpFilePath(mod: *Module, arena: *Allocator, suffix: []const u8) error{OutOfM...@@ -1702,7 +1820,7 @@ fn tmpFilePath(mod: *Module, arena: *Allocator, suffix: []const u8) error{OutOfM
1702 return std.fmt.allocPrint(1820 return std.fmt.allocPrint(
1703 arena,1821 arena,
1704 "{}" ++ s ++ "tmp" ++ s ++ "{x}-{}",1822 "{}" ++ s ++ "tmp" ++ s ++ "{x}-{}",
1705 .{ mod.zig_cache_dir_path, mod.rand.int(u64), suffix },1823 .{ mod.zig_cache_directory.path.?, mod.rand.int(u64), suffix },
1706 );1824 );
1707}1825}
17081826
...@@ -1749,10 +1867,10 @@ fn addCCArgs(...@@ -1749,10 +1867,10 @@ fn addCCArgs(
17491867
1750 if (mod.bin_file.options.link_libcpp) {1868 if (mod.bin_file.options.link_libcpp) {
1751 const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{1869 const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{
1752 mod.zig_lib_dir, "libcxx", "include",1870 mod.zig_lib_directory.path.?, "libcxx", "include",
1753 });1871 });
1754 const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{1872 const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{
1755 mod.zig_lib_dir, "libcxxabi", "include",1873 mod.zig_lib_directory.path.?, "libcxxabi", "include",
1756 });1874 });
17571875
1758 try argv.append("-isystem");1876 try argv.append("-isystem");
...@@ -1776,7 +1894,7 @@ fn addCCArgs(...@@ -1776,7 +1894,7 @@ fn addCCArgs(
1776 // According to Rich Felker libc headers are supposed to go before C language headers.1894 // According to Rich Felker libc headers are supposed to go before C language headers.
1777 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics1895 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
1778 // and other compiler specific items.1896 // and other compiler specific items.
1779 const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ mod.zig_lib_dir, "include" });1897 const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, "include" });
1780 try argv.append("-isystem");1898 try argv.append("-isystem");
1781 try argv.append(c_headers_dir);1899 try argv.append(c_headers_dir);
17821900
...@@ -1891,10 +2009,9 @@ fn addCCArgs(...@@ -1891,10 +2009,9 @@ fn addCCArgs(
1891 },2009 },
1892 }2010 }
18932011
1894 // TODO add CLI args for PIC2012 if (target_util.supports_fpic(target) and mod.bin_file.options.pic) {
1895 //if (target_supports_fpic(g->zig_target) and g->have_pic) {2013 try argv.append("-fPIC");
1896 // try argv.append("-fPIC");2014 }
1897 //}
18982015
1899 try argv.appendSlice(mod.clang_argv);2016 try argv.appendSlice(mod.clang_argv);
1900}2017}
...@@ -4497,7 +4614,9 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const...@@ -4497,7 +4614,9 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const
4497}4614}
44984615
4499pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 {4616pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 {
4500 // TODO port support for building crt files from stage14617 if (mod.wantBuildGLibCFromSource()) {
4618 return mod.crt_files.get(basename).?;
4619 }
4501 const lci = mod.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;4620 const lci = mod.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;
4502 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;4621 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
4503 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });4622 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
...@@ -4505,6 +4624,23 @@ pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8)...@@ -4505,6 +4624,23 @@ pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8)
4505}4624}
45064625
4507fn addBuildingGLibCWorkItems(mod: *Module) !void {4626fn addBuildingGLibCWorkItems(mod: *Module) !void {
4508 // crti.o, crtn.o, start.os, abi-note.o, Scrt1.o, libc_nonshared.a4627 const static_file_work_items = [_]WorkItem{
4509 try mod.work_queue.ensureUnusedCapacity(6);4628 .{ .glibc_crt_file = .crti_o },
4629 .{ .glibc_crt_file = .crtn_o },
4630 .{ .glibc_crt_file = .start_os },
4631 .{ .glibc_crt_file = .abi_note_o },
4632 .{ .glibc_crt_file = .scrt1_o },
4633 .{ .glibc_crt_file = .libc_nonshared_a },
4634 };
4635 try mod.work_queue.ensureUnusedCapacity(static_file_work_items.len + glibc.libs.len);
4636 mod.work_queue.writeAssumeCapacity(&static_file_work_items);
4637 for (glibc.libs) |*glibc_so| {
4638 mod.work_queue.writeItemAssumeCapacity(.{ .glibc_so = glibc_so });
4639 }
4640}
4641
4642fn wantBuildGLibCFromSource(mod: *Module) bool {
4643 return mod.bin_file.options.link_libc and
4644 mod.bin_file.options.libc_installation == null and
4645 mod.bin_file.options.target.isGnuLibC();
4510}4646}
src-self-hosted/Package.zig+29-29
...@@ -1,59 +1,59 @@...@@ -1,59 +1,59 @@
1pub const Table = std.StringHashMap(*Package);1pub const Table = std.StringHashMapUnmanaged(*Package);
22
3/// This should be used for file operations.3root_src_directory: Module.Directory,
4root_src_dir: std.fs.Dir,4/// Relative to `root_src_directory`.
5/// This is for metadata purposes, for example putting into debug information.
6root_src_dir_path: []u8,
7/// Relative to `root_src_dir` and `root_src_dir_path`.
8root_src_path: []u8,5root_src_path: []u8,
9table: Table,6table: Table,
107
11/// No references to `root_src_dir` and `root_src_path` are kept.8/// No references to `root_src_dir` and `root_src_path` are kept.
12pub fn create(9pub fn create(
13 allocator: *mem.Allocator,10 gpa: *Allocator,
14 base_dir: std.fs.Dir,11 base_dir: std.fs.Dir,
15 /// Relative to `base_dir`.12 /// Relative to `base_dir`.
16 root_src_dir: []const u8,13 root_src_dir: []const u8,
17 /// Relative to `root_src_dir`.14 /// Relative to `root_src_dir`.
18 root_src_path: []const u8,15 root_src_path: []const u8,
19) !*Package {16) !*Package {
20 const ptr = try allocator.create(Package);17 const ptr = try gpa.create(Package);
21 errdefer allocator.destroy(ptr);18 errdefer gpa.destroy(ptr);
22 const root_src_path_dupe = try mem.dupe(allocator, u8, root_src_path);19 const root_src_path_dupe = try mem.dupe(gpa, u8, root_src_path);
23 errdefer allocator.free(root_src_path_dupe);20 errdefer gpa.free(root_src_path_dupe);
24 const root_src_dir_path = try mem.dupe(allocator, u8, root_src_dir);21 const root_src_dir_path = try mem.dupe(gpa, u8, root_src_dir);
25 errdefer allocator.free(root_src_dir_path);22 errdefer gpa.free(root_src_dir_path);
26 ptr.* = .{23 ptr.* = .{
27 .root_src_dir = try base_dir.openDir(root_src_dir, .{}),24 .root_src_directory = .{
28 .root_src_dir_path = root_src_dir_path,25 .path = root_src_dir_path,
26 .handle = try base_dir.openDir(root_src_dir, .{}),
27 },
29 .root_src_path = root_src_path_dupe,28 .root_src_path = root_src_path_dupe,
30 .table = Table.init(allocator),29 .table = .{},
31 };30 };
32 return ptr;31 return ptr;
33}32}
3433
35pub fn destroy(self: *Package) void {34pub fn destroy(pkg: *Package, gpa: *Allocator) void {
36 const allocator = self.table.allocator;35 pkg.root_src_directory.handle.close();
37 self.root_src_dir.close();36 gpa.free(pkg.root_src_path);
38 allocator.free(self.root_src_path);37 if (pkg.root_src_directory.path) |p| gpa.free(p);
39 allocator.free(self.root_src_dir_path);
40 {38 {
41 var it = self.table.iterator();39 var it = pkg.table.iterator();
42 while (it.next()) |kv| {40 while (it.next()) |kv| {
43 allocator.free(kv.key);41 gpa.free(kv.key);
44 }42 }
45 }43 }
46 self.table.deinit();44 pkg.table.deinit(gpa);
47 allocator.destroy(self);45 gpa.destroy(pkg);
48}46}
4947
50pub fn add(self: *Package, name: []const u8, package: *Package) !void {48pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void {
51 try self.table.ensureCapacity(self.table.items().len + 1);49 try pkg.table.ensureCapacity(gpa, pkg.table.items().len + 1);
52 const name_dupe = try mem.dupe(self.table.allocator, u8, name);50 const name_dupe = try mem.dupe(gpa, u8, name);
53 self.table.putAssumeCapacityNoClobber(name_dupe, package);51 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
54}52}
5553
56const std = @import("std");54const std = @import("std");
57const mem = std.mem;55const mem = std.mem;
56const Allocator = std.mem.Allocator;
58const assert = std.debug.assert;57const assert = std.debug.assert;
59const Package = @This();58const Package = @This();
59const Module = @import("Module.zig");
src-self-hosted/glibc.zig+395-1
...@@ -2,6 +2,9 @@ const std = @import("std");...@@ -2,6 +2,9 @@ const std = @import("std");
2const Allocator = std.mem.Allocator;2const Allocator = std.mem.Allocator;
3const target_util = @import("target.zig");3const target_util = @import("target.zig");
4const mem = std.mem;4const mem = std.mem;
5const Module = @import("Module.zig");
6const path = std.fs.path;
7const build_options = @import("build_options");
58
6pub const Lib = struct {9pub const Lib = struct {
7 name: []const u8,10 name: []const u8,
...@@ -60,7 +63,7 @@ pub fn loadMetaData(gpa: *Allocator, zig_lib_dir: std.fs.Dir) LoadMetaDataError!...@@ -60,7 +63,7 @@ pub fn loadMetaData(gpa: *Allocator, zig_lib_dir: std.fs.Dir) LoadMetaDataError!
60 var version_table = std.AutoHashMapUnmanaged(target_util.ArchOsAbi, [*]VerList){};63 var version_table = std.AutoHashMapUnmanaged(target_util.ArchOsAbi, [*]VerList){};
61 errdefer version_table.deinit(gpa);64 errdefer version_table.deinit(gpa);
6265
63 var glibc_dir = zig_lib_dir.openDir("libc" ++ std.fs.path.sep_str ++ "glibc", .{}) catch |err| {66 var glibc_dir = zig_lib_dir.openDir("libc" ++ path.sep_str ++ "glibc", .{}) catch |err| {
64 std.log.err("unable to open glibc dir: {}", .{@errorName(err)});67 std.log.err("unable to open glibc dir: {}", .{@errorName(err)});
65 return error.ZigInstallationCorrupt;68 return error.ZigInstallationCorrupt;
66 };69 };
...@@ -229,3 +232,394 @@ fn findLib(name: []const u8) ?*const Lib {...@@ -229,3 +232,394 @@ fn findLib(name: []const u8) ?*const Lib {
229 }232 }
230 return null;233 return null;
231}234}
235
236pub const CRTFile = enum {
237 crti_o,
238 crtn_o,
239 start_os,
240 abi_note_o,
241 scrt1_o,
242 libc_nonshared_a,
243};
244
245pub fn buildCRTFile(mod: *Module, crt_file: CRTFile) !void {
246 if (!build_options.have_llvm) {
247 return error.ZigCompilerNotBuiltWithLLVMExtensions;
248 }
249 const gpa = mod.gpa;
250 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
251 errdefer arena_allocator.deinit();
252 const arena = &arena_allocator.allocator;
253
254 switch (crt_file) {
255 .crti_o => {
256 var args = std.ArrayList([]const u8).init(arena);
257 try add_include_dirs(mod, arena, &args);
258 try args.appendSlice(&[_][]const u8{
259 "-D_LIBC_REENTRANT",
260 "-include",
261 try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-modules.h"),
262 "-DMODULE_NAME=libc",
263 "-Wno-nonportable-include-path",
264 "-include",
265 try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-symbols.h"),
266 "-DTOP_NAMESPACE=glibc",
267 "-DASSEMBLER",
268 "-g",
269 "-Wa,--noexecstack",
270 });
271 const c_source_file: Module.CSourceFile = .{
272 .src_path = try start_asm_path(mod, arena, "crti.S"),
273 .extra_flags = args.items,
274 };
275 return build_libc_object(mod, "crti.o", c_source_file);
276 },
277 .crtn_o => {
278 var args = std.ArrayList([]const u8).init(arena);
279 try add_include_dirs(mod, arena, &args);
280 try args.appendSlice(&[_][]const u8{
281 "-D_LIBC_REENTRANT",
282 "-DMODULE_NAME=libc",
283 "-DTOP_NAMESPACE=glibc",
284 "-DASSEMBLER",
285 "-g",
286 "-Wa,--noexecstack",
287 });
288 const c_source_file: Module.CSourceFile = .{
289 .src_path = try start_asm_path(mod, arena, "crtn.S"),
290 .extra_flags = args.items,
291 };
292 return build_libc_object(mod, "crtn.o", c_source_file);
293 },
294 .start_os => {
295 var args = std.ArrayList([]const u8).init(arena);
296 try add_include_dirs(mod, arena, &args);
297 try args.appendSlice(&[_][]const u8{
298 "-D_LIBC_REENTRANT",
299 "-include",
300 try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-modules.h"),
301 "-DMODULE_NAME=libc",
302 "-Wno-nonportable-include-path",
303 "-include",
304 try lib_path(mod, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-symbols.h"),
305 "-DPIC",
306 "-DSHARED",
307 "-DTOP_NAMESPACE=glibc",
308 "-DASSEMBLER",
309 "-g",
310 "-Wa,--noexecstack",
311 });
312 const c_source_file: Module.CSourceFile = .{
313 .src_path = try start_asm_path(mod, arena, "start.S"),
314 .extra_flags = args.items,
315 };
316 return build_libc_object(mod, "start.os", c_source_file);
317 },
318 .abi_note_o => {
319 var args = std.ArrayList([]const u8).init(arena);
320 try args.appendSlice(&[_][]const u8{
321 "-I",
322 try lib_path(mod, arena, lib_libc_glibc ++ "glibc" ++ path.sep_str ++ "csu"),
323 });
324 try add_include_dirs(mod, arena, &args);
325 try args.appendSlice(&[_][]const u8{
326 "-D_LIBC_REENTRANT",
327 "-DMODULE_NAME=libc",
328 "-DTOP_NAMESPACE=glibc",
329 "-DASSEMBLER",
330 "-g",
331 "-Wa,--noexecstack",
332 });
333 const c_source_file: Module.CSourceFile = .{
334 .src_path = try lib_path(mod, arena, lib_libc_glibc ++ "csu" ++ path.sep_str ++ "abi-note.S"),
335 .extra_flags = args.items,
336 };
337 return build_libc_object(mod, "abi-note.o", c_source_file);
338 },
339 .scrt1_o => {
340 return error.Unimplemented; // TODO
341 },
342 .libc_nonshared_a => {
343 return error.Unimplemented; // TODO
344 },
345 }
346}
347
348fn start_asm_path(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 {
349 const arch = mod.getTarget().cpu.arch;
350 const is_ppc = arch == .powerpc or arch == .powerpc64 or arch == .powerpc64le;
351 const is_aarch64 = arch == .aarch64 or arch == .aarch64_be;
352 const is_sparc = arch == .sparc or arch == .sparcel or arch == .sparcv9;
353 const is_64 = arch.ptrBitWidth() == 64;
354
355 const s = path.sep_str;
356
357 var result = std.ArrayList(u8).init(arena);
358 try result.appendSlice(mod.zig_lib_directory.path.?);
359 try result.appendSlice(s ++ "libc" ++ s ++ "glibc" ++ s ++ "sysdeps" ++ s);
360 if (is_sparc) {
361 if (is_64) {
362 try result.appendSlice("sparc" ++ s ++ "sparc64");
363 } else {
364 try result.appendSlice("sparc" ++ s ++ "sparc32");
365 }
366 } else if (arch.isARM()) {
367 try result.appendSlice("arm");
368 } else if (arch.isMIPS()) {
369 try result.appendSlice("mips");
370 } else if (arch == .x86_64) {
371 try result.appendSlice("x86_64");
372 } else if (arch == .i386) {
373 try result.appendSlice("i386");
374 } else if (is_aarch64) {
375 try result.appendSlice("aarch64");
376 } else if (arch.isRISCV()) {
377 try result.appendSlice("riscv");
378 } else if (is_ppc) {
379 if (is_64) {
380 try result.appendSlice("powerpc" ++ s ++ "powerpc64");
381 } else {
382 try result.appendSlice("powerpc" ++ s ++ "powerpc32");
383 }
384 }
385
386 try result.appendSlice(s);
387 try result.appendSlice(basename);
388 return result.items;
389}
390
391fn add_include_dirs(mod: *Module, arena: *Allocator, args: *std.ArrayList([]const u8)) error{OutOfMemory}!void {
392 const target = mod.getTarget();
393 const arch = target.cpu.arch;
394 const opt_nptl: ?[]const u8 = if (target.os.tag == .linux) "nptl" else "htl";
395 const glibc = try lib_path(mod, arena, lib_libc ++ "glibc");
396
397 const s = path.sep_str;
398
399 try args.append("-I");
400 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "include"));
401
402 if (target.os.tag == .linux) {
403 try add_include_dirs_arch(arena, args, arch, null, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix" ++ s ++ "sysv" ++ s ++ "linux"));
404 }
405
406 if (opt_nptl) |nptl| {
407 try add_include_dirs_arch(arena, args, arch, nptl, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps"));
408 }
409
410 if (target.os.tag == .linux) {
411 try args.append("-I");
412 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++
413 "unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s ++ "generic"));
414
415 try args.append("-I");
416 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++
417 "unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s ++ "include"));
418 try args.append("-I");
419 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++
420 "unix" ++ s ++ "sysv" ++ s ++ "linux"));
421 }
422 if (opt_nptl) |nptl| {
423 try args.append("-I");
424 try args.append(try path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, lib_libc_glibc ++ "sysdeps", nptl }));
425 }
426
427 try args.append("-I");
428 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "pthread"));
429
430 try args.append("-I");
431 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix" ++ s ++ "sysv"));
432
433 try add_include_dirs_arch(arena, args, arch, null, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix"));
434
435 try args.append("-I");
436 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix"));
437
438 try add_include_dirs_arch(arena, args, arch, null, try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps"));
439
440 try args.append("-I");
441 try args.append(try lib_path(mod, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "generic"));
442
443 try args.append("-I");
444 try args.append(try path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, lib_libc ++ "glibc" }));
445
446 try args.append("-I");
447 try args.append(try std.fmt.allocPrint(arena, "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{}-{}-{}", .{
448 mod.zig_lib_directory.path.?, @tagName(arch), @tagName(target.os.tag), @tagName(target.abi),
449 }));
450
451 try args.append("-I");
452 try args.append(try lib_path(mod, arena, lib_libc ++ "include" ++ s ++ "generic-glibc"));
453
454 try args.append("-I");
455 try args.append(try std.fmt.allocPrint(arena, "{}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{}-linux-any", .{
456 mod.zig_lib_directory.path.?, @tagName(arch),
457 }));
458
459 try args.append("-I");
460 try args.append(try lib_path(mod, arena, lib_libc ++ "include" ++ s ++ "any-linux-any"));
461}
462
463fn add_include_dirs_arch(
464 arena: *Allocator,
465 args: *std.ArrayList([]const u8),
466 arch: std.Target.Cpu.Arch,
467 opt_nptl: ?[]const u8,
468 dir: []const u8,
469) error{OutOfMemory}!void {
470 const is_x86 = arch == .i386 or arch == .x86_64;
471 const is_aarch64 = arch == .aarch64 or arch == .aarch64_be;
472 const is_ppc = arch == .powerpc or arch == .powerpc64 or arch == .powerpc64le;
473 const is_sparc = arch == .sparc or arch == .sparcel or arch == .sparcv9;
474 const is_64 = arch.ptrBitWidth() == 64;
475
476 const s = path.sep_str;
477
478 if (is_x86) {
479 if (arch == .x86_64) {
480 if (opt_nptl) |nptl| {
481 try args.append("-I");
482 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86_64", nptl }));
483 } else {
484 try args.append("-I");
485 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86_64" }));
486 }
487 } else if (arch == .i386) {
488 if (opt_nptl) |nptl| {
489 try args.append("-I");
490 try args.append(try path.join(arena, &[_][]const u8{ dir, "i386", nptl }));
491 } else {
492 try args.append("-I");
493 try args.append(try path.join(arena, &[_][]const u8{ dir, "i386" }));
494 }
495 }
496 if (opt_nptl) |nptl| {
497 try args.append("-I");
498 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86", nptl }));
499 } else {
500 try args.append("-I");
501 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86" }));
502 }
503 } else if (arch.isARM()) {
504 if (opt_nptl) |nptl| {
505 try args.append("-I");
506 try args.append(try path.join(arena, &[_][]const u8{ dir, "arm", nptl }));
507 } else {
508 try args.append("-I");
509 try args.append(try path.join(arena, &[_][]const u8{ dir, "arm" }));
510 }
511 } else if (arch.isMIPS()) {
512 if (opt_nptl) |nptl| {
513 try args.append("-I");
514 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips", nptl }));
515 } else {
516 if (is_64) {
517 try args.append("-I");
518 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" ++ s ++ "mips64" }));
519 } else {
520 try args.append("-I");
521 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" ++ s ++ "mips32" }));
522 }
523 try args.append("-I");
524 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" }));
525 }
526 } else if (is_sparc) {
527 if (opt_nptl) |nptl| {
528 try args.append("-I");
529 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc", nptl }));
530 } else {
531 if (is_64) {
532 try args.append("-I");
533 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" ++ s ++ "sparc64" }));
534 } else {
535 try args.append("-I");
536 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" ++ s ++ "sparc32" }));
537 }
538 try args.append("-I");
539 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" }));
540 }
541 } else if (is_aarch64) {
542 if (opt_nptl) |nptl| {
543 try args.append("-I");
544 try args.append(try path.join(arena, &[_][]const u8{ dir, "aarch64", nptl }));
545 } else {
546 try args.append("-I");
547 try args.append(try path.join(arena, &[_][]const u8{ dir, "aarch64" }));
548 }
549 } else if (is_ppc) {
550 if (opt_nptl) |nptl| {
551 try args.append("-I");
552 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc", nptl }));
553 } else {
554 if (is_64) {
555 try args.append("-I");
556 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" ++ s ++ "powerpc64" }));
557 } else {
558 try args.append("-I");
559 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" ++ s ++ "powerpc32" }));
560 }
561 try args.append("-I");
562 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" }));
563 }
564 } else if (arch.isRISCV()) {
565 if (opt_nptl) |nptl| {
566 try args.append("-I");
567 try args.append(try path.join(arena, &[_][]const u8{ dir, "riscv", nptl }));
568 } else {
569 try args.append("-I");
570 try args.append(try path.join(arena, &[_][]const u8{ dir, "riscv" }));
571 }
572 }
573}
574
575fn path_from_lib(mod: *Module, arena: *Allocator, sub_path: []const u8) ![]const u8 {
576 return path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, sub_path });
577}
578
579const lib_libc = "libc" ++ path.sep_str;
580const lib_libc_glibc = lib_libc ++ "glibc" ++ path.sep_str;
581
582fn lib_path(mod: *Module, arena: *Allocator, sub_path: []const u8) ![]const u8 {
583 return path.join(arena, &[_][]const u8{ mod.zig_lib_directory.path.?, sub_path });
584}
585
586fn build_libc_object(mod: *Module, basename: []const u8, c_source_file: Module.CSourceFile) !void {
587 // TODO: This is extracted into a local variable to work around a stage1 miscompilation.
588 const emit_bin = Module.EmitLoc{
589 .directory = null, // Put it in the cache directory.
590 .basename = basename,
591 };
592 const sub_module = try Module.create(mod.gpa, .{
593 // TODO use the global cache directory here
594 .zig_cache_directory = mod.zig_cache_directory,
595 .zig_lib_directory = mod.zig_lib_directory,
596 .target = mod.getTarget(),
597 .root_name = mem.split(basename, ".").next().?,
598 .root_pkg = null,
599 .output_mode = .Obj,
600 .rand = mod.rand,
601 .libc_installation = mod.bin_file.options.libc_installation,
602 .emit_bin = emit_bin,
603 .optimize_mode = mod.bin_file.options.optimize_mode,
604 .want_sanitize_c = false,
605 .want_stack_check = false,
606 .want_valgrind = false,
607 .want_pic = mod.bin_file.options.pic,
608 .emit_h = null,
609 .strip = mod.bin_file.options.strip,
610 .is_native_os = mod.bin_file.options.is_native_os,
611 .self_exe_path = mod.self_exe_path,
612 .c_source_files = &[1]Module.CSourceFile{c_source_file},
613 .debug_cc = mod.debug_cc,
614 .debug_link = mod.bin_file.options.debug_link,
615 });
616 defer sub_module.destroy();
617
618 try sub_module.update();
619
620 try mod.crt_files.ensureCapacity(mod.gpa, mod.crt_files.count() + 1);
621 const artifact_path = try std.fs.path.join(mod.gpa, &[_][]const u8{
622 sub_module.zig_cache_artifact_directory.path.?, basename,
623 });
624 mod.crt_files.putAssumeCapacityNoClobber(basename, artifact_path);
625}
src-self-hosted/introspect.zig+46-58
...@@ -1,77 +1,65 @@...@@ -1,77 +1,65 @@
1//! Introspection and determination of system libraries needed by zig.
2
3const std = @import("std");1const std = @import("std");
4const mem = std.mem;2const mem = std.mem;
5const fs = std.fs;3const fs = std.fs;
6const CacheHash = std.cache_hash.CacheHash;4const CacheHash = std.cache_hash.CacheHash;
75const Module = @import("Module.zig");
8/// Caller must free result6
9pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {7/// Returns the sub_path that worked, or `null` if none did.
10 {8/// The path of the returned Directory is relative to `base`.
11 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });9/// The handle of the returned Directory is open.
12 errdefer allocator.free(test_zig_dir);10fn testZigInstallPrefix(base_dir: fs.Dir) ?Module.Directory {
1311 const test_index_file = "std" ++ fs.path.sep_str ++ "std.zig";
14 const test_index_file = try fs.path.join(allocator, &[_][]const u8{ test_zig_dir, "std", "std.zig" });12
15 defer allocator.free(test_index_file);13 zig_dir: {
1614 // Try lib/zig/std/std.zig
17 if (fs.cwd().openFile(test_index_file, .{})) |file| {15 const lib_zig = "lib" ++ fs.path.sep_str ++ "zig";
18 file.close();16 var test_zig_dir = base_dir.openDir(lib_zig, .{}) catch break :zig_dir;
19 return test_zig_dir;17 const file = test_zig_dir.openFile(test_index_file, .{}) catch {
20 } else |err| switch (err) {18 test_zig_dir.close();
21 error.FileNotFound => {19 break :zig_dir;
22 allocator.free(test_zig_dir);20 };
23 },21 file.close();
24 else => |e| return e,22 return Module.Directory{ .handle = test_zig_dir, .path = lib_zig };
25 }
26 }23 }
2724
28 // Also try without "zig"25 // Try lib/std/std.zig
29 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib" });26 var test_zig_dir = base_dir.openDir("lib", .{}) catch return null;
30 errdefer allocator.free(test_zig_dir);27 const file = test_zig_dir.openFile(test_index_file, .{}) catch {
3128 test_zig_dir.close();
32 const test_index_file = try fs.path.join(allocator, &[_][]const u8{ test_zig_dir, "std", "std.zig" });29 return null;
33 defer allocator.free(test_index_file);30 };
34
35 const file = try fs.cwd().openFile(test_index_file, .{});
36 file.close();31 file.close();
3732 return Module.Directory{ .handle = test_zig_dir, .path = "lib" };
38 return test_zig_dir;
39}33}
4034
41/// Caller must free result35/// Both the directory handle and the path are newly allocated resources which the caller now owns.
42pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {36pub fn findZigLibDir(gpa: *mem.Allocator) !Module.Directory {
43 const self_exe_path = try fs.selfExePathAlloc(allocator);37 const self_exe_path = try fs.selfExePathAlloc(gpa);
44 defer allocator.free(self_exe_path);38 defer gpa.free(self_exe_path);
4539
46 var cur_path: []const u8 = self_exe_path;40 return findZigLibDirFromSelfExe(gpa, self_exe_path);
47 while (true) {41}
48 const test_dir = fs.path.dirname(cur_path) orelse ".";
49
50 if (mem.eql(u8, test_dir, cur_path)) {
51 break;
52 }
5342
54 return testZigInstallPrefix(allocator, test_dir) catch |err| {43/// Both the directory handle and the path are newly allocated resources which the caller now owns.
55 cur_path = test_dir;44pub fn findZigLibDirFromSelfExe(
56 continue;45 allocator: *mem.Allocator,
46 self_exe_path: []const u8,
47) error{ OutOfMemory, FileNotFound }!Module.Directory {
48 const cwd = fs.cwd();
49 var cur_path: []const u8 = self_exe_path;
50 while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) {
51 var base_dir = cwd.openDir(dirname, .{}) catch continue;
52 defer base_dir.close();
53
54 const sub_directory = testZigInstallPrefix(base_dir) orelse continue;
55 return Module.Directory{
56 .handle = sub_directory.handle,
57 .path = try fs.path.join(allocator, &[_][]const u8{ dirname, sub_directory.path.? }),
57 };58 };
58 }59 }
59
60 return error.FileNotFound;60 return error.FileNotFound;
61}61}
6262
63pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 {
64 return findZigLibDir(allocator) catch |err| {
65 std.debug.print(
66 \\Unable to find zig lib directory: {}.
67 \\Reinstall Zig or use --zig-install-prefix.
68 \\
69 , .{@errorName(err)});
70
71 return error.ZigLibDirNotFound;
72 };
73}
74
75/// Caller owns returned memory.63/// Caller owns returned memory.
76pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 {64pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 {
77 const appname = "zig";65 const appname = "zig";
src-self-hosted/link.zig+9-6
...@@ -11,11 +11,9 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation;...@@ -11,11 +11,9 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
11pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;11pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
1212
13pub const Options = struct {13pub const Options = struct {
14 dir: fs.Dir,14 /// Where the output will go.
15 /// Redundant with dir. Needed when linking with LLD because we have to pass paths rather15 directory: Module.Directory,
16 /// than file descriptors. `null` means cwd. OK to pass `null` when `use_lld` is `false`.16 /// Path to the output file, relative to `directory`.
17 dir_path: ?[]const u8,
18 /// Path to the output file, relative to dir.
19 sub_path: []const u8,17 sub_path: []const u8,
20 target: std.Target,18 target: std.Target,
21 output_mode: std.builtin.OutputMode,19 output_mode: std.builtin.OutputMode,
...@@ -53,6 +51,11 @@ pub const Options = struct {...@@ -53,6 +51,11 @@ pub const Options = struct {
53 z_defs: bool = false,51 z_defs: bool = false,
54 bind_global_refs_locally: bool,52 bind_global_refs_locally: bool,
55 is_native_os: bool,53 is_native_os: bool,
54 pic: bool,
55 valgrind: bool,
56 stack_check: bool,
57 single_threaded: bool,
58 debug_link: bool = false,
56 gc_sections: ?bool = null,59 gc_sections: ?bool = null,
57 allow_shlib_undefined: ?bool = null,60 allow_shlib_undefined: ?bool = null,
58 linker_script: ?[]const u8 = null,61 linker_script: ?[]const u8 = null,
...@@ -154,7 +157,7 @@ pub const File = struct {...@@ -154,7 +157,7 @@ pub const File = struct {
154 switch (base.tag) {157 switch (base.tag) {
155 .coff, .elf, .macho => {158 .coff, .elf, .macho => {
156 if (base.file != null) return;159 if (base.file != null) return;
157 base.file = try base.options.dir.createFile(base.options.sub_path, .{160 base.file = try base.options.directory.handle.createFile(base.options.sub_path, .{
158 .truncate = false,161 .truncate = false,
159 .read = true,162 .read = true,
160 .mode = determineMode(base.options),163 .mode = determineMode(base.options),
src-self-hosted/link/C.zig+1-1
...@@ -28,7 +28,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -28,7 +28,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
28 if (options.use_llvm) return error.LLVMHasNoCBackend;28 if (options.use_llvm) return error.LLVMHasNoCBackend;
29 if (options.use_lld) return error.LLDHasNoCBackend;29 if (options.use_lld) return error.LLDHasNoCBackend;
3030
31 const file = try options.dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });31 const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });
32 errdefer file.close();32 errdefer file.close();
3333
34 var c_file = try allocator.create(C);34 var c_file = try allocator.create(C);
src-self-hosted/link/Coff.zig+1-1
...@@ -116,7 +116,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -116,7 +116,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
116 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO116 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO
117 if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO117 if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO
118118
119 const file = try options.dir.createFile(sub_path, .{119 const file = try options.directory.handle.createFile(sub_path, .{
120 .truncate = false,120 .truncate = false,
121 .read = true,121 .read = true,
122 .mode = link.determineMode(options),122 .mode = link.determineMode(options),
src-self-hosted/link/Elf.zig+53-12
...@@ -19,6 +19,7 @@ const File = link.File;...@@ -19,6 +19,7 @@ const File = link.File;
19const Elf = @This();19const Elf = @This();
20const build_options = @import("build_options");20const build_options = @import("build_options");
21const target_util = @import("../target.zig");21const target_util = @import("../target.zig");
22const fatal = @import("main.zig").fatal;
2223
23const default_entry_addr = 0x8000000;24const default_entry_addr = 0x8000000;
2425
...@@ -222,7 +223,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -222,7 +223,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
222223
223 if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO224 if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO
224225
225 const file = try options.dir.createFile(sub_path, .{226 const file = try options.directory.handle.createFile(sub_path, .{
226 .truncate = false,227 .truncate = false,
227 .read = true,228 .read = true,
228 .mode = link.determineMode(options),229 .mode = link.determineMode(options),
...@@ -844,7 +845,7 @@ fn flushInner(self: *Elf, module: *Module) !void {...@@ -844,7 +845,7 @@ fn flushInner(self: *Elf, module: *Module) !void {
844 }845 }
845 // Write the form for the compile unit, which must match the abbrev table above.846 // Write the form for the compile unit, which must match the abbrev table above.
846 const name_strp = try self.makeDebugString(self.base.options.root_pkg.?.root_src_path);847 const name_strp = try self.makeDebugString(self.base.options.root_pkg.?.root_src_path);
847 const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.?.root_src_dir_path);848 const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.?.root_src_directory.path.?);
848 const producer_strp = try self.makeDebugString(link.producer_string);849 const producer_strp = try self.makeDebugString(link.producer_string);
849 // Currently only one compilation unit is supported, so the address range is simply850 // Currently only one compilation unit is supported, so the address range is simply
850 // identical to the main program header virtual address and memory size.851 // identical to the main program header virtual address and memory size.
...@@ -1199,11 +1200,6 @@ fn flushInner(self: *Elf, module: *Module) !void {...@@ -1199,11 +1200,6 @@ fn flushInner(self: *Elf, module: *Module) !void {
1199}1200}
12001201
1201fn linkWithLLD(self: *Elf, module: *Module) !void {1202fn linkWithLLD(self: *Elf, module: *Module) !void {
1202 // If there is no Zig code to compile, then we should skip flushing the output file because it
1203 // will not be part of the linker line anyway.
1204 if (module.root_pkg != null) {
1205 try self.flushInner(module);
1206 }
1207 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);1203 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
1208 defer arena_allocator.deinit();1204 defer arena_allocator.deinit();
1209 const arena = &arena_allocator.allocator;1205 const arena = &arena_allocator.allocator;
...@@ -1292,7 +1288,7 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {...@@ -1292,7 +1288,7 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {
1292 try argv.append("-pie");1288 try argv.append("-pie");
1293 }1289 }
12941290
1295 const full_out_path = if (self.base.options.dir_path) |dir_path|1291 const full_out_path = if (self.base.options.directory.path) |dir_path|
1296 try std.fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path})1292 try std.fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path})
1297 else 1293 else
1298 self.base.options.sub_path;1294 self.base.options.sub_path;
...@@ -1382,6 +1378,30 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {...@@ -1382,6 +1378,30 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {
1382 // Positional arguments to the linker such as object files.1378 // Positional arguments to the linker such as object files.
1383 try argv.appendSlice(self.base.options.objects);1379 try argv.appendSlice(self.base.options.objects);
13841380
1381 for (module.c_object_table.items()) |entry| {
1382 const c_object = entry.key;
1383 switch (c_object.status) {
1384 .new => unreachable,
1385 .failure => return error.NotAllCSourceFilesAvailableToLink,
1386 .success => |full_obj_path| {
1387 try argv.append(full_obj_path);
1388 },
1389 }
1390 }
1391
1392 // If there is no Zig code to compile, then we should skip flushing the output file because it
1393 // will not be part of the linker line anyway.
1394 if (module.root_pkg != null) {
1395 try self.flushInner(module);
1396
1397 const obj_basename = self.base.intermediary_basename.?;
1398 const full_obj_path = if (self.base.options.directory.path) |dir_path|
1399 try std.fs.path.join(arena, &[_][]const u8{dir_path, obj_basename})
1400 else
1401 obj_basename;
1402 try argv.append(full_obj_path);
1403 }
1404
1385 // TODO compiler-rt and libc1405 // TODO compiler-rt and libc
1386 //if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {1406 //if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
1387 // if (g->libc_link_lib == nullptr) {1407 // if (g->libc_link_lib == nullptr) {
...@@ -1461,10 +1481,31 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {...@@ -1461,10 +1481,31 @@ fn linkWithLLD(self: *Elf, module: *Module) !void {
1461 try argv.append("-Bsymbolic");1481 try argv.append("-Bsymbolic");
1462 }1482 }
14631483
1464 for (argv.items) |arg| {1484 if (self.base.options.debug_link) {
1465 std.debug.print("{} ", .{arg});1485 for (argv.items[0 .. argv.items.len - 1]) |arg| {
1486 std.debug.print("{} ", .{arg});
1487 }
1488 std.debug.print("{}\n", .{argv.items[argv.items.len - 1]});
1466 }1489 }
1467 @panic("invoke LLD");1490
1491 // Oh, snapplesauce! We need null terminated argv.
1492 // TODO allocSentinel crashed stage1 so this is working around it.
1493 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);
1494 new_argv_with_sentinel[argv.items.len] = null;
1495 const new_argv = new_argv_with_sentinel[0..argv.items.len: null];
1496 for (argv.items) |arg, i| {
1497 new_argv[i] = try arena.dupeZ(u8, arg);
1498 }
1499
1500 const ZigLLDLink = @import("../llvm.zig").ZigLLDLink;
1501 const ok = ZigLLDLink(.ELF, new_argv.ptr, new_argv.len, append_diagnostic, 0, 0);
1502 if (!ok) return error.LLDReportedFailure;
1503}
1504
1505fn append_diagnostic(context: usize, ptr: [*]const u8, len: usize) callconv(.C) void {
1506 // TODO collect diagnostics and handle cleanly
1507 const msg = ptr[0..len];
1508 std.log.err("LLD: {}", .{msg});
1468}1509}
14691510
1470fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {1511fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
...@@ -2681,7 +2722,7 @@ fn dbgLineNeededHeaderBytes(self: Elf) u32 {...@@ -2681,7 +2722,7 @@ fn dbgLineNeededHeaderBytes(self: Elf) u32 {
2681 directory_count * 8 + file_name_count * 8 +2722 directory_count * 8 + file_name_count * 8 +
2682 // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like2723 // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like
2683 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.2724 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
2684 self.base.options.root_pkg.?.root_src_dir_path.len +2725 self.base.options.root_pkg.?.root_src_directory.path.?.len +
2685 self.base.options.root_pkg.?.root_src_path.len);2726 self.base.options.root_pkg.?.root_src_path.len);
2686}2727}
26872728
src-self-hosted/link/MachO.zig+1-1
...@@ -140,7 +140,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -140,7 +140,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
140 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO140 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO
141 if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO141 if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO
142142
143 const file = try options.dir.createFile(sub_path, .{143 const file = try options.directory.handle.createFile(sub_path, .{
144 .truncate = false,144 .truncate = false,
145 .read = true,145 .read = true,
146 .mode = link.determineMode(options),146 .mode = link.determineMode(options),
src-self-hosted/link/Wasm.zig+1-1
...@@ -56,7 +56,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -56,7 +56,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
56 if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO56 if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO
5757
58 // TODO: read the file and keep vaild parts instead of truncating58 // TODO: read the file and keep vaild parts instead of truncating
59 const file = try options.dir.createFile(sub_path, .{ .truncate = true, .read = true });59 const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
60 errdefer file.close();60 errdefer file.close();
6161
62 const wasm = try allocator.create(Wasm);62 const wasm = try allocator.create(Wasm);
src-self-hosted/llvm.zig+18-291
...@@ -1,293 +1,20 @@...@@ -1,293 +1,20 @@
1const c = @import("c.zig");1//! We do this instead of @cImport because the self-hosted compiler is easier
2const assert = @import("std").debug.assert;2//! to bootstrap if it does not depend on translate-c.
33
4// we wrap the c module for 3 reasons:4pub extern fn ZigLLDLink(
5// 1. to avoid accidentally calling the non-thread-safe functions5 oformat: ZigLLVM_ObjectFormatType,
6// 2. patch up some of the types to remove nullability6 args: [*:null]const ?[*:0]const u8,
7// 3. some functions have been augmented by zig_llvm.cpp to be more powerful,7 arg_count: usize,
8// such as ZigLLVMTargetMachineEmitToFile8 append_diagnostic: fn (context: usize, ptr: [*]const u8, len: usize) callconv(.C) void,
99 context_stdout: usize,
10pub const AttributeIndex = c_uint;10 context_stderr: usize,
11pub const Bool = c_int;
12
13pub const Builder = c.LLVMBuilderRef.Child.Child;
14pub const Context = c.LLVMContextRef.Child.Child;
15pub const Module = c.LLVMModuleRef.Child.Child;
16pub const Value = c.LLVMValueRef.Child.Child;
17pub const Type = c.LLVMTypeRef.Child.Child;
18pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child;
19pub const Attribute = c.LLVMAttributeRef.Child.Child;
20pub const Target = c.LLVMTargetRef.Child.Child;
21pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child;
22pub const TargetData = c.LLVMTargetDataRef.Child.Child;
23pub const DIBuilder = c.ZigLLVMDIBuilder;
24pub const DIFile = c.ZigLLVMDIFile;
25pub const DICompileUnit = c.ZigLLVMDICompileUnit;
26
27pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
28pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
29pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
30pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
31pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
32pub const ConstAllOnes = c.LLVMConstAllOnes;
33pub const ConstArray = c.LLVMConstArray;
34pub const ConstBitCast = c.LLVMConstBitCast;
35pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
36pub const ConstNeg = c.LLVMConstNeg;
37pub const ConstStructInContext = c.LLVMConstStructInContext;
38pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
39pub const DisposeBuilder = c.LLVMDisposeBuilder;
40pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
41pub const DisposeMessage = c.LLVMDisposeMessage;
42pub const DisposeModule = c.LLVMDisposeModule;
43pub const DisposeTargetData = c.LLVMDisposeTargetData;
44pub const DisposeTargetMachine = c.LLVMDisposeTargetMachine;
45pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext;
46pub const DumpModule = c.LLVMDumpModule;
47pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
48pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
49pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
50pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
51pub const GetUndef = c.LLVMGetUndef;
52pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
53pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
54pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;
55pub const InitializeAllTargetInfos = c.LLVMInitializeAllTargetInfos;
56pub const InitializeAllTargetMCs = c.LLVMInitializeAllTargetMCs;
57pub const InitializeAllTargets = c.LLVMInitializeAllTargets;
58pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext;
59pub const Int128TypeInContext = c.LLVMInt128TypeInContext;
60pub const Int16TypeInContext = c.LLVMInt16TypeInContext;
61pub const Int1TypeInContext = c.LLVMInt1TypeInContext;
62pub const Int32TypeInContext = c.LLVMInt32TypeInContext;
63pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
64pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
65pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
66pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
67pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
68pub const MDNodeInContext = c.LLVMMDNodeInContext;
69pub const MDStringInContext = c.LLVMMDStringInContext;
70pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
71pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
72pub const SetAlignment = c.LLVMSetAlignment;
73pub const SetDataLayout = c.LLVMSetDataLayout;
74pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
75pub const SetInitializer = c.LLVMSetInitializer;
76pub const SetLinkage = c.LLVMSetLinkage;
77pub const SetTarget = c.LLVMSetTarget;
78pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
79pub const SetVolatile = c.LLVMSetVolatile;
80pub const StructTypeInContext = c.LLVMStructTypeInContext;
81pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
82pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
83pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
84
85pub const AddGlobal = LLVMAddGlobal;
86extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value;
87
88pub const ConstStringInContext = LLVMConstStringInContext;
89extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
90
91pub const ConstInt = LLVMConstInt;
92extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
93
94pub const BuildLoad = LLVMBuildLoad;
95extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*:0]const u8) ?*Value;
96
97pub const ConstNull = LLVMConstNull;
98extern fn LLVMConstNull(Ty: *Type) ?*Value;
99
100pub const CreateStringAttribute = LLVMCreateStringAttribute;
101extern fn LLVMCreateStringAttribute(
102 C: *Context,
103 K: [*]const u8,
104 KLength: c_uint,
105 V: [*]const u8,
106 VLength: c_uint,
107) ?*Attribute;
108
109pub const CreateEnumAttribute = LLVMCreateEnumAttribute;
110extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute;
111
112pub const AddFunction = LLVMAddFunction;
113extern fn LLVMAddFunction(M: *Module, Name: [*:0]const u8, FunctionTy: *Type) ?*Value;
114
115pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
116extern fn ZigLLVMCreateCompileUnit(
117 dibuilder: *DIBuilder,
118 lang: c_uint,
119 difile: *DIFile,
120 producer: [*:0]const u8,
121 is_optimized: bool,
122 flags: [*:0]const u8,
123 runtime_version: c_uint,
124 split_name: [*:0]const u8,
125 dwo_id: u64,
126 emit_debug_info: bool,
127) ?*DICompileUnit;
128
129pub const CreateFile = ZigLLVMCreateFile;
130extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*:0]const u8, directory: [*:0]const u8) ?*DIFile;
131
132pub const ArrayType = LLVMArrayType;
133extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type;
134
135pub const CreateDIBuilder = ZigLLVMCreateDIBuilder;
136extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder;
137
138pub const PointerType = LLVMPointerType;
139extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type;
140
141pub const CreateBuilderInContext = LLVMCreateBuilderInContext;
142extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder;
143
144pub const IntTypeInContext = LLVMIntTypeInContext;
145extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type;
146
147pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext;
148extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*:0]const u8, C: *Context) ?*Module;
149
150pub const VoidTypeInContext = LLVMVoidTypeInContext;
151extern fn LLVMVoidTypeInContext(C: *Context) ?*Type;
152
153pub const ContextCreate = LLVMContextCreate;
154extern fn LLVMContextCreate() ?*Context;
155
156pub const ContextDispose = LLVMContextDispose;
157extern fn LLVMContextDispose(C: *Context) void;
158
159pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData;
160extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*:0]u8;
161
162pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
163extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
164
165pub const CreateTargetMachine = ZigLLVMCreateTargetMachine;
166extern fn ZigLLVMCreateTargetMachine(
167 T: *Target,
168 Triple: [*:0]const u8,
169 CPU: [*:0]const u8,
170 Features: [*:0]const u8,
171 Level: CodeGenOptLevel,
172 Reloc: RelocMode,
173 CodeModel: CodeModel,
174 function_sections: bool,
175) ?*TargetMachine;
176
177pub const GetHostCPUName = LLVMGetHostCPUName;
178extern fn LLVMGetHostCPUName() ?[*:0]u8;
179
180pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
181extern fn ZigLLVMGetNativeFeatures() ?[*:0]u8;
182
183pub const GetElementType = LLVMGetElementType;
184extern fn LLVMGetElementType(Ty: *Type) *Type;
185
186pub const TypeOf = LLVMTypeOf;
187extern fn LLVMTypeOf(Val: *Value) *Type;
188
189pub const BuildStore = LLVMBuildStore;
190extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
191
192pub const BuildAlloca = LLVMBuildAlloca;
193extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*:0]const u8) ?*Value;
194
195pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
196pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
197
198pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
199extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **Target, ErrorMessage: ?*[*:0]u8) Bool;
200
201pub const VerifyModule = LLVMVerifyModule;
202extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*:0]u8) Bool;
203
204pub const GetInsertBlock = LLVMGetInsertBlock;
205extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
206
207pub const FunctionType = LLVMFunctionType;
208extern fn LLVMFunctionType(
209 ReturnType: *Type,
210 ParamTypes: [*]*Type,
211 ParamCount: c_uint,
212 IsVarArg: Bool,
213) ?*Type;
214
215pub const GetParam = LLVMGetParam;
216extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
217
218pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
219extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*:0]const u8) ?*BasicBlock;
220
221pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
222extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
223
224pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
225pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
226pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction;
227pub const VerifierFailureAction = c.LLVMVerifierFailureAction;
228
229pub const CodeGenLevelNone = CodeGenOptLevel.LLVMCodeGenLevelNone;
230pub const CodeGenLevelLess = CodeGenOptLevel.LLVMCodeGenLevelLess;
231pub const CodeGenLevelDefault = CodeGenOptLevel.LLVMCodeGenLevelDefault;
232pub const CodeGenLevelAggressive = CodeGenOptLevel.LLVMCodeGenLevelAggressive;
233pub const CodeGenOptLevel = c.LLVMCodeGenOptLevel;
234
235pub const RelocDefault = RelocMode.LLVMRelocDefault;
236pub const RelocStatic = RelocMode.LLVMRelocStatic;
237pub const RelocPIC = RelocMode.LLVMRelocPIC;
238pub const RelocDynamicNoPic = RelocMode.LLVMRelocDynamicNoPic;
239pub const RelocMode = c.LLVMRelocMode;
240
241pub const CodeModelDefault = CodeModel.LLVMCodeModelDefault;
242pub const CodeModelJITDefault = CodeModel.LLVMCodeModelJITDefault;
243pub const CodeModelSmall = CodeModel.LLVMCodeModelSmall;
244pub const CodeModelKernel = CodeModel.LLVMCodeModelKernel;
245pub const CodeModelMedium = CodeModel.LLVMCodeModelMedium;
246pub const CodeModelLarge = CodeModel.LLVMCodeModelLarge;
247pub const CodeModel = c.LLVMCodeModel;
248
249pub const EmitAssembly = EmitOutputType.ZigLLVM_EmitAssembly;
250pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;
251pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;
252pub const EmitOutputType = c.ZigLLVM_EmitOutputType;
253
254pub const CCallConv = CallConv.LLVMCCallConv;
255pub const FastCallConv = CallConv.LLVMFastCallConv;
256pub const ColdCallConv = CallConv.LLVMColdCallConv;
257pub const WebKitJSCallConv = CallConv.LLVMWebKitJSCallConv;
258pub const AnyRegCallConv = CallConv.LLVMAnyRegCallConv;
259pub const X86StdcallCallConv = CallConv.LLVMX86StdcallCallConv;
260pub const X86FastcallCallConv = CallConv.LLVMX86FastcallCallConv;
261pub const CallConv = c.LLVMCallConv;
262
263pub const CallAttr = extern enum {
264 Auto,
265 NeverTail,
266 NeverInline,
267 AlwaysTail,
268 AlwaysInline,
269};
270
271fn removeNullability(comptime T: type) type {
272 comptime assert(@typeInfo(T).Pointer.size == .C);
273 return *T.Child;
274}
275
276pub const BuildRet = LLVMBuildRet;
277extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
278
279pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
280extern fn ZigLLVMTargetMachineEmitToFile(
281 targ_machine_ref: *TargetMachine,
282 module_ref: *Module,
283 filename: [*:0]const u8,
284 output_type: EmitOutputType,
285 error_message: *[*:0]u8,
286 is_debug: bool,
287 is_small: bool,
288) bool;11) bool;
28912
290pub const BuildCall = ZigLLVMBuildCall;13pub const ZigLLVM_ObjectFormatType = extern enum(c_int) {
291extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: CallConv, fn_inline: CallAttr, Name: [*:0]const u8) ?*Value;14 Unknown,
29215 COFF,
293pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;16 ELF,
17 MachO,
18 Wasm,
19 XCOFF,
20};
src-self-hosted/main.zig+121-33
...@@ -191,7 +191,14 @@ const usage_build_generic =...@@ -191,7 +191,14 @@ const usage_build_generic =
191 \\ ReleaseSmall Optimize for small binary, safety off191 \\ ReleaseSmall Optimize for small binary, safety off
192 \\ -fPIC Force-enable Position Independent Code192 \\ -fPIC Force-enable Position Independent Code
193 \\ -fno-PIC Force-disable Position Independent Code193 \\ -fno-PIC Force-disable Position Independent Code
194 \\ -fstack-check Enable stack probing in unsafe builds
195 \\ -fno-stack-check Disable stack probing in safe builds
196 \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds
197 \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds
198 \\ -fvalgrind Include valgrind client requests in release builds
199 \\ -fno-valgrind Omit valgrind client requests in debug builds
194 \\ --strip Exclude debug symbols200 \\ --strip Exclude debug symbols
201 \\ --single-threaded Code assumes it is only used single-threaded
195 \\ -ofmt=[mode] Override target object format202 \\ -ofmt=[mode] Override target object format
196 \\ elf Executable and Linking Format203 \\ elf Executable and Linking Format
197 \\ c Compile to C source code204 \\ c Compile to C source code
...@@ -262,6 +269,7 @@ pub fn buildOutputType(...@@ -262,6 +269,7 @@ pub fn buildOutputType(
262 var root_src_file: ?[]const u8 = null;269 var root_src_file: ?[]const u8 = null;
263 var version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 };270 var version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 };
264 var strip = false;271 var strip = false;
272 var single_threaded = false;
265 var watch = false;273 var watch = false;
266 var debug_tokenize = false;274 var debug_tokenize = false;
267 var debug_ast_tree = false;275 var debug_ast_tree = false;
...@@ -287,6 +295,8 @@ pub fn buildOutputType(...@@ -287,6 +295,8 @@ pub fn buildOutputType(
287 var enable_cache: ?bool = null;295 var enable_cache: ?bool = null;
288 var want_pic: ?bool = null;296 var want_pic: ?bool = null;
289 var want_sanitize_c: ?bool = null;297 var want_sanitize_c: ?bool = null;
298 var want_stack_check: ?bool = null;
299 var want_valgrind: ?bool = null;
290 var rdynamic: bool = false;300 var rdynamic: bool = false;
291 var only_pp_or_asm = false;301 var only_pp_or_asm = false;
292 var linker_script: ?[]const u8 = null;302 var linker_script: ?[]const u8 = null;
...@@ -320,7 +330,7 @@ pub fn buildOutputType(...@@ -320,7 +330,7 @@ pub fn buildOutputType(
320 var rpath_list = std.ArrayList([]const u8).init(gpa);330 var rpath_list = std.ArrayList([]const u8).init(gpa);
321 defer rpath_list.deinit();331 defer rpath_list.deinit();
322332
323 var c_source_files = std.ArrayList([]const u8).init(gpa);333 var c_source_files = std.ArrayList(Module.CSourceFile).init(gpa);
324 defer c_source_files.deinit();334 defer c_source_files.deinit();
325335
326 var link_objects = std.ArrayList([]const u8).init(gpa);336 var link_objects = std.ArrayList([]const u8).init(gpa);
...@@ -463,6 +473,18 @@ pub fn buildOutputType(...@@ -463,6 +473,18 @@ pub fn buildOutputType(
463 want_pic = true;473 want_pic = true;
464 } else if (mem.eql(u8, arg, "-fno-PIC")) {474 } else if (mem.eql(u8, arg, "-fno-PIC")) {
465 want_pic = false;475 want_pic = false;
476 } else if (mem.eql(u8, arg, "-fstack-check")) {
477 want_stack_check = true;
478 } else if (mem.eql(u8, arg, "-fno-stack-check")) {
479 want_stack_check = false;
480 } else if (mem.eql(u8, arg, "-fsanitize-c")) {
481 want_sanitize_c = true;
482 } else if (mem.eql(u8, arg, "-fno-sanitize-c")) {
483 want_sanitize_c = false;
484 } else if (mem.eql(u8, arg, "-fvalgrind")) {
485 want_valgrind = true;
486 } else if (mem.eql(u8, arg, "-fno-valgrind")) {
487 want_valgrind = false;
466 } else if (mem.eql(u8, arg, "-fLLVM")) {488 } else if (mem.eql(u8, arg, "-fLLVM")) {
467 use_llvm = true;489 use_llvm = true;
468 } else if (mem.eql(u8, arg, "-fno-LLVM")) {490 } else if (mem.eql(u8, arg, "-fno-LLVM")) {
...@@ -501,6 +523,8 @@ pub fn buildOutputType(...@@ -501,6 +523,8 @@ pub fn buildOutputType(
501 link_mode = .Static;523 link_mode = .Static;
502 } else if (mem.eql(u8, arg, "--strip")) {524 } else if (mem.eql(u8, arg, "--strip")) {
503 strip = true;525 strip = true;
526 } else if (mem.eql(u8, arg, "--single-threaded")) {
527 single_threaded = true;
504 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {528 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
505 link_eh_frame_hdr = true;529 link_eh_frame_hdr = true;
506 } else if (mem.eql(u8, arg, "-Bsymbolic")) {530 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
...@@ -541,7 +565,8 @@ pub fn buildOutputType(...@@ -541,7 +565,8 @@ pub fn buildOutputType(
541 {565 {
542 try link_objects.append(arg);566 try link_objects.append(arg);
543 } else if (Module.hasAsmExt(arg) or Module.hasCExt(arg) or Module.hasCppExt(arg)) {567 } else if (Module.hasAsmExt(arg) or Module.hasCExt(arg) or Module.hasCppExt(arg)) {
544 try c_source_files.append(arg);568 // TODO a way to pass extra flags on the CLI
569 try c_source_files.append(.{ .src_path = arg });
545 } else if (mem.endsWith(u8, arg, ".so") or570 } else if (mem.endsWith(u8, arg, ".so") or
546 mem.endsWith(u8, arg, ".dylib") or571 mem.endsWith(u8, arg, ".dylib") or
547 mem.endsWith(u8, arg, ".dll"))572 mem.endsWith(u8, arg, ".dll"))
...@@ -586,7 +611,7 @@ pub fn buildOutputType(...@@ -586,7 +611,7 @@ pub fn buildOutputType(
586 .positional => {611 .positional => {
587 const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg));612 const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg));
588 switch (file_ext) {613 switch (file_ext) {
589 .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg),614 .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(.{ .src_path = it.only_arg }),
590 .unknown, .so => try link_objects.append(it.only_arg),615 .unknown, .so => try link_objects.append(it.only_arg),
591 }616 }
592 },617 },
...@@ -812,7 +837,7 @@ pub fn buildOutputType(...@@ -812,7 +837,7 @@ pub fn buildOutputType(
812 // .yes => |p| p,837 // .yes => |p| p,
813 // else => c_source_file.source_path,838 // else => c_source_file.source_path,
814 // };839 // };
815 // const basename = std.fs.path.basename(src_path);840 // const basename = fs.path.basename(src_path);
816 // c_source_file.preprocessor_only_basename = basename;841 // c_source_file.preprocessor_only_basename = basename;
817 //}842 //}
818 //emit_bin = .no;843 //emit_bin = .no;
...@@ -839,7 +864,7 @@ pub fn buildOutputType(...@@ -839,7 +864,7 @@ pub fn buildOutputType(
839 const basename = fs.path.basename(file);864 const basename = fs.path.basename(file);
840 break :blk mem.split(basename, ".").next().?;865 break :blk mem.split(basename, ".").next().?;
841 } else if (c_source_files.items.len == 1) {866 } else if (c_source_files.items.len == 1) {
842 const basename = fs.path.basename(c_source_files.items[0]);867 const basename = fs.path.basename(c_source_files.items[0].src_path);
843 break :blk mem.split(basename, ".").next().?;868 break :blk mem.split(basename, ".").next().?;
844 } else if (link_objects.items.len == 1) {869 } else if (link_objects.items.len == 1) {
845 const basename = fs.path.basename(link_objects.items[0]);870 const basename = fs.path.basename(link_objects.items[0]);
...@@ -966,19 +991,71 @@ pub fn buildOutputType(...@@ -966,19 +991,71 @@ pub fn buildOutputType(
966 }991 }
967 };992 };
968993
969 const bin_path = switch (emit_bin) {994 var cleanup_emit_bin_dir: ?fs.Dir = null;
970 .no => {995 defer if (cleanup_emit_bin_dir) |*dir| dir.close();
971 fatal("-fno-emit-bin not supported yet", .{});996
997 const emit_bin_loc: ?Module.EmitLoc = switch (emit_bin) {
998 .no => null,
999 .yes_default_path => Module.EmitLoc{
1000 .directory = .{ .path = null, .handle = fs.cwd() },
1001 .basename = try std.zig.binNameAlloc(
1002 arena,
1003 root_name,
1004 target_info.target,
1005 output_mode,
1006 link_mode,
1007 object_format,
1008 ),
1009 },
1010 .yes => |full_path| b: {
1011 const basename = fs.path.basename(full_path);
1012 if (fs.path.dirname(full_path)) |dirname| {
1013 const handle = try fs.cwd().openDir(dirname, .{});
1014 cleanup_emit_bin_dir = handle;
1015 break :b Module.EmitLoc{
1016 .basename = basename,
1017 .directory = .{
1018 .path = dirname,
1019 .handle = handle,
1020 },
1021 };
1022 } else {
1023 break :b Module.EmitLoc{
1024 .basename = basename,
1025 .directory = .{ .path = null, .handle = fs.cwd() },
1026 };
1027 }
1028 },
1029 };
1030
1031 var cleanup_emit_h_dir: ?fs.Dir = null;
1032 defer if (cleanup_emit_h_dir) |*dir| dir.close();
1033
1034 const emit_h_loc: ?Module.EmitLoc = switch (emit_h) {
1035 .no => null,
1036 .yes_default_path => Module.EmitLoc{
1037 .directory = .{ .path = null, .handle = fs.cwd() },
1038 .basename = try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
1039 },
1040 .yes => |full_path| b: {
1041 const basename = fs.path.basename(full_path);
1042 if (fs.path.dirname(full_path)) |dirname| {
1043 const handle = try fs.cwd().openDir(dirname, .{});
1044 cleanup_emit_h_dir = handle;
1045 break :b Module.EmitLoc{
1046 .basename = basename,
1047 .directory = .{
1048 .path = dirname,
1049 .handle = handle,
1050 },
1051 };
1052 } else {
1053 break :b Module.EmitLoc{
1054 .basename = basename,
1055 .directory = .{ .path = null, .handle = fs.cwd() },
1056 };
1057 }
972 },1058 },
973 .yes_default_path => try std.zig.binNameAlloc(
974 arena,
975 root_name,
976 target_info.target,
977 output_mode,
978 link_mode,
979 object_format,
980 ),
981 .yes => |p| p,
982 };1059 };
9831060
984 const zir_out_path: ?[]const u8 = switch (emit_zir) {1061 const zir_out_path: ?[]const u8 = switch (emit_zir) {
...@@ -995,19 +1072,13 @@ pub fn buildOutputType(...@@ -995,19 +1072,13 @@ pub fn buildOutputType(
995 };1072 };
9961073
997 const root_pkg = if (root_src_file) |src_path| try Package.create(gpa, fs.cwd(), ".", src_path) else null;1074 const root_pkg = if (root_src_file) |src_path| try Package.create(gpa, fs.cwd(), ".", src_path) else null;
998 defer if (root_pkg) |pkg| pkg.destroy();1075 defer if (root_pkg) |pkg| pkg.destroy(gpa);
999
1000 const emit_h_path: ?[]const u8 = switch (emit_h) {
1001 .yes => |p| p,
1002 .no => null,
1003 .yes_default_path => try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
1004 };
10051076
1006 const self_exe_path = try fs.selfExePathAlloc(arena);1077 const self_exe_path = try fs.selfExePathAlloc(arena);
1007 const zig_lib_dir = introspect.resolveZigLibDir(gpa) catch |err| {1078 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
1008 fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});1079 fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
1009 };1080 };
1010 defer gpa.free(zig_lib_dir);1081 defer zig_lib_directory.handle.close();
10111082
1012 const random_seed = blk: {1083 const random_seed = blk: {
1013 var random_seed: u64 = undefined;1084 var random_seed: u64 = undefined;
...@@ -1025,17 +1096,32 @@ pub fn buildOutputType(...@@ -1025,17 +1096,32 @@ pub fn buildOutputType(
1025 };1096 };
1026 }1097 }
10271098
1099 const cache_parent_dir = if (root_pkg) |pkg| pkg.root_src_directory.handle else fs.cwd();
1100 var cache_dir = try cache_parent_dir.makeOpenPath("zig-cache", .{});
1101 defer cache_dir.close();
1102 const zig_cache_directory: Module.Directory = .{
1103 .handle = cache_dir,
1104 .path = blk: {
1105 if (root_pkg) |pkg| {
1106 if (pkg.root_src_directory.path) |p| {
1107 break :blk try fs.path.join(arena, &[_][]const u8{ p, "zig-cache" });
1108 }
1109 }
1110 break :blk "zig-cache";
1111 },
1112 };
1113
1028 const module = Module.create(gpa, .{1114 const module = Module.create(gpa, .{
1029 .zig_lib_dir = zig_lib_dir,1115 .zig_lib_directory = zig_lib_directory,
1116 .zig_cache_directory = zig_cache_directory,
1030 .root_name = root_name,1117 .root_name = root_name,
1031 .target = target_info.target,1118 .target = target_info.target,
1032 .is_native_os = cross_target.isNativeOs(),1119 .is_native_os = cross_target.isNativeOs(),
1033 .dynamic_linker = target_info.dynamic_linker.get(),1120 .dynamic_linker = target_info.dynamic_linker.get(),
1034 .output_mode = output_mode,1121 .output_mode = output_mode,
1035 .root_pkg = root_pkg,1122 .root_pkg = root_pkg,
1036 .bin_file_dir_path = null,1123 .emit_bin = emit_bin_loc,
1037 .bin_file_dir = fs.cwd(),1124 .emit_h = emit_h_loc,
1038 .bin_file_path = bin_path,
1039 .link_mode = link_mode,1125 .link_mode = link_mode,
1040 .object_format = object_format,1126 .object_format = object_format,
1041 .optimize_mode = build_mode,1127 .optimize_mode = build_mode,
...@@ -1049,11 +1135,12 @@ pub fn buildOutputType(...@@ -1049,11 +1135,12 @@ pub fn buildOutputType(
1049 .framework_dirs = framework_dirs.items,1135 .framework_dirs = framework_dirs.items,
1050 .frameworks = frameworks.items,1136 .frameworks = frameworks.items,
1051 .system_libs = system_libs.items,1137 .system_libs = system_libs.items,
1052 .emit_h = emit_h_path,
1053 .link_libc = link_libc,1138 .link_libc = link_libc,
1054 .link_libcpp = link_libcpp,1139 .link_libcpp = link_libcpp,
1055 .want_pic = want_pic,1140 .want_pic = want_pic,
1056 .want_sanitize_c = want_sanitize_c,1141 .want_sanitize_c = want_sanitize_c,
1142 .want_stack_check = want_stack_check,
1143 .want_valgrind = want_valgrind,
1057 .use_llvm = use_llvm,1144 .use_llvm = use_llvm,
1058 .use_lld = use_lld,1145 .use_lld = use_lld,
1059 .use_clang = use_clang,1146 .use_clang = use_clang,
...@@ -1070,11 +1157,14 @@ pub fn buildOutputType(...@@ -1070,11 +1157,14 @@ pub fn buildOutputType(
1070 .link_eh_frame_hdr = link_eh_frame_hdr,1157 .link_eh_frame_hdr = link_eh_frame_hdr,
1071 .stack_size_override = stack_size_override,1158 .stack_size_override = stack_size_override,
1072 .strip = strip,1159 .strip = strip,
1160 .single_threaded = single_threaded,
1073 .self_exe_path = self_exe_path,1161 .self_exe_path = self_exe_path,
1074 .rand = &default_prng.random,1162 .rand = &default_prng.random,
1075 .clang_passthrough_mode = arg_mode != .build,1163 .clang_passthrough_mode = arg_mode != .build,
1076 .version = version,1164 .version = version,
1077 .libc_installation = if (libc_installation) |*lci| lci else null,1165 .libc_installation = if (libc_installation) |*lci| lci else null,
1166 .debug_cc = debug_cc,
1167 .debug_link = debug_link,
1078 }) catch |err| {1168 }) catch |err| {
1079 fatal("unable to create module: {}", .{@errorName(err)});1169 fatal("unable to create module: {}", .{@errorName(err)});
1080 };1170 };
...@@ -1121,9 +1211,7 @@ pub fn buildOutputType(...@@ -1121,9 +1211,7 @@ pub fn buildOutputType(
1121}1211}
11221212
1123fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void {1213fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void {
1124 var timer = try std.time.Timer.start();
1125 try module.update();1214 try module.update();
1126 const update_nanos = timer.read();
11271215
1128 var errors = try module.getAllErrorsAlloc();1216 var errors = try module.getAllErrorsAlloc();
1129 defer errors.deinit(module.gpa);1217 defer errors.deinit(module.gpa);
src-self-hosted/print_env.zig+13-6
...@@ -2,15 +2,19 @@ const std = @import("std");...@@ -2,15 +2,19 @@ const std = @import("std");
2const build_options = @import("build_options");2const build_options = @import("build_options");
3const introspect = @import("introspect.zig");3const introspect = @import("introspect.zig");
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const fatal = @import("main.zig").fatal;
56
6pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void {7pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void {
7 const zig_lib_dir = introspect.resolveZigLibDir(gpa) catch |err| {8 const self_exe_path = try std.fs.selfExePathAlloc(gpa);
8 std.debug.print("unable to find zig installation directory: {}\n", .{@errorName(err)});9 defer gpa.free(self_exe_path);
9 std.process.exit(1);10
11 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(gpa, self_exe_path) catch |err| {
12 fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
10 };13 };
11 defer gpa.free(zig_lib_dir);14 defer gpa.free(zig_lib_directory.path.?);
15 defer zig_lib_directory.handle.close();
1216
13 const zig_std_dir = try std.fs.path.join(gpa, &[_][]const u8{ zig_lib_dir, "std" });17 const zig_std_dir = try std.fs.path.join(gpa, &[_][]const u8{ zig_lib_directory.path.?, "std" });
14 defer gpa.free(zig_std_dir);18 defer gpa.free(zig_std_dir);
1519
16 const global_cache_dir = try introspect.resolveGlobalCacheDir(gpa);20 const global_cache_dir = try introspect.resolveGlobalCacheDir(gpa);
...@@ -22,8 +26,11 @@ pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void...@@ -22,8 +26,11 @@ pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void
22 var jws = std.json.WriteStream(@TypeOf(bos_stream), 6).init(bos_stream);26 var jws = std.json.WriteStream(@TypeOf(bos_stream), 6).init(bos_stream);
23 try jws.beginObject();27 try jws.beginObject();
2428
29 try jws.objectField("zig_exe");
30 try jws.emitString(self_exe_path);
31
25 try jws.objectField("lib_dir");32 try jws.objectField("lib_dir");
26 try jws.emitString(zig_lib_dir);33 try jws.emitString(zig_lib_directory.path.?);
2734
28 try jws.objectField("std_dir");35 try jws.objectField("std_dir");
29 try jws.emitString(zig_std_dir);36 try jws.emitString(zig_std_dir);
src-self-hosted/print_targets.zig+5-7
...@@ -17,16 +17,14 @@ pub fn cmdTargets(...@@ -17,16 +17,14 @@ pub fn cmdTargets(
17 stdout: anytype,17 stdout: anytype,
18 native_target: Target,18 native_target: Target,
19) !void {19) !void {
20 const zig_lib_dir_path = introspect.resolveZigLibDir(allocator) catch |err| {20 var zig_lib_directory = introspect.findZigLibDir(allocator) catch |err| {
21 fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});21 fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
22 };22 };
23 defer allocator.free(zig_lib_dir_path);23 defer zig_lib_directory.handle.close();
24 defer allocator.free(zig_lib_directory.path.?);
2425
25 var zig_lib_dir = try fs.cwd().openDir(zig_lib_dir_path, .{});26 const glibc_abi = try glibc.loadMetaData(allocator, zig_lib_directory.handle);
26 defer zig_lib_dir.close();27 defer glibc_abi.destroy(allocator);
27
28 const glibc_abi = try glibc.loadMetaData(allocator, zig_lib_dir);
29 errdefer glibc_abi.destroy(allocator);
3028
31 var bos = io.bufferedOutStream(stdout);29 var bos = io.bufferedOutStream(stdout);
32 const bos_stream = bos.outStream();30 const bos_stream = bos.outStream();
src-self-hosted/target.zig+37-3
...@@ -117,10 +117,10 @@ pub fn cannotDynamicLink(target: std.Target) bool {...@@ -117,10 +117,10 @@ pub fn cannotDynamicLink(target: std.Target) bool {
117 };117 };
118}118}
119119
120/// On Darwin, we always link libSystem which contains libc.
121/// Similarly on FreeBSD and NetBSD we always link system libc
122/// since this is the stable syscall interface.
120pub fn osRequiresLibC(target: std.Target) bool {123pub fn osRequiresLibC(target: std.Target) bool {
121 // On Darwin, we always link libSystem which contains libc.
122 // Similarly on FreeBSD and NetBSD we always link system libc
123 // since this is the stable syscall interface.
124 return switch (target.os.tag) {124 return switch (target.os.tag) {
125 .freebsd, .netbsd, .dragonfly, .macosx, .ios, .watchos, .tvos => true,125 .freebsd, .netbsd, .dragonfly, .macosx, .ios, .watchos, .tvos => true,
126 else => false,126 else => false,
...@@ -131,6 +131,40 @@ pub fn requiresPIE(target: std.Target) bool {...@@ -131,6 +131,40 @@ pub fn requiresPIE(target: std.Target) bool {
131 return target.isAndroid();131 return target.isAndroid();
132}132}
133133
134/// This function returns whether non-pic code is completely invalid on the given target.
135pub fn requiresPIC(target: std.Target, linking_libc: bool) bool {
136 return target.isAndroid() or
137 target.os.tag == .windows or target.os.tag == .uefi or
138 osRequiresLibC(target) or
139 (linking_libc and target.isGnuLibC());
140}
141
142/// This is not whether the target supports Position Independent Code, but whether the -fPIC
143/// C compiler argument is valid to Clang.
144pub fn supports_fpic(target: std.Target) bool {
145 return target.os.tag != .windows;
146}
147
134pub fn libc_needs_crti_crtn(target: std.Target) bool {148pub fn libc_needs_crti_crtn(target: std.Target) bool {
135 return !(target.cpu.arch.isRISCV() or target.isAndroid());149 return !(target.cpu.arch.isRISCV() or target.isAndroid());
136}150}
151
152pub fn isSingleThreaded(target: std.Target) bool {
153 return target.isWasm();
154}
155
156/// Valgrind supports more, but Zig does not support them yet.
157pub fn hasValgrindSupport(target: std.Target) bool {
158 switch (target.cpu.arch) {
159 .x86_64 => {
160 return target.os.tag == .linux or target.isDarwin() or target.os.tag == .solaris or
161 (target.os.tag == .windows and target.abi != .msvc);
162 },
163 else => return false,
164 }
165}
166
167pub fn supportsStackProbing(target: std.Target) bool {
168 return target.os.tag != .windows and target.os.tag != .uefi and
169 (target.cpu.arch == .i386 or target.cpu.arch == .x86_64);
170}
src-self-hosted/test.zig+25-8
...@@ -407,8 +407,9 @@ pub const TestContext = struct {...@@ -407,8 +407,9 @@ pub const TestContext = struct {
407 const root_node = try progress.start("tests", self.cases.items.len);407 const root_node = try progress.start("tests", self.cases.items.len);
408 defer root_node.end();408 defer root_node.end();
409409
410 const zig_lib_dir = try introspect.resolveZigLibDir(std.testing.allocator);410 var zig_lib_directory = try introspect.findZigLibDir(std.testing.allocator);
411 defer std.testing.allocator.free(zig_lib_dir);411 defer zig_lib_directory.handle.close();
412 defer std.testing.allocator.free(zig_lib_directory.path.?);
412413
413 const random_seed = blk: {414 const random_seed = blk: {
414 var random_seed: u64 = undefined;415 var random_seed: u64 = undefined;
...@@ -427,7 +428,7 @@ pub const TestContext = struct {...@@ -427,7 +428,7 @@ pub const TestContext = struct {
427 progress.initial_delay_ns = 0;428 progress.initial_delay_ns = 0;
428 progress.refresh_rate_ns = 0;429 progress.refresh_rate_ns = 0;
429430
430 try self.runOneCase(std.testing.allocator, &prg_node, case, zig_lib_dir, &default_prng.random);431 try self.runOneCase(std.testing.allocator, &prg_node, case, zig_lib_directory, &default_prng.random);
431 }432 }
432 }433 }
433434
...@@ -436,7 +437,7 @@ pub const TestContext = struct {...@@ -436,7 +437,7 @@ pub const TestContext = struct {
436 allocator: *Allocator,437 allocator: *Allocator,
437 root_node: *std.Progress.Node,438 root_node: *std.Progress.Node,
438 case: Case,439 case: Case,
439 zig_lib_dir: []const u8,440 zig_lib_directory: Module.Directory,
440 rand: *std.rand.Random,441 rand: *std.rand.Random,
441 ) !void {442 ) !void {
442 const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);443 const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);
...@@ -449,15 +450,32 @@ pub const TestContext = struct {...@@ -449,15 +450,32 @@ pub const TestContext = struct {
449 var tmp = std.testing.tmpDir(.{});450 var tmp = std.testing.tmpDir(.{});
450 defer tmp.cleanup();451 defer tmp.cleanup();
451452
453 var cache_dir = try tmp.dir.makeOpenPath("zig-cache", .{});
454 defer cache_dir.close();
455 const bogus_path = "bogus"; // TODO this will need to be fixed before we can test LLVM extensions
456 const zig_cache_directory: Module.Directory = .{
457 .handle = cache_dir,
458 .path = try std.fs.path.join(arena, &[_][]const u8{ bogus_path, "zig-cache" }),
459 };
460
452 const tmp_src_path = if (case.extension == .Zig) "test_case.zig" else if (case.extension == .ZIR) "test_case.zir" else unreachable;461 const tmp_src_path = if (case.extension == .Zig) "test_case.zig" else if (case.extension == .ZIR) "test_case.zir" else unreachable;
453 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);462 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
454 defer root_pkg.destroy();463 defer root_pkg.destroy(allocator);
455464
456 const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null;465 const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null;
457 const bin_name = try std.zig.binNameAlloc(arena, "test_case", target, case.output_mode, null, ofmt);466 const bin_name = try std.zig.binNameAlloc(arena, "test_case", target, case.output_mode, null, ofmt);
458467
468 const emit_directory: Module.Directory = .{
469 .path = bogus_path,
470 .handle = tmp.dir,
471 };
472 const emit_bin: Module.EmitLoc = .{
473 .directory = emit_directory,
474 .basename = bin_name,
475 };
459 const module = try Module.create(allocator, .{476 const module = try Module.create(allocator, .{
460 .zig_lib_dir = zig_lib_dir,477 .zig_cache_directory = zig_cache_directory,
478 .zig_lib_directory = zig_lib_directory,
461 .rand = rand,479 .rand = rand,
462 .root_name = "test_case",480 .root_name = "test_case",
463 .target = target,481 .target = target,
...@@ -467,8 +485,7 @@ pub const TestContext = struct {...@@ -467,8 +485,7 @@ pub const TestContext = struct {
467 .output_mode = case.output_mode,485 .output_mode = case.output_mode,
468 // TODO: support testing optimizations486 // TODO: support testing optimizations
469 .optimize_mode = .Debug,487 .optimize_mode = .Debug,
470 .bin_file_dir = tmp.dir,488 .emit_bin = emit_bin,
471 .bin_file_path = bin_name,
472 .root_pkg = root_pkg,489 .root_pkg = root_pkg,
473 .keep_source_files_loaded = true,490 .keep_source_files_loaded = true,
474 .object_format = ofmt,491 .object_format = ofmt,