| ... | @@ -27,7 +27,8 @@ gpa: *Allocator, | ... | @@ -27,7 +27,8 @@ gpa: *Allocator, |
| 27 | arena_state: std.heap.ArenaAllocator.State, | 27 | arena_state: std.heap.ArenaAllocator.State, |
| 28 | bin_file: *link.File, | 28 | bin_file: *link.File, |
| 29 | c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, | 29 | c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, |
| 30 | stage1_module: ?*stage1.Module, | 30 | stage1_lock: ?Cache.Lock = null, |
| | 31 | stage1_cache_hash: *Cache.CacheHash = undefined, |
| 31 | | 32 | |
| 32 | link_error_flags: link.File.ErrorFlags = .{}, | 33 | link_error_flags: link.File.ErrorFlags = .{}, |
| 33 | | 34 | |
| ... | @@ -54,6 +55,7 @@ verbose_cimport: bool, | ... | @@ -54,6 +55,7 @@ verbose_cimport: bool, |
| 54 | verbose_llvm_cpu_features: bool, | 55 | verbose_llvm_cpu_features: bool, |
| 55 | disable_c_depfile: bool, | 56 | disable_c_depfile: bool, |
| 56 | is_test: bool, | 57 | is_test: bool, |
| | 58 | time_report: bool, |
| 57 | | 59 | |
| 58 | c_source_files: []const CSourceFile, | 60 | c_source_files: []const CSourceFile, |
| 59 | clang_argv: []const []const u8, | 61 | clang_argv: []const []const u8, |
| ... | @@ -91,6 +93,10 @@ crt_files: std.StringHashMapUnmanaged(CRTFile) = .{}, | ... | @@ -91,6 +93,10 @@ crt_files: std.StringHashMapUnmanaged(CRTFile) = .{}, |
| 91 | /// Keeping track of this possibly open resource so we can close it later. | 93 | /// Keeping track of this possibly open resource so we can close it later. |
| 92 | owned_link_dir: ?std.fs.Dir, | 94 | owned_link_dir: ?std.fs.Dir, |
| 93 | | 95 | |
| | 96 | /// This is for stage1 and should be deleted upon completion of self-hosting. |
| | 97 | /// Don't use this for anything other than stage1 compatibility. |
| | 98 | color: @import("main.zig").Color = .Auto, |
| | 99 | |
| 94 | pub const InnerError = Module.InnerError; | 100 | pub const InnerError = Module.InnerError; |
| 95 | | 101 | |
| 96 | pub const CRTFile = struct { | 102 | pub const CRTFile = struct { |
| ... | @@ -643,100 +649,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -643,100 +649,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 643 | .ReleaseFast, .ReleaseSmall => false, | 649 | .ReleaseFast, .ReleaseSmall => false, |
| 644 | }; | 650 | }; |
| 645 | | 651 | |
| 646 | const stage1_module: ?*stage1.Module = if (build_options.is_stage1 and use_llvm) blk: { | | |
| 647 | // Here we use the legacy stage1 C++ compiler to compile Zig code. | | |
| 648 | const stage2_target = try arena.create(stage1.Stage2Target); | | |
| 649 | stage2_target.* = .{ | | |
| 650 | .arch = @enumToInt(options.target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch | | |
| 651 | .os = @enumToInt(options.target.os.tag), | | |
| 652 | .abi = @enumToInt(options.target.abi), | | |
| 653 | .is_native_os = options.is_native_os, | | |
| 654 | .is_native_cpu = false, // Only true when bootstrapping the compiler. | | |
| 655 | .llvm_cpu_name = if (options.target.cpu.model.llvm_name) |s| s.ptr else null, | | |
| 656 | .llvm_cpu_features = llvm_cpu_features.?, | | |
| 657 | }; | | |
| 658 | const progress = try arena.create(std.Progress); | | |
| 659 | const main_progress_node = try progress.start("", 100); | | |
| 660 | if (options.color == .Off) progress.terminal = null; | | |
| 661 | | | |
| 662 | const mod = module.?; | | |
| 663 | const main_zig_file = try mod.root_pkg.root_src_directory.join(arena, &[_][]const u8{ | | |
| 664 | mod.root_pkg.root_src_path, | | |
| 665 | }); | | |
| 666 | const zig_lib_dir = options.zig_lib_directory.path.?; | | |
| 667 | const builtin_sub = &[_][]const u8{"builtin.zig"}; | | |
| 668 | const builtin_zig_path = try mod.zig_cache_artifact_directory.join(arena, builtin_sub); | | |
| 669 | | | |
| 670 | const stage1_module = stage1.create( | | |
| 671 | @enumToInt(options.optimize_mode), | | |
| 672 | undefined, | | |
| 673 | 0, // TODO --main-pkg-path | | |
| 674 | main_zig_file.ptr, | | |
| 675 | main_zig_file.len, | | |
| 676 | zig_lib_dir.ptr, | | |
| 677 | zig_lib_dir.len, | | |
| 678 | stage2_target, | | |
| 679 | options.is_test, | | |
| 680 | ) orelse return error.OutOfMemory; | | |
| 681 | | | |
| 682 | const output_dir = bin_directory.path orelse "."; | | |
| 683 | | | |
| 684 | const stage1_pkg = try arena.create(stage1.Pkg); | | |
| 685 | stage1_pkg.* = .{ | | |
| 686 | .name_ptr = undefined, | | |
| 687 | .name_len = 0, | | |
| 688 | .path_ptr = undefined, | | |
| 689 | .path_len = 0, | | |
| 690 | .children_ptr = undefined, | | |
| 691 | .children_len = 0, | | |
| 692 | .parent = null, | | |
| 693 | }; | | |
| 694 | | | |
| 695 | stage1_module.* = .{ | | |
| 696 | .root_name_ptr = root_name.ptr, | | |
| 697 | .root_name_len = root_name.len, | | |
| 698 | .output_dir_ptr = output_dir.ptr, | | |
| 699 | .output_dir_len = output_dir.len, | | |
| 700 | .builtin_zig_path_ptr = builtin_zig_path.ptr, | | |
| 701 | .builtin_zig_path_len = builtin_zig_path.len, | | |
| 702 | .test_filter_ptr = "", | | |
| 703 | .test_filter_len = 0, | | |
| 704 | .test_name_prefix_ptr = "", | | |
| 705 | .test_name_prefix_len = 0, | | |
| 706 | .userdata = @ptrToInt(comp), | | |
| 707 | .root_pkg = stage1_pkg, | | |
| 708 | .code_model = @enumToInt(options.machine_code_model), | | |
| 709 | .subsystem = stage1.TargetSubsystem.Auto, | | |
| 710 | .err_color = @enumToInt(options.color), | | |
| 711 | .pic = pic, | | |
| 712 | .link_libc = options.link_libc, | | |
| 713 | .link_libcpp = options.link_libcpp, | | |
| 714 | .strip = options.strip, | | |
| 715 | .is_single_threaded = single_threaded, | | |
| 716 | .dll_export_fns = dll_export_fns, | | |
| 717 | .link_mode_dynamic = link_mode == .Dynamic, | | |
| 718 | .valgrind_enabled = valgrind, | | |
| 719 | .function_sections = function_sections, | | |
| 720 | .enable_stack_probing = stack_check, | | |
| 721 | .enable_time_report = options.time_report, | | |
| 722 | .enable_stack_report = false, | | |
| 723 | .dump_analysis = false, | | |
| 724 | .enable_doc_generation = false, | | |
| 725 | .emit_bin = true, | | |
| 726 | .emit_asm = false, | | |
| 727 | .emit_llvm_ir = false, | | |
| 728 | .test_is_evented = false, | | |
| 729 | .verbose_tokenize = options.verbose_tokenize, | | |
| 730 | .verbose_ast = options.verbose_ast, | | |
| 731 | .verbose_ir = options.verbose_ir, | | |
| 732 | .verbose_llvm_ir = options.verbose_llvm_ir, | | |
| 733 | .verbose_cimport = options.verbose_cimport, | | |
| 734 | .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features, | | |
| 735 | .main_progress_node = main_progress_node, | | |
| 736 | }; | | |
| 737 | break :blk stage1_module; | | |
| 738 | } else null; | | |
| 739 | | | |
| 740 | const bin_file = try link.File.openPath(gpa, .{ | 652 | const bin_file = try link.File.openPath(gpa, .{ |
| 741 | .directory = bin_directory, | 653 | .directory = bin_directory, |
| 742 | .sub_path = emit_bin.basename, | 654 | .sub_path = emit_bin.basename, |
| ... | @@ -793,7 +705,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -793,7 +705,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 793 | .zig_lib_directory = options.zig_lib_directory, | 705 | .zig_lib_directory = options.zig_lib_directory, |
| 794 | .zig_cache_directory = options.zig_cache_directory, | 706 | .zig_cache_directory = options.zig_cache_directory, |
| 795 | .bin_file = bin_file, | 707 | .bin_file = bin_file, |
| 796 | .stage1_module = stage1_module, | | |
| 797 | .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), | 708 | .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), |
| 798 | .keep_source_files_loaded = options.keep_source_files_loaded, | 709 | .keep_source_files_loaded = options.keep_source_files_loaded, |
| 799 | .use_clang = use_clang, | 710 | .use_clang = use_clang, |
| ... | @@ -815,6 +726,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -815,6 +726,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 815 | .disable_c_depfile = options.disable_c_depfile, | 726 | .disable_c_depfile = options.disable_c_depfile, |
| 816 | .owned_link_dir = owned_link_dir, | 727 | .owned_link_dir = owned_link_dir, |
| 817 | .is_test = options.is_test, | 728 | .is_test = options.is_test, |
| | 729 | .color = options.color, |
| | 730 | .time_report = options.time_report, |
| 818 | }; | 731 | }; |
| 819 | break :comp comp; | 732 | break :comp comp; |
| 820 | }; | 733 | }; |
| ... | @@ -845,7 +758,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -845,7 +758,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 845 | if (comp.wantBuildLibUnwindFromSource()) { | 758 | if (comp.wantBuildLibUnwindFromSource()) { |
| 846 | try comp.work_queue.writeItem(.{ .libunwind = {} }); | 759 | try comp.work_queue.writeItem(.{ .libunwind = {} }); |
| 847 | } | 760 | } |
| 848 | if (comp.stage1_module) |module| { | 761 | if (build_options.is_stage1 and comp.bin_file.options.use_llvm) { |
| 849 | try comp.work_queue.writeItem(.{ .stage1_module = {} }); | 762 | try comp.work_queue.writeItem(.{ .stage1_module = {} }); |
| 850 | } | 763 | } |
| 851 | if (is_exe_or_dyn_lib) { | 764 | if (is_exe_or_dyn_lib) { |
| ... | @@ -858,15 +771,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -858,15 +771,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 858 | return comp; | 771 | return comp; |
| 859 | } | 772 | } |
| 860 | | 773 | |
| | 774 | fn releaseStage1Lock(comp: *Compilation) void { |
| | 775 | if (comp.stage1_lock) |*lock| { |
| | 776 | lock.release(); |
| | 777 | comp.stage1_lock = null; |
| | 778 | } |
| | 779 | } |
| | 780 | |
| 861 | pub fn destroy(self: *Compilation) void { | 781 | pub fn destroy(self: *Compilation) void { |
| 862 | const optional_module = self.bin_file.options.module; | 782 | const optional_module = self.bin_file.options.module; |
| 863 | self.bin_file.destroy(); | 783 | self.bin_file.destroy(); |
| 864 | if (optional_module) |module| module.deinit(); | 784 | if (optional_module) |module| module.deinit(); |
| 865 | | 785 | |
| 866 | if (self.stage1_module) |module| { | 786 | self.releaseStage1Lock(); |
| 867 | module.main_progress_node.?.end(); | | |
| 868 | module.destroy(); | | |
| 869 | } | | |
| 870 | | 787 | |
| 871 | const gpa = self.gpa; | 788 | const gpa = self.gpa; |
| 872 | self.work_queue.deinit(); | 789 | self.work_queue.deinit(); |
| ... | @@ -1200,8 +1117,9 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void { | ... | @@ -1200,8 +1117,9 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void { |
| 1200 | }; | 1117 | }; |
| 1201 | }, | 1118 | }, |
| 1202 | .stage1_module => { | 1119 | .stage1_module => { |
| 1203 | // This Job is only queued up if there is a zig module. | 1120 | self.updateStage1Module() catch |err| { |
| 1204 | self.stage1_module.?.build_object(); | 1121 | fatal("unable to build stage1 zig object: {}", .{@errorName(err)}); |
| | 1122 | }; |
| 1205 | }, | 1123 | }, |
| 1206 | }; | 1124 | }; |
| 1207 | } | 1125 | } |
| ... | @@ -2174,3 +2092,155 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil | ... | @@ -2174,3 +2092,155 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil |
| 2174 | .lock = sub_compilation.bin_file.toOwnedLock(), | 2092 | .lock = sub_compilation.bin_file.toOwnedLock(), |
| 2175 | }; | 2093 | }; |
| 2176 | } | 2094 | } |
| | 2095 | |
| | 2096 | fn updateStage1Module(comp: *Compilation) !void { |
| | 2097 | const tracy = trace(@src()); |
| | 2098 | defer tracy.end(); |
| | 2099 | |
| | 2100 | var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); |
| | 2101 | defer arena_allocator.deinit(); |
| | 2102 | const arena = &arena_allocator.allocator; |
| | 2103 | |
| | 2104 | // Here we use the legacy stage1 C++ compiler to compile Zig code. |
| | 2105 | const mod = comp.bin_file.options.module.?; |
| | 2106 | const directory = mod.zig_cache_artifact_directory; // Just an alias to make it shorter to type. |
| | 2107 | const main_zig_file = try mod.root_pkg.root_src_directory.join(arena, &[_][]const u8{ |
| | 2108 | mod.root_pkg.root_src_path, |
| | 2109 | }); |
| | 2110 | const zig_lib_dir = comp.zig_lib_directory.path.?; |
| | 2111 | const builtin_zig_path = try directory.join(arena, &[_][]const u8{"builtin.zig"}); |
| | 2112 | const target = comp.getTarget(); |
| | 2113 | const id_symlink_basename = "stage1.id"; |
| | 2114 | |
| | 2115 | // We are about to obtain this lock, so here we give other processes a chance first. |
| | 2116 | comp.releaseStage1Lock(); |
| | 2117 | |
| | 2118 | // Unlike with the self-hosted Zig module, stage1 does not support incremental compilation, |
| | 2119 | // so we input all the zig source files into the cache hash system. We're going to keep |
| | 2120 | // the artifact directory the same, however, so we take the same strategy as linking |
| | 2121 | // does where we have a file which specifies the hash of the output directory so that we can |
| | 2122 | // skip the expensive compilation step if the hash matches. |
| | 2123 | var ch = comp.cache_parent.obtain(); |
| | 2124 | defer ch.deinit(); |
| | 2125 | |
| | 2126 | _ = try ch.addFile(main_zig_file, null); |
| | 2127 | ch.hash.add(comp.bin_file.options.valgrind); |
| | 2128 | ch.hash.add(comp.bin_file.options.single_threaded); |
| | 2129 | ch.hash.add(target.os.getVersionRange()); |
| | 2130 | ch.hash.add(comp.bin_file.options.dll_export_fns); |
| | 2131 | ch.hash.add(comp.bin_file.options.function_sections); |
| | 2132 | |
| | 2133 | if (try ch.hit()) { |
| | 2134 | const digest = ch.final(); |
| | 2135 | |
| | 2136 | var prev_digest_buf: [digest.len]u8 = undefined; |
| | 2137 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { |
| | 2138 | // Handle this as a cache miss. |
| | 2139 | break :blk prev_digest_buf[0..0]; |
| | 2140 | }; |
| | 2141 | if (mem.eql(u8, prev_digest, &digest)) { |
| | 2142 | comp.stage1_lock = ch.toOwnedLock(); |
| | 2143 | return; |
| | 2144 | } |
| | 2145 | } |
| | 2146 | |
| | 2147 | const stage2_target = try arena.create(stage1.Stage2Target); |
| | 2148 | stage2_target.* = .{ |
| | 2149 | .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch |
| | 2150 | .os = @enumToInt(target.os.tag), |
| | 2151 | .abi = @enumToInt(target.abi), |
| | 2152 | .is_native_os = comp.bin_file.options.is_native_os, |
| | 2153 | .is_native_cpu = false, // Only true when bootstrapping the compiler. |
| | 2154 | .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null, |
| | 2155 | .llvm_cpu_features = comp.bin_file.options.llvm_cpu_features.?, |
| | 2156 | }; |
| | 2157 | var progress: std.Progress = .{}; |
| | 2158 | var main_progress_node = try progress.start("", 100); |
| | 2159 | defer main_progress_node.end(); |
| | 2160 | if (comp.color == .Off) progress.terminal = null; |
| | 2161 | |
| | 2162 | comp.stage1_cache_hash = &ch; |
| | 2163 | |
| | 2164 | const stage1_module = stage1.create( |
| | 2165 | @enumToInt(comp.bin_file.options.optimize_mode), |
| | 2166 | undefined, |
| | 2167 | 0, // TODO --main-pkg-path |
| | 2168 | main_zig_file.ptr, |
| | 2169 | main_zig_file.len, |
| | 2170 | zig_lib_dir.ptr, |
| | 2171 | zig_lib_dir.len, |
| | 2172 | stage2_target, |
| | 2173 | comp.is_test, |
| | 2174 | ) orelse return error.OutOfMemory; |
| | 2175 | |
| | 2176 | const stage1_pkg = try arena.create(stage1.Pkg); |
| | 2177 | stage1_pkg.* = .{ |
| | 2178 | .name_ptr = undefined, |
| | 2179 | .name_len = 0, |
| | 2180 | .path_ptr = undefined, |
| | 2181 | .path_len = 0, |
| | 2182 | .children_ptr = undefined, |
| | 2183 | .children_len = 0, |
| | 2184 | .parent = null, |
| | 2185 | }; |
| | 2186 | const output_dir = comp.bin_file.options.directory.path orelse "."; |
| | 2187 | stage1_module.* = .{ |
| | 2188 | .root_name_ptr = comp.bin_file.options.root_name.ptr, |
| | 2189 | .root_name_len = comp.bin_file.options.root_name.len, |
| | 2190 | .output_dir_ptr = output_dir.ptr, |
| | 2191 | .output_dir_len = output_dir.len, |
| | 2192 | .builtin_zig_path_ptr = builtin_zig_path.ptr, |
| | 2193 | .builtin_zig_path_len = builtin_zig_path.len, |
| | 2194 | .test_filter_ptr = "", |
| | 2195 | .test_filter_len = 0, |
| | 2196 | .test_name_prefix_ptr = "", |
| | 2197 | .test_name_prefix_len = 0, |
| | 2198 | .userdata = @ptrToInt(comp), |
| | 2199 | .root_pkg = stage1_pkg, |
| | 2200 | .code_model = @enumToInt(comp.bin_file.options.machine_code_model), |
| | 2201 | .subsystem = stage1.TargetSubsystem.Auto, |
| | 2202 | .err_color = @enumToInt(comp.color), |
| | 2203 | .pic = comp.bin_file.options.pic, |
| | 2204 | .link_libc = comp.bin_file.options.link_libc, |
| | 2205 | .link_libcpp = comp.bin_file.options.link_libcpp, |
| | 2206 | .strip = comp.bin_file.options.strip, |
| | 2207 | .is_single_threaded = comp.bin_file.options.single_threaded, |
| | 2208 | .dll_export_fns = comp.bin_file.options.dll_export_fns, |
| | 2209 | .link_mode_dynamic = comp.bin_file.options.link_mode == .Dynamic, |
| | 2210 | .valgrind_enabled = comp.bin_file.options.valgrind, |
| | 2211 | .function_sections = comp.bin_file.options.function_sections, |
| | 2212 | .enable_stack_probing = comp.bin_file.options.stack_check, |
| | 2213 | .enable_time_report = comp.time_report, |
| | 2214 | .enable_stack_report = false, |
| | 2215 | .dump_analysis = false, |
| | 2216 | .enable_doc_generation = false, |
| | 2217 | .emit_bin = true, |
| | 2218 | .emit_asm = false, |
| | 2219 | .emit_llvm_ir = false, |
| | 2220 | .test_is_evented = false, |
| | 2221 | .verbose_tokenize = comp.verbose_tokenize, |
| | 2222 | .verbose_ast = comp.verbose_ast, |
| | 2223 | .verbose_ir = comp.verbose_ir, |
| | 2224 | .verbose_llvm_ir = comp.verbose_llvm_ir, |
| | 2225 | .verbose_cimport = comp.verbose_cimport, |
| | 2226 | .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, |
| | 2227 | .main_progress_node = main_progress_node, |
| | 2228 | }; |
| | 2229 | stage1_module.build_object(); |
| | 2230 | stage1_module.destroy(); |
| | 2231 | |
| | 2232 | const digest = ch.final(); |
| | 2233 | |
| | 2234 | // Update the dangling symlink with the digest. If it fails we can continue; it only |
| | 2235 | // means that the next invocation will have an unnecessary cache miss. |
| | 2236 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { |
| | 2237 | std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)}); |
| | 2238 | }; |
| | 2239 | // Again failure here only means an unnecessary cache miss. |
| | 2240 | ch.writeManifest() catch |err| { |
| | 2241 | std.log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)}); |
| | 2242 | }; |
| | 2243 | // We hang on to this lock so that the output file path can be used without |
| | 2244 | // other processes clobbering it. |
| | 2245 | comp.stage1_lock = ch.toOwnedLock(); |
| | 2246 | } |