| author | |
| committer | |
| log | 03a23418ff13e6ff64cdeed3ef4b54f99c533d88 |
| tree | 90b53580d9f1fe74e8598f10dc86dfc490ee230e |
| parent | 8374be1a1c6cba12ec01d7a6301a8da0a00907f4 |
* 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"); |
| 25 | const zir_sema = @import("zir_sema.zig"); | 25 | const zir_sema = @import("zir_sema.zig"); |
| 26 | const build_options = @import("build_options"); | 26 | const build_options = @import("build_options"); |
| 27 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 27 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 28 | const glibc = @import("glibc.zig"); | ||
| 29 | const fatal = @import("main.zig").fatal; | ||
| 28 | 30 | ||
| 29 | /// General-purpose allocator. Used for both temporary and long-term storage. | 31 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 30 | gpa: *Allocator, | 32 | gpa: *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`. |
| 93 | clang_passthrough_mode: bool, | 95 | clang_passthrough_mode: bool, |
| 96 | /// Whether to print clang argvs to stdout. | ||
| 97 | debug_cc: bool, | ||
| 94 | 98 | ||
| 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. |
| 96 | global_error_set: std.StringHashMapUnmanaged(u16) = .{}, | 100 | global_error_set: std.StringHashMapUnmanaged(u16) = .{}, |
| 97 | 101 | ||
| 98 | c_source_files: []const []const u8, | 102 | c_source_files: []const CSourceFile, |
| 99 | clang_argv: []const []const u8, | 103 | clang_argv: []const []const u8, |
| 100 | cache: std.cache_hash.CacheHash, | 104 | cache: std.cache_hash.CacheHash, |
| 101 | /// Path to own executable for invoking `zig clang`. | 105 | /// Path to own executable for invoking `zig clang`. |
| 102 | self_exe_path: ?[]const u8, | 106 | self_exe_path: ?[]const u8, |
| 103 | zig_lib_dir: []const u8, | 107 | zig_lib_directory: Directory, |
| 104 | zig_cache_dir_path: []const u8, | 108 | zig_cache_directory: Directory, |
| 109 | zig_cache_artifact_directory: Directory, | ||
| 105 | libc_include_dir_list: []const []const u8, | 110 | libc_include_dir_list: []const []const u8, |
| 106 | rand: *std.rand.Random, | 111 | rand: *std.rand.Random, |
| 107 | 112 | ||
| ... | @@ -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(). |
| 119 | libc_static_lib: ?[]const u8 = null, | 124 | libc_static_lib: ?[]const u8 = null, |
| 120 | 125 | ||
| 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. | ||
| 129 | crt_files: std.StringHashMapUnmanaged([]const u8) = .{}, | ||
| 130 | |||
| 121 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; | 131 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 122 | 132 | ||
| 133 | /// For passing to a C compiler. | ||
| 134 | pub const CSourceFile = struct { | ||
| 135 | src_path: []const u8, | ||
| 136 | extra_flags: []const []const u8 = &[0][]const u8{}, | ||
| 137 | }; | ||
| 138 | |||
| 123 | const WorkItem = union(enum) { | 139 | const 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 linked | 149 | /// 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 | }; |
| 137 | 158 | ||
| 138 | pub const Export = struct { | 159 | pub 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 | }; |
| 939 | 960 | ||
| 961 | pub 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 | |||
| 969 | pub 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 | |||
| 940 | pub const InitOptions = struct { | 977 | pub 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 { |
| 1057 | 1100 | ||
| 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 | ); |
| 1066 | 1109 | ||
| 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(); |
| 1108 | 1265 | ||
| ... | @@ -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 | }; |
| 1144 | 1301 | ||
| 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(); |
| 1246 | 1333 | ||
| 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); | ||
| 1249 | 1335 | ||
| 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 | } |
| 1258 | 1346 | ||
| 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 and | 1348 | // We go through the work queue so that building can be done in parallel. |
| 1261 | mod.bin_file.options.libc_installation == null and | 1349 | if (mod.wantBuildGLibCFromSource()) { |
| 1262 | mod.bin_file.options.target.isGnuLibC()) | ||
| 1263 | { | ||
| 1264 | try mod.addBuildingGLibCWorkItems(); | 1350 | try mod.addBuildingGLibCWorkItems(); |
| 1265 | } | 1351 | } |
| 1266 | 1352 | ||
| ... | @@ -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(); |
| 1275 | 1361 | ||
| 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(); |
| 1326 | 1423 | ||
| 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 | } |
| 1586 | 1694 | ||
| ... | @@ -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(); |
| 1590 | 1698 | ||
| 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); |
| 1618 | 1728 | ||
| 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" }); |
| 1620 | 1733 | ||
| 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); |
| 1630 | 1743 | ||
| 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 | } | ||
| 1634 | 1750 | ||
| 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 { |
| 1689 | 1805 | ||
| 1690 | // TODO handle .d files | 1806 | // TODO handle .d files |
| 1691 | 1807 | ||
| 1692 | // TODO rename into place | 1808 | // 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); | ||
| 1694 | 1811 | ||
| 1695 | // TODO use the cache file name instead of tmp file name | 1812 | 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 | } |
| 1699 | 1817 | ||
| ... | @@ -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 | } |
| 1708 | 1826 | ||
| ... | @@ -1749,10 +1867,10 @@ fn addCCArgs( | ... | @@ -1749,10 +1867,10 @@ fn addCCArgs( |
| 1749 | 1867 | ||
| 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 | }); |
| 1757 | 1875 | ||
| 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 intrinsics | 1895 | // 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); |
| 1782 | 1900 | ||
| ... | @@ -1891,10 +2009,9 @@ fn addCCArgs( | ... | @@ -1891,10 +2009,9 @@ fn addCCArgs( |
| 1891 | }, | 2009 | }, |
| 1892 | } | 2010 | } |
| 1893 | 2011 | ||
| 1894 | // TODO add CLI args for PIC | 2012 | 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 | //} | ||
| 1898 | 2015 | ||
| 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 | } |
| 4498 | 4615 | ||
| 4499 | pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 { | 4616 | pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 { |
| 4500 | // TODO port support for building crt files from stage1 | 4617 | 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 | } |
| 4506 | 4625 | ||
| 4507 | fn addBuildingGLibCWorkItems(mod: *Module) !void { | 4626 | fn addBuildingGLibCWorkItems(mod: *Module) !void { |
| 4508 | // crti.o, crtn.o, start.os, abi-note.o, Scrt1.o, libc_nonshared.a | 4627 | 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 | |||
| 4642 | fn 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 @@ |
| 1 | pub const Table = std.StringHashMap(*Package); | 1 | pub const Table = std.StringHashMapUnmanaged(*Package); |
| 2 | 2 | ||
| 3 | /// This should be used for file operations. | 3 | root_src_directory: Module.Directory, |
| 4 | root_src_dir: std.fs.Dir, | 4 | /// Relative to `root_src_directory`. |
| 5 | /// This is for metadata purposes, for example putting into debug information. | ||
| 6 | root_src_dir_path: []u8, | ||
| 7 | /// Relative to `root_src_dir` and `root_src_dir_path`. | ||
| 8 | root_src_path: []u8, | 5 | root_src_path: []u8, |
| 9 | table: Table, | 6 | table: Table, |
| 10 | 7 | ||
| 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. |
| 12 | pub fn create( | 9 | pub 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 | } |
| 34 | 33 | ||
| 35 | pub fn destroy(self: *Package) void { | 34 | pub 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 | } |
| 49 | 47 | ||
| 50 | pub fn add(self: *Package, name: []const u8, package: *Package) !void { | 48 | pub 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 | } |
| 55 | 53 | ||
| 56 | const std = @import("std"); | 54 | const std = @import("std"); |
| 57 | const mem = std.mem; | 55 | const mem = std.mem; |
| 56 | const Allocator = std.mem.Allocator; | ||
| 58 | const assert = std.debug.assert; | 57 | const assert = std.debug.assert; |
| 59 | const Package = @This(); | 58 | const Package = @This(); |
| 59 | const 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"); |
| 2 | const Allocator = std.mem.Allocator; | 2 | const Allocator = std.mem.Allocator; |
| 3 | const target_util = @import("target.zig"); | 3 | const target_util = @import("target.zig"); |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const Module = @import("Module.zig"); | ||
| 6 | const path = std.fs.path; | ||
| 7 | const build_options = @import("build_options"); | ||
| 5 | 8 | ||
| 6 | pub const Lib = struct { | 9 | pub 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); |
| 62 | 65 | ||
| 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 | |||
| 236 | pub 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 | |||
| 245 | pub 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 | |||
| 348 | fn 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 | |||
| 391 | fn 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 | |||
| 463 | fn 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 | |||
| 575 | fn 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 | |||
| 579 | const lib_libc = "libc" ++ path.sep_str; | ||
| 580 | const lib_libc_glibc = lib_libc ++ "glibc" ++ path.sep_str; | ||
| 581 | |||
| 582 | fn 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 | |||
| 586 | fn 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 | |||
| 3 | const std = @import("std"); | 1 | const std = @import("std"); |
| 4 | const mem = std.mem; | 2 | const mem = std.mem; |
| 5 | const fs = std.fs; | 3 | const fs = std.fs; |
| 6 | const CacheHash = std.cache_hash.CacheHash; | 4 | const CacheHash = std.cache_hash.CacheHash; |
| 7 | 5 | const Module = @import("Module.zig"); | |
| 8 | /// Caller must free result | 6 | |
| 9 | pub 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); | 10 | fn testZigInstallPrefix(base_dir: fs.Dir) ?Module.Directory { |
| 13 | 11 | 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: { |
| 16 | 14 | // 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 | } |
| 27 | 24 | ||
| 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 { |
| 31 | 28 | 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(); |
| 37 | 32 | return Module.Directory{ .handle = test_zig_dir, .path = "lib" }; | |
| 38 | return test_zig_dir; | ||
| 39 | } | 33 | } |
| 40 | 34 | ||
| 41 | /// Caller must free result | 35 | /// Both the directory handle and the path are newly allocated resources which the caller now owns. |
| 42 | pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 { | 36 | pub 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); |
| 45 | 39 | ||
| 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 | } | ||
| 53 | 42 | ||
| 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; | 44 | pub 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 | } |
| 62 | 62 | ||
| 63 | pub 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. |
| 76 | pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 { | 64 | pub 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; |
| 11 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; | 11 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; |
| 12 | 12 | ||
| 13 | pub const Options = struct { | 13 | pub 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 rather | 15 | 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; |
| 30 | 30 | ||
| 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(); |
| 33 | 33 | ||
| 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; // TODO | 116 | if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO |
| 117 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO | 117 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO |
| 118 | 118 | ||
| 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; |
| 19 | const Elf = @This(); | 19 | const Elf = @This(); |
| 20 | const build_options = @import("build_options"); | 20 | const build_options = @import("build_options"); |
| 21 | const target_util = @import("../target.zig"); | 21 | const target_util = @import("../target.zig"); |
| 22 | const fatal = @import("main.zig").fatal; | ||
| 22 | 23 | ||
| 23 | const default_entry_addr = 0x8000000; | 24 | const default_entry_addr = 0x8000000; |
| 24 | 25 | ||
| ... | @@ -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 |
| 222 | 223 | ||
| 223 | if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO | 224 | if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO |
| 224 | 225 | ||
| 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 simply | 850 | // 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 | } |
| 1200 | 1201 | ||
| 1201 | fn linkWithLLD(self: *Elf, module: *Module) !void { | 1202 | fn 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 | } |
| 1294 | 1290 | ||
| 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); |
| 1384 | 1380 | ||
| 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 libc | 1405 | // 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 | } |
| 1463 | 1483 | ||
| 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 | |||
| 1505 | fn 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 | } |
| 1469 | 1510 | ||
| 1470 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { | 1511 | fn 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 like | 2723 | // 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 | } |
| 2687 | 2728 |
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; // TODO | 140 | if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO |
| 141 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO | 141 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO |
| 142 | 142 | ||
| 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; // TODO | 56 | if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO |
| 57 | 57 | ||
| 58 | // TODO: read the file and keep vaild parts instead of truncating | 58 | // 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(); |
| 61 | 61 | ||
| 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 @@ |
| 1 | const c = @import("c.zig"); | 1 | //! We do this instead of @cImport because the self-hosted compiler is easier |
| 2 | const assert = @import("std").debug.assert; | 2 | //! to bootstrap if it does not depend on translate-c. |
| 3 | 3 | ||
| 4 | // we wrap the c module for 3 reasons: | 4 | pub extern fn ZigLLDLink( |
| 5 | // 1. to avoid accidentally calling the non-thread-safe functions | 5 | oformat: ZigLLVM_ObjectFormatType, |
| 6 | // 2. patch up some of the types to remove nullability | 6 | 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 ZigLLVMTargetMachineEmitToFile | 8 | append_diagnostic: fn (context: usize, ptr: [*]const u8, len: usize) callconv(.C) void, |
| 9 | 9 | context_stdout: usize, | |
| 10 | pub const AttributeIndex = c_uint; | 10 | context_stderr: usize, |
| 11 | pub const Bool = c_int; | ||
| 12 | |||
| 13 | pub const Builder = c.LLVMBuilderRef.Child.Child; | ||
| 14 | pub const Context = c.LLVMContextRef.Child.Child; | ||
| 15 | pub const Module = c.LLVMModuleRef.Child.Child; | ||
| 16 | pub const Value = c.LLVMValueRef.Child.Child; | ||
| 17 | pub const Type = c.LLVMTypeRef.Child.Child; | ||
| 18 | pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child; | ||
| 19 | pub const Attribute = c.LLVMAttributeRef.Child.Child; | ||
| 20 | pub const Target = c.LLVMTargetRef.Child.Child; | ||
| 21 | pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child; | ||
| 22 | pub const TargetData = c.LLVMTargetDataRef.Child.Child; | ||
| 23 | pub const DIBuilder = c.ZigLLVMDIBuilder; | ||
| 24 | pub const DIFile = c.ZigLLVMDIFile; | ||
| 25 | pub const DICompileUnit = c.ZigLLVMDICompileUnit; | ||
| 26 | |||
| 27 | pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType; | ||
| 28 | pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex; | ||
| 29 | pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag; | ||
| 30 | pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; | ||
| 31 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; | ||
| 32 | pub const ConstAllOnes = c.LLVMConstAllOnes; | ||
| 33 | pub const ConstArray = c.LLVMConstArray; | ||
| 34 | pub const ConstBitCast = c.LLVMConstBitCast; | ||
| 35 | pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision; | ||
| 36 | pub const ConstNeg = c.LLVMConstNeg; | ||
| 37 | pub const ConstStructInContext = c.LLVMConstStructInContext; | ||
| 38 | pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize; | ||
| 39 | pub const DisposeBuilder = c.LLVMDisposeBuilder; | ||
| 40 | pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder; | ||
| 41 | pub const DisposeMessage = c.LLVMDisposeMessage; | ||
| 42 | pub const DisposeModule = c.LLVMDisposeModule; | ||
| 43 | pub const DisposeTargetData = c.LLVMDisposeTargetData; | ||
| 44 | pub const DisposeTargetMachine = c.LLVMDisposeTargetMachine; | ||
| 45 | pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext; | ||
| 46 | pub const DumpModule = c.LLVMDumpModule; | ||
| 47 | pub const FP128TypeInContext = c.LLVMFP128TypeInContext; | ||
| 48 | pub const FloatTypeInContext = c.LLVMFloatTypeInContext; | ||
| 49 | pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName; | ||
| 50 | pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext; | ||
| 51 | pub const GetUndef = c.LLVMGetUndef; | ||
| 52 | pub const HalfTypeInContext = c.LLVMHalfTypeInContext; | ||
| 53 | pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers; | ||
| 54 | pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters; | ||
| 55 | pub const InitializeAllTargetInfos = c.LLVMInitializeAllTargetInfos; | ||
| 56 | pub const InitializeAllTargetMCs = c.LLVMInitializeAllTargetMCs; | ||
| 57 | pub const InitializeAllTargets = c.LLVMInitializeAllTargets; | ||
| 58 | pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext; | ||
| 59 | pub const Int128TypeInContext = c.LLVMInt128TypeInContext; | ||
| 60 | pub const Int16TypeInContext = c.LLVMInt16TypeInContext; | ||
| 61 | pub const Int1TypeInContext = c.LLVMInt1TypeInContext; | ||
| 62 | pub const Int32TypeInContext = c.LLVMInt32TypeInContext; | ||
| 63 | pub const Int64TypeInContext = c.LLVMInt64TypeInContext; | ||
| 64 | pub const Int8TypeInContext = c.LLVMInt8TypeInContext; | ||
| 65 | pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext; | ||
| 66 | pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext; | ||
| 67 | pub const LabelTypeInContext = c.LLVMLabelTypeInContext; | ||
| 68 | pub const MDNodeInContext = c.LLVMMDNodeInContext; | ||
| 69 | pub const MDStringInContext = c.LLVMMDStringInContext; | ||
| 70 | pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext; | ||
| 71 | pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext; | ||
| 72 | pub const SetAlignment = c.LLVMSetAlignment; | ||
| 73 | pub const SetDataLayout = c.LLVMSetDataLayout; | ||
| 74 | pub const SetGlobalConstant = c.LLVMSetGlobalConstant; | ||
| 75 | pub const SetInitializer = c.LLVMSetInitializer; | ||
| 76 | pub const SetLinkage = c.LLVMSetLinkage; | ||
| 77 | pub const SetTarget = c.LLVMSetTarget; | ||
| 78 | pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr; | ||
| 79 | pub const SetVolatile = c.LLVMSetVolatile; | ||
| 80 | pub const StructTypeInContext = c.LLVMStructTypeInContext; | ||
| 81 | pub const TokenTypeInContext = c.LLVMTokenTypeInContext; | ||
| 82 | pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; | ||
| 83 | pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; | ||
| 84 | |||
| 85 | pub const AddGlobal = LLVMAddGlobal; | ||
| 86 | extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value; | ||
| 87 | |||
| 88 | pub const ConstStringInContext = LLVMConstStringInContext; | ||
| 89 | extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; | ||
| 90 | |||
| 91 | pub const ConstInt = LLVMConstInt; | ||
| 92 | extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value; | ||
| 93 | |||
| 94 | pub const BuildLoad = LLVMBuildLoad; | ||
| 95 | extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*:0]const u8) ?*Value; | ||
| 96 | |||
| 97 | pub const ConstNull = LLVMConstNull; | ||
| 98 | extern fn LLVMConstNull(Ty: *Type) ?*Value; | ||
| 99 | |||
| 100 | pub const CreateStringAttribute = LLVMCreateStringAttribute; | ||
| 101 | extern fn LLVMCreateStringAttribute( | ||
| 102 | C: *Context, | ||
| 103 | K: [*]const u8, | ||
| 104 | KLength: c_uint, | ||
| 105 | V: [*]const u8, | ||
| 106 | VLength: c_uint, | ||
| 107 | ) ?*Attribute; | ||
| 108 | |||
| 109 | pub const CreateEnumAttribute = LLVMCreateEnumAttribute; | ||
| 110 | extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute; | ||
| 111 | |||
| 112 | pub const AddFunction = LLVMAddFunction; | ||
| 113 | extern fn LLVMAddFunction(M: *Module, Name: [*:0]const u8, FunctionTy: *Type) ?*Value; | ||
| 114 | |||
| 115 | pub const CreateCompileUnit = ZigLLVMCreateCompileUnit; | ||
| 116 | extern 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 | |||
| 129 | pub const CreateFile = ZigLLVMCreateFile; | ||
| 130 | extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*:0]const u8, directory: [*:0]const u8) ?*DIFile; | ||
| 131 | |||
| 132 | pub const ArrayType = LLVMArrayType; | ||
| 133 | extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type; | ||
| 134 | |||
| 135 | pub const CreateDIBuilder = ZigLLVMCreateDIBuilder; | ||
| 136 | extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder; | ||
| 137 | |||
| 138 | pub const PointerType = LLVMPointerType; | ||
| 139 | extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type; | ||
| 140 | |||
| 141 | pub const CreateBuilderInContext = LLVMCreateBuilderInContext; | ||
| 142 | extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder; | ||
| 143 | |||
| 144 | pub const IntTypeInContext = LLVMIntTypeInContext; | ||
| 145 | extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type; | ||
| 146 | |||
| 147 | pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext; | ||
| 148 | extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*:0]const u8, C: *Context) ?*Module; | ||
| 149 | |||
| 150 | pub const VoidTypeInContext = LLVMVoidTypeInContext; | ||
| 151 | extern fn LLVMVoidTypeInContext(C: *Context) ?*Type; | ||
| 152 | |||
| 153 | pub const ContextCreate = LLVMContextCreate; | ||
| 154 | extern fn LLVMContextCreate() ?*Context; | ||
| 155 | |||
| 156 | pub const ContextDispose = LLVMContextDispose; | ||
| 157 | extern fn LLVMContextDispose(C: *Context) void; | ||
| 158 | |||
| 159 | pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData; | ||
| 160 | extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*:0]u8; | ||
| 161 | |||
| 162 | pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout; | ||
| 163 | extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData; | ||
| 164 | |||
| 165 | pub const CreateTargetMachine = ZigLLVMCreateTargetMachine; | ||
| 166 | extern 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 | |||
| 177 | pub const GetHostCPUName = LLVMGetHostCPUName; | ||
| 178 | extern fn LLVMGetHostCPUName() ?[*:0]u8; | ||
| 179 | |||
| 180 | pub const GetNativeFeatures = ZigLLVMGetNativeFeatures; | ||
| 181 | extern fn ZigLLVMGetNativeFeatures() ?[*:0]u8; | ||
| 182 | |||
| 183 | pub const GetElementType = LLVMGetElementType; | ||
| 184 | extern fn LLVMGetElementType(Ty: *Type) *Type; | ||
| 185 | |||
| 186 | pub const TypeOf = LLVMTypeOf; | ||
| 187 | extern fn LLVMTypeOf(Val: *Value) *Type; | ||
| 188 | |||
| 189 | pub const BuildStore = LLVMBuildStore; | ||
| 190 | extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value; | ||
| 191 | |||
| 192 | pub const BuildAlloca = LLVMBuildAlloca; | ||
| 193 | extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*:0]const u8) ?*Value; | ||
| 194 | |||
| 195 | pub const ConstInBoundsGEP = LLVMConstInBoundsGEP; | ||
| 196 | pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value; | ||
| 197 | |||
| 198 | pub const GetTargetFromTriple = LLVMGetTargetFromTriple; | ||
| 199 | extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **Target, ErrorMessage: ?*[*:0]u8) Bool; | ||
| 200 | |||
| 201 | pub const VerifyModule = LLVMVerifyModule; | ||
| 202 | extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*:0]u8) Bool; | ||
| 203 | |||
| 204 | pub const GetInsertBlock = LLVMGetInsertBlock; | ||
| 205 | extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock; | ||
| 206 | |||
| 207 | pub const FunctionType = LLVMFunctionType; | ||
| 208 | extern fn LLVMFunctionType( | ||
| 209 | ReturnType: *Type, | ||
| 210 | ParamTypes: [*]*Type, | ||
| 211 | ParamCount: c_uint, | ||
| 212 | IsVarArg: Bool, | ||
| 213 | ) ?*Type; | ||
| 214 | |||
| 215 | pub const GetParam = LLVMGetParam; | ||
| 216 | extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value; | ||
| 217 | |||
| 218 | pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext; | ||
| 219 | extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*:0]const u8) ?*BasicBlock; | ||
| 220 | |||
| 221 | pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd; | ||
| 222 | extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void; | ||
| 223 | |||
| 224 | pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction; | ||
| 225 | pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; | ||
| 226 | pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction; | ||
| 227 | pub const VerifierFailureAction = c.LLVMVerifierFailureAction; | ||
| 228 | |||
| 229 | pub const CodeGenLevelNone = CodeGenOptLevel.LLVMCodeGenLevelNone; | ||
| 230 | pub const CodeGenLevelLess = CodeGenOptLevel.LLVMCodeGenLevelLess; | ||
| 231 | pub const CodeGenLevelDefault = CodeGenOptLevel.LLVMCodeGenLevelDefault; | ||
| 232 | pub const CodeGenLevelAggressive = CodeGenOptLevel.LLVMCodeGenLevelAggressive; | ||
| 233 | pub const CodeGenOptLevel = c.LLVMCodeGenOptLevel; | ||
| 234 | |||
| 235 | pub const RelocDefault = RelocMode.LLVMRelocDefault; | ||
| 236 | pub const RelocStatic = RelocMode.LLVMRelocStatic; | ||
| 237 | pub const RelocPIC = RelocMode.LLVMRelocPIC; | ||
| 238 | pub const RelocDynamicNoPic = RelocMode.LLVMRelocDynamicNoPic; | ||
| 239 | pub const RelocMode = c.LLVMRelocMode; | ||
| 240 | |||
| 241 | pub const CodeModelDefault = CodeModel.LLVMCodeModelDefault; | ||
| 242 | pub const CodeModelJITDefault = CodeModel.LLVMCodeModelJITDefault; | ||
| 243 | pub const CodeModelSmall = CodeModel.LLVMCodeModelSmall; | ||
| 244 | pub const CodeModelKernel = CodeModel.LLVMCodeModelKernel; | ||
| 245 | pub const CodeModelMedium = CodeModel.LLVMCodeModelMedium; | ||
| 246 | pub const CodeModelLarge = CodeModel.LLVMCodeModelLarge; | ||
| 247 | pub const CodeModel = c.LLVMCodeModel; | ||
| 248 | |||
| 249 | pub const EmitAssembly = EmitOutputType.ZigLLVM_EmitAssembly; | ||
| 250 | pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary; | ||
| 251 | pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr; | ||
| 252 | pub const EmitOutputType = c.ZigLLVM_EmitOutputType; | ||
| 253 | |||
| 254 | pub const CCallConv = CallConv.LLVMCCallConv; | ||
| 255 | pub const FastCallConv = CallConv.LLVMFastCallConv; | ||
| 256 | pub const ColdCallConv = CallConv.LLVMColdCallConv; | ||
| 257 | pub const WebKitJSCallConv = CallConv.LLVMWebKitJSCallConv; | ||
| 258 | pub const AnyRegCallConv = CallConv.LLVMAnyRegCallConv; | ||
| 259 | pub const X86StdcallCallConv = CallConv.LLVMX86StdcallCallConv; | ||
| 260 | pub const X86FastcallCallConv = CallConv.LLVMX86FastcallCallConv; | ||
| 261 | pub const CallConv = c.LLVMCallConv; | ||
| 262 | |||
| 263 | pub const CallAttr = extern enum { | ||
| 264 | Auto, | ||
| 265 | NeverTail, | ||
| 266 | NeverInline, | ||
| 267 | AlwaysTail, | ||
| 268 | AlwaysInline, | ||
| 269 | }; | ||
| 270 | |||
| 271 | fn removeNullability(comptime T: type) type { | ||
| 272 | comptime assert(@typeInfo(T).Pointer.size == .C); | ||
| 273 | return *T.Child; | ||
| 274 | } | ||
| 275 | |||
| 276 | pub const BuildRet = LLVMBuildRet; | ||
| 277 | extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value; | ||
| 278 | |||
| 279 | pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile; | ||
| 280 | extern 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; |
| 289 | 12 | ||
| 290 | pub const BuildCall = ZigLLVMBuildCall; | 13 | pub const ZigLLVM_ObjectFormatType = extern enum(c_int) { |
| 291 | extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: CallConv, fn_inline: CallAttr, Name: [*:0]const u8) ?*Value; | 14 | Unknown, |
| 292 | 15 | COFF, | |
| 293 | pub 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 off | 191 | \\ ReleaseSmall Optimize for small binary, safety off |
| 192 | \\ -fPIC Force-enable Position Independent Code | 192 | \\ -fPIC Force-enable Position Independent Code |
| 193 | \\ -fno-PIC Force-disable Position Independent Code | 193 | \\ -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 symbols | 200 | \\ --strip Exclude debug symbols |
| 201 | \\ --single-threaded Code assumes it is only used single-threaded | ||
| 195 | \\ -ofmt=[mode] Override target object format | 202 | \\ -ofmt=[mode] Override target object format |
| 196 | \\ elf Executable and Linking Format | 203 | \\ elf Executable and Linking Format |
| 197 | \\ c Compile to C source code | 204 | \\ 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(); |
| 322 | 332 | ||
| 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(); |
| 325 | 335 | ||
| 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") or | 570 | } else if (mem.endsWith(u8, arg, ".so") or |
| 546 | mem.endsWith(u8, arg, ".dylib") or | 571 | 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 | }; |
| 968 | 993 | ||
| 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 | }; |
| 983 | 1060 | ||
| 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 | }; |
| 996 | 1073 | ||
| 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 | }; | ||
| 1005 | 1076 | ||
| 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(); |
| 1011 | 1082 | ||
| 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 | } |
| 1027 | 1098 | ||
| 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 | } |
| 1122 | 1212 | ||
| 1123 | fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void { | 1213 | fn 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(); | ||
| 1127 | 1215 | ||
| 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"); |
| 2 | const build_options = @import("build_options"); | 2 | const build_options = @import("build_options"); |
| 3 | const introspect = @import("introspect.zig"); | 3 | const introspect = @import("introspect.zig"); |
| 4 | const Allocator = std.mem.Allocator; | 4 | const Allocator = std.mem.Allocator; |
| 5 | const fatal = @import("main.zig").fatal; | ||
| 5 | 6 | ||
| 6 | pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void { | 7 | pub 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(); | ||
| 12 | 16 | ||
| 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); |
| 15 | 19 | ||
| 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(); |
| 24 | 28 | ||
| 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.?); |
| 27 | 34 | ||
| 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.?); | ||
| 24 | 25 | ||
| 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); | ||
| 30 | 28 | ||
| 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 | } |
| 119 | 119 | ||
| 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. | ||
| 120 | pub fn osRequiresLibC(target: std.Target) bool { | 123 | pub 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 | } |
| 133 | 133 | ||
| 134 | /// This function returns whether non-pic code is completely invalid on the given target. | ||
| 135 | pub 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. | ||
| 144 | pub fn supports_fpic(target: std.Target) bool { | ||
| 145 | return target.os.tag != .windows; | ||
| 146 | } | ||
| 147 | |||
| 134 | pub fn libc_needs_crti_crtn(target: std.Target) bool { | 148 | pub 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 | |||
| 152 | pub fn isSingleThreaded(target: std.Target) bool { | ||
| 153 | return target.isWasm(); | ||
| 154 | } | ||
| 155 | |||
| 156 | /// Valgrind supports more, but Zig does not support them yet. | ||
| 157 | pub 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 | |||
| 167 | pub 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(); |
| 409 | 409 | ||
| 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.?); | ||
| 412 | 413 | ||
| 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; |
| 429 | 430 | ||
| 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 | } |
| 433 | 434 | ||
| ... | @@ -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(); |
| 451 | 452 | ||
| 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); |
| 455 | 464 | ||
| 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); |
| 458 | 467 | ||
| 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 optimizations | 486 | // 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, |