@@ -17,8 +17,10 @@ pub fn build(b: *std.Build) !void {
1717
1818 const prebuilt_v8_path = b .option ([]const u8 , "prebuilt_v8_path" , "Path to prebuilt libc_v8.a" );
1919
20- const prepared_v8 = try prepareV8Sources (b );
21- const bootstrapped_v8 = bootstrapV8 (b , prepared_v8 );
20+ const cache_root = b .cache_root .path orelse ".zig-cache" ;
21+ const v8_dir = b .fmt ("{s}/v8-{s}" , .{ cache_root , V8_VERSION });
22+
23+ const bootstrapped_v8 = try bootstrapV8 (b , v8_dir );
2224
2325 const built_v8 = if (prebuilt_v8_path ) | path | blk : {
2426 // Use prebuilt_v8 if available.
@@ -27,11 +29,10 @@ pub fn build(b: *std.Build) !void {
2729 break :blk wf ;
2830 } else blk : {
2931 // Otherwise, go through build process.
30- break :blk try buildV8 (b , prepared_v8 , bootstrapped_v8 , target , optimize );
32+ break :blk try buildV8 (b , v8_dir , bootstrapped_v8 , target , optimize );
3133 };
3234
3335 const prepare_step = b .step ("prepare-v8" , "Prepare V8 source code" );
34- prepare_step .dependOn (& prepared_v8 .step );
3536 prepare_step .dependOn (& bootstrapped_v8 .step );
3637
3738 const build_step = b .step ("build-v8" , "Build v8" );
@@ -98,10 +99,96 @@ pub fn build(b: *std.Build) !void {
9899 }
99100}
100101
101- fn prepareV8Sources (b : * std.Build ) ! * std.Build.Step.WriteFile {
102- const wf = b .addWriteFiles ();
102+ fn bootstrapV8 (b : * std.Build , v8_dir : []const u8 ) ! * std.Build.Step.Run {
103+ const depot_tools = b .dependency ("depot_tools" , .{});
104+ const marker_file = b .fmt ("{s}/.bootstrap-complete" , .{v8_dir });
105+
106+ // Check if already bootstrapped
107+ const needs_full_bootstrap = blk : {
108+ std .fs .cwd ().access (marker_file , .{}) catch break :blk true ;
109+ break :blk false ;
110+ };
111+
112+ if (! needs_full_bootstrap ) {
113+ const needs_source_update = blk : {
114+ if (needs_full_bootstrap ) break :blk false ;
115+
116+ // Check if marker exists
117+ const marker_stat = std .fs .cwd ().statFile (marker_file ) catch break :blk true ;
118+ const marker_mtime = marker_stat .mtime ;
119+
120+ const source_dirs = [_ ][]const u8 { "src" , "build-tools" };
121+
122+ for (source_dirs ) | dir_path | {
123+ var dir = try std .fs .cwd ().openDir (dir_path , .{ .iterate = true });
124+ defer dir .close ();
125+
126+ var walker = try dir .walk (b .allocator );
127+ while (try walker .next ()) | entry | {
128+ switch (entry .kind ) {
129+ .file = > {
130+ const file = try entry .dir .openFile (entry .path , .{});
131+ defer file .close ();
132+ const stat = try file .stat ();
133+ const mtime = stat .mtime ;
134+
135+ if (mtime > marker_mtime ) {
136+ std .debug .print ("Source file {s} changed, updating bootstrap\n " , .{entry .path });
137+ break :blk true ;
138+ }
139+ },
140+ // Doesn't currently search into subfolders.
141+ else = > {},
142+ }
143+ }
144+ }
145+
146+ break :blk false ;
147+ };
148+
149+ if (needs_source_update ) {
150+ // Just needs the bindings to be updated, will reuse cached dir.
151+ std .debug .print ("Updating source files in V8 bootstrap\n " , .{});
152+
153+ // Just copy the updated files
154+ const copy_binding = b .addSystemCommand (&.{"cp" });
155+ copy_binding .addFileArg (b .path ("src/binding.cpp" ));
156+ copy_binding .addArg (b .fmt ("{s}/binding.cpp" , .{v8_dir }));
157+
158+ const copy_inspector = b .addSystemCommand (&.{"cp" });
159+ copy_inspector .addFileArg (b .path ("src/inspector.h" ));
160+ copy_inspector .addArg (b .fmt ("{s}/inspector.h" , .{v8_dir }));
161+ copy_inspector .step .dependOn (& copy_binding .step );
162+
163+ const copy_build_gn = b .addSystemCommand (&.{"cp" });
164+ copy_build_gn .addFileArg (b .path ("build-tools/BUILD.gn" ));
165+ copy_build_gn .addArg (b .fmt ("{s}/zig/BUILD.gn" , .{v8_dir }));
166+ copy_build_gn .step .dependOn (& copy_inspector .step );
167+
168+ const copy_gn = b .addSystemCommand (&.{"cp" });
169+ copy_gn .addFileArg (b .path ("build-tools/.gn" ));
170+ copy_gn .addArg (b .fmt ("{s}/zig/.gn" , .{v8_dir }));
171+ copy_gn .step .dependOn (& copy_build_gn .step );
172+
173+ // Touch marker to update timestamp
174+ const update_marker = b .addSystemCommand (&.{ "touch" , marker_file });
175+ update_marker .step .dependOn (& copy_gn .step );
176+
177+ return update_marker ;
178+ } else {
179+ // Cached V8 is still valid.
180+ std .debug .print ("Using cached V8 bootstrap from {s}\n " , .{v8_dir });
181+ const noop = b .addSystemCommand (&.{"true" });
182+ return noop ;
183+ }
184+ }
185+
186+ std .debug .print ("Bootstrapping V8 {s} in {s} (this will take a while)...\n " , .{ V8_VERSION , v8_dir });
187+
188+ // Create cache directory
189+ const mkdir = b .addSystemCommand (&.{ "mkdir" , "-p" , v8_dir });
103190
104- // Create .gclient file for gclient
191+ // Write .gclient file
105192 const gclient_content = b .fmt (
106193 \\solutions = [
107194 \\ {{
@@ -114,54 +201,72 @@ fn prepareV8Sources(b: *std.Build) !*std.Build.Step.WriteFile {
114201 \\]
115202 \\
116203 , .{V8_VERSION });
117- _ = wf .add (".gclient" , gclient_content );
118204
119- // Copy binding files
120- _ = wf .addCopyFile (b .path ("src/binding.cpp" ), "binding.cpp" );
121- _ = wf .addCopyFile (b .path ("src/inspector.h" ), "inspector.h" );
122- // Copy build configuration
123- _ = wf .addCopyFile (b .path ("build-tools/BUILD.gn" ), "zig/BUILD.gn" );
124- // Not sure if it's a Zig bug or intended behavior but, addCopyFile won't
125- // overwrite the original .gn. This means we put it in here and just call it from there.
126- _ = wf .addCopyFile (b .path ("build-tools/.gn" ), "zig/.gn" );
127- // Generate gclient_args.gni
128- _ = wf .add ("build/config/gclient_args.gni" ,
129- \\# Generated by Zig build system
130- \\
131- );
132- return wf ;
133- }
134-
135- fn bootstrapV8 (b : * std.Build , prepared_v8 : * std.Build.Step.WriteFile ) * std.Build.Step.Run {
136- const depot_tools = b .dependency ("depot_tools" , .{});
205+ const write_gclient = b .addSystemCommand (&.{ "sh" , "-c" });
206+ write_gclient .addArg (b .fmt ("echo '{s}' > {s}/.gclient" , .{ gclient_content , v8_dir }));
207+ write_gclient .step .dependOn (& mkdir .step );
137208
138- // Sync dependencies for this version
209+ // Copy binding files
210+ const copy_binding = b .addSystemCommand (&.{"cp" });
211+ copy_binding .addFileArg (b .path ("src/binding.cpp" ));
212+ copy_binding .addArg (b .fmt ("{s}/binding.cpp" , .{v8_dir }));
213+ copy_binding .step .dependOn (& write_gclient .step );
214+
215+ const copy_inspector = b .addSystemCommand (&.{"cp" });
216+ copy_inspector .addFileArg (b .path ("src/inspector.h" ));
217+ copy_inspector .addArg (b .fmt ("{s}/inspector.h" , .{v8_dir }));
218+ copy_inspector .step .dependOn (& copy_binding .step );
219+
220+ // Create zig directory and copy build files
221+ const mkdir_zig = b .addSystemCommand (&.{ "mkdir" , "-p" , b .fmt ("{s}/zig" , .{v8_dir }) });
222+ mkdir_zig .step .dependOn (& copy_inspector .step );
223+
224+ const copy_build_gn = b .addSystemCommand (&.{"cp" });
225+ copy_build_gn .addFileArg (b .path ("build-tools/BUILD.gn" ));
226+ copy_build_gn .addArg (b .fmt ("{s}/zig/BUILD.gn" , .{v8_dir }));
227+ copy_build_gn .step .dependOn (& mkdir_zig .step );
228+
229+ const copy_gn = b .addSystemCommand (&.{"cp" });
230+ copy_gn .addFileArg (b .path ("build-tools/.gn" ));
231+ copy_gn .addArg (b .fmt ("{s}/zig/.gn" , .{v8_dir }));
232+ copy_gn .step .dependOn (& copy_build_gn .step );
233+
234+ // Create gclient_args.gni
235+ const mkdir_build_config = b .addSystemCommand (&.{ "mkdir" , "-p" , b .fmt ("{s}/build/config" , .{v8_dir }) });
236+ mkdir_build_config .step .dependOn (& copy_gn .step );
237+
238+ const write_gclient_args = b .addSystemCommand (&.{ "sh" , "-c" });
239+ write_gclient_args .addArg (b .fmt ("echo '# Generated by Zig build system' > {s}/build/config/gclient_args.gni" , .{v8_dir }));
240+ write_gclient_args .step .dependOn (& mkdir_build_config .step );
241+
242+ // Run gclient sync
139243 var gclient_sync = std .Build .Step .Run .create (b , "run gclient sync" );
140244 gclient_sync .addFileArg (depot_tools .path ("gclient" ));
141245 gclient_sync .addArgs (&.{"sync" });
142- // gclient_sync.setEnvironmentVariable("DEPOT_TOOLS_UPDATE", "0");
143- gclient_sync .setCwd (prepared_v8 .getDirectory ());
144- gclient_sync .step .dependOn (& prepared_v8 .step );
145-
146- // Run clang update script after copying
147- const clang_update = b .addSystemCommand (&.{
148- "python3" ,
149- "tools/clang/scripts/update.py" ,
150- });
151- clang_update .setCwd (prepared_v8 .getDirectory ());
246+ gclient_sync .setCwd (.{ .cwd_relative = v8_dir });
247+ gclient_sync .step .dependOn (& write_gclient_args .step );
248+
249+ // Run clang update
250+ const clang_update = b .addSystemCommand (&.{ "python3" , "tools/clang/scripts/update.py" });
251+ clang_update .setCwd (.{ .cwd_relative = v8_dir });
152252 clang_update .step .dependOn (& gclient_sync .step );
153- return clang_update ;
253+
254+ // Create marker file
255+ const create_marker = b .addSystemCommand (&.{ "touch" , marker_file });
256+ create_marker .step .dependOn (& clang_update .step );
257+
258+ return create_marker ;
154259}
155260
156261fn buildV8 (
157262 b : * std.Build ,
158- prepared_v8 : * std.Build.Step.WriteFile ,
263+ v8_cache : [] const u8 ,
159264 bootstrapped_v8 : * std.Build.Step.Run ,
160265 target : std.Build.ResolvedTarget ,
161266 optimize : std.builtin.OptimizeMode ,
162267) ! * std.Build.Step.WriteFile {
163268 const depot_tools = b .dependency ("depot_tools" , .{});
164- const v8_dir = prepared_v8 . getDirectory () ;
269+ const v8_dir : LazyPath = .{ . cwd_relative = v8_cache } ;
165270
166271 const allocator = b .allocator ;
167272
@@ -199,29 +304,31 @@ fn buildV8(
199304 else = > {},
200305 }
201306
307+ const out_dir = b .fmt ("out/{s}/{s}" , .{ @tagName (tag ), if (is_debug ) "debug" else "release" });
308+
202309 var gn_run = std .Build .Step .Run .create (b , "run gn" );
203310 gn_run .addFileArg (depot_tools .path ("gn" ));
204311 gn_run .addArgs (&.{
205312 "--root=." ,
206313 "--root-target=//zig" ,
207314 "--dotfile=zig/.gn" ,
208315 "gen" ,
209- "out" ,
316+ out_dir ,
210317 b .fmt ("--args={s}" , .{gn_args .items }),
211318 });
212319 gn_run .setCwd (v8_dir );
213- gn_run .step .dependOn (& prepared_v8 .step );
214320 gn_run .step .dependOn (& bootstrapped_v8 .step );
215321
216322 var ninja_run = std .Build .Step .Run .create (b , "run ninja" );
217323 ninja_run .addFileArg (depot_tools .path ("ninja" ));
218- ninja_run .addArgs (&.{ "-C" , "out" , "c_v8" });
324+ ninja_run .addArgs (&.{ "-C" , out_dir , "c_v8" });
219325 ninja_run .setCwd (v8_dir );
220326 ninja_run .step .dependOn (& gn_run .step );
221327
222328 const wf = b .addWriteFiles ();
223329 wf .step .dependOn (& ninja_run .step );
224- _ = wf .addCopyFile (v8_dir .path (b , "out/obj/zig/libc_v8.a" ), "libc_v8.a" );
330+ const libc_v8_path = b .fmt ("{s}/obj/zig/libc_v8.a" , .{out_dir });
331+ _ = wf .addCopyFile (v8_dir .path (b , libc_v8_path ), "libc_v8.a" );
225332
226333 return wf ;
227334}
0 commit comments