Commit 716b128a24

Andrew Kelley <andrew@ziglang.org>
2024-07-15 06:18:09
frontend: add -fincremental, -fno-incremental flag
Remove --debug-incremental This flag is also added to the build system. Importantly, this tells Compile step whether or not to keep the compiler running between rebuilds. It defaults off because it is currently crashing zirUpdateRefs.
1 parent abf8955
lib/compiler/build_runner.zig
@@ -72,6 +72,7 @@ pub fn main() !void {
             .query = .{},
             .result = try std.zig.system.resolveTargetQuery(.{}),
         },
+        .incremental = null,
     };
 
     graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
@@ -235,6 +236,10 @@ pub fn main() !void {
                 prominent_compile_errors = true;
             } else if (mem.eql(u8, arg, "--watch")) {
                 watch = true;
+            } else if (mem.eql(u8, arg, "-fincremental")) {
+                graph.incremental = true;
+            } else if (mem.eql(u8, arg, "-fno-incremental")) {
+                graph.incremental = false;
             } else if (mem.eql(u8, arg, "-fwine")) {
                 builder.enable_wine = true;
             } else if (mem.eql(u8, arg, "-fno-wine")) {
@@ -1216,6 +1221,8 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
         \\  --fetch                      Exit after fetching dependency tree
         \\  --watch                      Continuously rebuild when source files are modified
         \\  --debounce <ms>              Delay before rebuilding after changed file detected
+        \\     -fincremental             Enable incremental compilation
+        \\  -fno-incremental             Disable incremental compilation
         \\
         \\Project-Specific Options:
         \\
lib/std/Build/Step/Compile.zig
@@ -1679,6 +1679,8 @@ fn getZigArgs(compile: *Compile) ![][]const u8 {
         b.fmt("{}", .{err_limit}),
     });
 
+    try addFlag(&zig_args, "incremental", b.graph.incremental);
+
     try zig_args.append("--listen=-");
 
     // Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux
@@ -1750,7 +1752,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
     const maybe_output_bin_path = step.evalZigProcess(
         zig_args,
         options.progress_node,
-        options.watch,
+        (b.graph.incremental == true) and options.watch,
     ) catch |err| switch (err) {
         error.NeedCompileErrorCheck => {
             assert(compile.expect_errors != null);
lib/std/Build.zig
@@ -120,6 +120,7 @@ pub const Graph = struct {
     needed_lazy_dependencies: std.StringArrayHashMapUnmanaged(void) = .{},
     /// Information about the native target. Computed before build() is invoked.
     host: ResolvedTarget,
+    incremental: ?bool,
 };
 
 const AvailableDeps = []const struct { []const u8, []const u8 };
src/Zcu/PerThread.zig
@@ -888,7 +888,7 @@ fn getFileRootStruct(
     };
     errdefer wip_ty.cancel(ip, pt.tid);
 
-    if (zcu.comp.debug_incremental) {
+    if (zcu.comp.incremental) {
         try ip.addDependency(
             gpa,
             InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
src/Compilation.zig
@@ -169,7 +169,7 @@ time_report: bool,
 stack_report: bool,
 debug_compiler_runtime_libs: bool,
 debug_compile_errors: bool,
-debug_incremental: bool,
+incremental: bool,
 job_queued_compiler_rt_lib: bool = false,
 job_queued_compiler_rt_obj: bool = false,
 job_queued_update_builtin_zig: bool,
@@ -1134,7 +1134,7 @@ pub const CreateOptions = struct {
     verbose_llvm_cpu_features: bool = false,
     debug_compiler_runtime_libs: bool = false,
     debug_compile_errors: bool = false,
-    debug_incremental: bool = false,
+    incremental: bool = false,
     /// Normally when you create a `Compilation`, Zig will automatically build
     /// and link in required dependencies, such as compiler-rt and libc. When
     /// building such dependencies themselves, this flag must be set to avoid
@@ -1516,7 +1516,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
             .test_name_prefix = options.test_name_prefix,
             .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
             .debug_compile_errors = options.debug_compile_errors,
-            .debug_incremental = options.debug_incremental,
+            .incremental = options.incremental,
             .libcxx_abi_version = options.libcxx_abi_version,
             .root_name = root_name,
             .sysroot = sysroot,
src/main.zig
@@ -404,6 +404,8 @@ const usage_build_generic =
     \\  -h, --help                Print this help and exit
     \\  --color [auto|off|on]     Enable or disable colored error messages
     \\  -j<N>                     Limit concurrent jobs (default is to use all CPU cores)
+    \\  -fincremental             Enable incremental compilation
+    \\  -fno-incremental          Disable incremental compilation
     \\  -femit-bin[=path]         (default) Output machine code
     \\  -fno-emit-bin             Do not output machine code
     \\  -femit-asm[=path]         Output .s (assembly code)
@@ -642,7 +644,6 @@ const usage_build_generic =
     \\  --debug-log [scope]          Enable printing debug/info log messages for scope
     \\  --debug-compile-errors       Crash with helpful diagnostics at the first compile error
     \\  --debug-link-snapshot        Enable dumping of the linker's state in JSON format
-    \\  --debug-incremental          Enable experimental feature: incremental compilation
     \\
 ;
 
@@ -904,7 +905,7 @@ fn buildOutputType(
     var minor_subsystem_version: ?u16 = null;
     var mingw_unicode_entry_point: bool = false;
     var enable_link_snapshots: bool = false;
-    var debug_incremental: bool = false;
+    var opt_incremental: ?bool = null;
     var install_name: ?[]const u8 = null;
     var hash_style: link.File.Elf.HashStyle = .both;
     var entitlements: ?[]const u8 = null;
@@ -1357,8 +1358,10 @@ fn buildOutputType(
                         } else {
                             enable_link_snapshots = true;
                         }
-                    } else if (mem.eql(u8, arg, "--debug-incremental")) {
-                        debug_incremental = true;
+                    } else if (mem.eql(u8, arg, "-fincremental")) {
+                        opt_incremental = true;
+                    } else if (mem.eql(u8, arg, "-fno-incremental")) {
+                        opt_incremental = false;
                     } else if (mem.eql(u8, arg, "--entitlements")) {
                         entitlements = args_iter.nextOrFatal();
                     } else if (mem.eql(u8, arg, "-fcompiler-rt")) {
@@ -3225,6 +3228,8 @@ fn buildOutputType(
         break :b .incremental;
     };
 
+    const incremental = opt_incremental orelse false;
+
     process.raiseFileDescriptorLimit();
 
     var file_system_inputs: std.ArrayListUnmanaged(u8) = .{};
@@ -3336,7 +3341,7 @@ fn buildOutputType(
         .cache_mode = cache_mode,
         .subsystem = subsystem,
         .debug_compile_errors = debug_compile_errors,
-        .debug_incremental = debug_incremental,
+        .incremental = incremental,
         .enable_link_snapshots = enable_link_snapshots,
         .install_name = install_name,
         .entitlements = entitlements,
@@ -3443,7 +3448,7 @@ fn buildOutputType(
         updateModule(comp, color, root_prog_node) catch |err| switch (err) {
             error.SemanticAnalyzeFail => {
                 assert(listen == .none);
-                saveState(comp, debug_incremental);
+                saveState(comp, incremental);
                 process.exit(1);
             },
             else => |e| return e,
@@ -3451,7 +3456,7 @@ fn buildOutputType(
     }
     if (build_options.only_c) return cleanExit();
     try comp.makeBinFileExecutable();
-    saveState(comp, debug_incremental);
+    saveState(comp, incremental);
 
     if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: {
         // Default to using `zig run` to execute the produced .c code from `zig test`.
@@ -4032,8 +4037,8 @@ fn createModule(
     return mod;
 }
 
-fn saveState(comp: *Compilation, debug_incremental: bool) void {
-    if (debug_incremental) {
+fn saveState(comp: *Compilation, incremental: bool) void {
+    if (incremental) {
         comp.saveState() catch |err| {
             warn("unable to save incremental compilation state: {s}", .{@errorName(err)});
         };
src/Sema.zig
@@ -2726,7 +2726,7 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
     const pt = sema.pt;
     const zcu = pt.zcu;
 
-    if (!zcu.comp.debug_incremental) return false;
+    if (!zcu.comp.incremental) return false;
 
     const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu);
     const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index });
@@ -2826,7 +2826,7 @@ fn zirStructDecl(
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer pt.abortAnonDecl(new_decl_index);
 
-    if (pt.zcu.comp.debug_incremental) {
+    if (pt.zcu.comp.incremental) {
         try ip.addDependency(
             sema.gpa,
             AnalUnit.wrap(.{ .decl = new_decl_index }),
@@ -3064,7 +3064,7 @@ fn zirEnumDecl(
     new_decl.owns_tv = true;
     errdefer if (!done) pt.abortAnonDecl(new_decl_index);
 
-    if (pt.zcu.comp.debug_incremental) {
+    if (pt.zcu.comp.incremental) {
         try mod.intern_pool.addDependency(
             gpa,
             AnalUnit.wrap(.{ .decl = new_decl_index }),
@@ -3331,7 +3331,7 @@ fn zirUnionDecl(
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer pt.abortAnonDecl(new_decl_index);
 
-    if (pt.zcu.comp.debug_incremental) {
+    if (pt.zcu.comp.incremental) {
         try mod.intern_pool.addDependency(
             gpa,
             AnalUnit.wrap(.{ .decl = new_decl_index }),
@@ -3421,7 +3421,7 @@ fn zirOpaqueDecl(
     mod.declPtr(new_decl_index).owns_tv = true;
     errdefer pt.abortAnonDecl(new_decl_index);
 
-    if (pt.zcu.comp.debug_incremental) {
+    if (pt.zcu.comp.incremental) {
         try ip.addDependency(
             gpa,
             AnalUnit.wrap(.{ .decl = new_decl_index }),
@@ -38098,7 +38098,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool
 
 pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
     const zcu = sema.pt.zcu;
-    if (!zcu.comp.debug_incremental) return;
+    if (!zcu.comp.incremental) return;
 
     // Avoid creating dependencies on ourselves. This situation can arise when we analyze the fields
     // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would
src/Zcu.zig
@@ -2679,7 +2679,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
 }
 
 pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
-    if (!zcu.comp.debug_incremental) return null;
+    if (!zcu.comp.incremental) return null;
 
     if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
         log.debug("findOutdatedToAnalyze: no outdated depender", .{});