authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-14 01:28:28-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-26 19:08:50-04:00
logf63e8e802f5dc2aebe888c0051f685cab6b2571e
tree625df3909db9fdaf74cc21d481e0f16b67df3edf
parent11958a306f30268b17454a25bc365e67aad84efd

Build: implement discovered inputs


4 files changed, 372 insertions(+), 266 deletions(-)

lib/compiler/Maker/Step/Run.zig+310-252
......@@ -207,6 +207,7 @@ pub fn make(
207207 var owned_files: std.bit_set.Dynamic = .{};
208208 var inherit_files: std.ArrayList(Io.File) = .empty;
209209 var protocol_args: std.ArrayList(u8) = .empty;
210 var input_dirs: std.ArrayList(Cache.Path) = .empty;
210211 defer {
211212 for (inherit_dirs.items, 0..) |inherit_dir, inherit_dir_index|
212213 if (owned_dirs.isSet(inherit_dir_index)) inherit_dir.close(io);
......@@ -217,6 +218,7 @@ pub fn make(
217218 owned_files.deinit(gpa);
218219 inherit_files.deinit(gpa);
219220 protocol_args.deinit(gpa);
221 input_dirs.deinit(gpa);
220222 }
221223 switch (conf_run.flags.stdio) {
222224 .infer_from_args, .inherit, .check => {},
......@@ -228,257 +230,264 @@ pub fn make(
228230 argv_list.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{graph.random_seed}));
229231 argv_list.appendAssumeCapacity("--listen=-");
230232 },
231 .protocol => for (conf_run.args.slice[1..]) |arg_index| {
232 const arg = arg_index.get(conf);
233 switch (arg.flags.tag) {
234 .string => {
235 const string = arg.prefix.value.?.slice(conf);
236
237 man.hash.addBytesZ(string);
238
239 try protocol_args.ensureUnusedCapacity(gpa, 1 + string.len + 1);
240 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));
241 protocol_args.appendSliceAssumeCapacity(string);
242 protocol_args.appendAssumeCapacity(0);
243 },
244 .path_file => {
245 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
246 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
247 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
248
249 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
250 try inherit_files.ensureUnusedCapacity(gpa, 1);
251 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
252 return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err });
253 inherit_files.appendAssumeCapacity(file);
254
255 man.hash.addBytesZ(prefix);
256 _ = try man.addInputPath(file_path, .{});
257 man.hash.addBytesZ(suffix);
258
259 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
260 1 + @sizeOf(Io.File.Handle) +
261 1 + suffix.len + 1);
262 if (prefix.len > 0) {
263 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
264 protocol_args.appendSliceAssumeCapacity(prefix);
265 protocol_args.appendAssumeCapacity(0);
266 }
267 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file));
268 const file_handle: *align(1) Io.File.Handle =
269 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
270 file_handle.* = file.handle;
271 if (suffix.len > 0) {
272 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
273 protocol_args.appendSliceAssumeCapacity(prefix);
274 protocol_args.appendAssumeCapacity(0);
275 }
276 },
277 .path_directory => {
278 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
279 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
280 const dir_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
281
282 const has_sub_path = dir_path.sub_path.len > 0;
283 try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, has_sub_path);
284 try inherit_dirs.ensureUnusedCapacity(gpa, 1);
285 const dir = if (has_sub_path)
286 dir_path.root_dir.handle.openDir(io, dir_path.sub_path, .{
287 .iterate = true,
288 }) catch |err| return step.fail(maker, "unable to open input dir {qf}: {t}", .{ dir_path, err })
289 else
290 dir_path.root_dir.handle;
291 inherit_dirs.appendAssumeCapacity(dir);
292
293 man.hash.addBytesZ(prefix);
294 man.hash.addOptionalBytes(dir_path.root_dir.path);
295 man.hash.addBytes(dir_path.sub_path);
296 man.hash.addBytesZ(suffix);
297
298 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
299 1 + @sizeOf(Io.Dir.Handle) +
300 1 + suffix.len + 1);
301 if (prefix.len > 0) {
302 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
303 protocol_args.appendSliceAssumeCapacity(prefix);
304 protocol_args.appendAssumeCapacity(0);
305 }
306 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_dir));
307 const dir_handle: *align(1) Io.Dir.Handle =
308 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle)));
309 dir_handle.* = dir.handle;
310 if (suffix.len > 0) {
311 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
312 protocol_args.appendSliceAssumeCapacity(prefix);
313 protocol_args.appendAssumeCapacity(0);
314 }
315 },
316 .file_content => {
317 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
318 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
319 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
320
321 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
322 try inherit_files.ensureUnusedCapacity(gpa, 1);
323 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
324 return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err });
325 inherit_files.appendAssumeCapacity(file);
326
327 man.hash.addBytesZ(prefix);
328 _ = try man.addInputPath(file_path, .{});
329 man.hash.addBytesZ(suffix);
330
331 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
332 1 + @sizeOf(Io.File.Handle) +
333 1 + suffix.len + 1);
334 if (prefix.len > 0) {
335 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
336 protocol_args.appendSliceAssumeCapacity(prefix);
337 protocol_args.appendAssumeCapacity(0);
338 }
339 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file_content));
340 const file_handle: *align(1) Io.File.Handle =
341 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
342 file_handle.* = file.handle;
343 if (suffix.len > 0) {
344 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
345 protocol_args.appendSliceAssumeCapacity(prefix);
346 protocol_args.appendAssumeCapacity(0);
347 }
348 },
349 .artifact => {
350 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
351 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
352 const producer_index = arg.producer.value.?;
353 const producer_step = producer_index.ptr(conf);
354 const producer = producer_step.extended.get(conf.extra).compile;
355 const producer_make_comp_step = maker.stepByIndex(producer_index);
356 const producer_make_comp = &producer_make_comp_step.extended.compile;
357
358 const file_path = producer_make_comp.installed_path orelse
359 maker.generatedPath(producer.generated_bin.value.?);
360
361 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
362 try inherit_files.ensureUnusedCapacity(gpa, 1);
363 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
364 return step.fail(maker, "unable to open input artifact {qf}: {t}", .{ file_path, err });
365 inherit_files.appendAssumeCapacity(file);
366
367 man.hash.addBytesZ(prefix);
368 _ = try man.addInputPath(file_path, .{});
369 man.hash.addBytesZ(suffix);
370
371 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
372 1 + @sizeOf(Io.File.Handle) +
373 1 + suffix.len + 1);
374 if (prefix.len > 0) {
375 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
376 protocol_args.appendSliceAssumeCapacity(prefix);
377 protocol_args.appendAssumeCapacity(0);
378 }
379 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file));
380 const file_handle: *align(1) Io.File.Handle =
381 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
382 file_handle.* = file.handle;
383 if (suffix.len > 0) {
384 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
385 protocol_args.appendSliceAssumeCapacity(prefix);
386 protocol_args.appendAssumeCapacity(0);
387 }
388 },
389 .output_file => {
390 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
391 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
392 const basename = arg.basename.value.?.slice(conf);
393
394 man.hash.addBytesZ(prefix);
395 man.hash.addBytesZ(basename);
396 man.hash.addBytesZ(suffix);
397 assert(!arg.flags.dep_file);
398
399 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
400 1 + @sizeOf(Io.File.Handle) +
401 1 + suffix.len + 1);
402 if (prefix.len > 0) {
403 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
404 protocol_args.appendSliceAssumeCapacity(prefix);
405 protocol_args.appendAssumeCapacity(0);
406 }
407 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_file));
408
409 // Add a placeholder into the argument list because we need the
410 // manifest hash to be updated with all arguments before the
411 // object directory is computed.
412 try owned_files.resize(gpa, owned_files.bit_length + 1, false);
413 try inherit_files.ensureUnusedCapacity(gpa, 1);
414 try output_placeholders.append(gpa, .{
415 .index = @intCast(inherit_files.items.len),
416 .offset = @intCast(protocol_args.items.len),
417 .arg_index = arg_index,
418 });
419 _ = inherit_files.addOneAssumeCapacity();
420
421 _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle));
422 if (suffix.len > 0) {
423 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
424 protocol_args.appendSliceAssumeCapacity(prefix);
425 protocol_args.appendAssumeCapacity(0);
426 }
427 },
428 .output_directory => {
429 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
430 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
431 const basename = arg.basename.value.?.slice(conf);
432
433 man.hash.addBytesZ(prefix);
434 man.hash.addBytesZ(basename);
435 man.hash.addBytesZ(suffix);
436 assert(!arg.flags.dep_file);
437
438 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
439 1 + @sizeOf(Io.Dir.Handle) +
440 1 + suffix.len + 1);
441 if (prefix.len > 0) {
442 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
443 protocol_args.appendSliceAssumeCapacity(prefix);
233 .protocol => {
234 try input_dirs.append(gpa, if (conf_run.cwd.value) |lazy_cwd|
235 try maker.resolveLazyPathIndex(arena, lazy_cwd, run_index)
236 else
237 .cwd());
238 for (conf_run.args.slice[1..]) |arg_index| {
239 const arg = arg_index.get(conf);
240 switch (arg.flags.tag) {
241 .string => {
242 const string = arg.prefix.value.?.slice(conf);
243
244 man.hash.addBytesZ(string);
245
246 try protocol_args.ensureUnusedCapacity(gpa, 1 + string.len + 1);
247 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));
248 protocol_args.appendSliceAssumeCapacity(string);
444249 protocol_args.appendAssumeCapacity(0);
445 }
446 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_dir));
447
448 // Add a placeholder into the argument list because we need the
449 // manifest hash to be updated with all arguments before the
450 // object directory is computed.
451 try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, false);
452 try inherit_dirs.ensureUnusedCapacity(gpa, 1);
453 try output_placeholders.append(gpa, .{
454 .index = @intCast(inherit_dirs.items.len),
455 .offset = @intCast(protocol_args.items.len),
456 .arg_index = arg_index,
457 });
458 _ = inherit_dirs.addOneAssumeCapacity();
250 },
251 .path_file => {
252 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
253 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
254 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
255
256 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
257 try inherit_files.ensureUnusedCapacity(gpa, 1);
258 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
259 return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err });
260 inherit_files.appendAssumeCapacity(file);
261
262 man.hash.addBytesZ(prefix);
263 _ = try man.addInputPath(file_path, .{});
264 man.hash.addBytesZ(suffix);
265
266 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
267 1 + @sizeOf(Io.File.Handle) +
268 1 + suffix.len + 1);
269 if (prefix.len > 0) {
270 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
271 protocol_args.appendSliceAssumeCapacity(prefix);
272 protocol_args.appendAssumeCapacity(0);
273 }
274 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file));
275 const file_handle: *align(1) Io.File.Handle =
276 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
277 file_handle.* = file.handle;
278 if (suffix.len > 0) {
279 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
280 protocol_args.appendSliceAssumeCapacity(prefix);
281 protocol_args.appendAssumeCapacity(0);
282 }
283 },
284 .path_directory => {
285 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
286 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
287 const dir_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
288 try input_dirs.append(gpa, dir_path);
289
290 const has_sub_path = dir_path.sub_path.len > 0;
291 try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, has_sub_path);
292 try inherit_dirs.ensureUnusedCapacity(gpa, 1);
293 const dir = if (has_sub_path)
294 dir_path.root_dir.handle.openDir(io, dir_path.sub_path, .{
295 .iterate = true,
296 }) catch |err| return step.fail(maker, "unable to open input dir {qf}: {t}", .{ dir_path, err })
297 else
298 dir_path.root_dir.handle;
299 inherit_dirs.appendAssumeCapacity(dir);
300
301 man.hash.addBytesZ(prefix);
302 man.hash.addOptionalBytes(dir_path.root_dir.path);
303 man.hash.addBytes(dir_path.sub_path);
304 man.hash.addBytesZ(suffix);
305
306 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
307 1 + @sizeOf(Io.Dir.Handle) +
308 1 + suffix.len + 1);
309 if (prefix.len > 0) {
310 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
311 protocol_args.appendSliceAssumeCapacity(prefix);
312 protocol_args.appendAssumeCapacity(0);
313 }
314 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_dir));
315 const dir_handle: *align(1) Io.Dir.Handle =
316 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle)));
317 dir_handle.* = dir.handle;
318 if (suffix.len > 0) {
319 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
320 protocol_args.appendSliceAssumeCapacity(prefix);
321 protocol_args.appendAssumeCapacity(0);
322 }
323 },
324 .file_content => {
325 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
326 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
327 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
328
329 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
330 try inherit_files.ensureUnusedCapacity(gpa, 1);
331 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
332 return step.fail(maker, "unable to open input file {qf}: {t}", .{ file_path, err });
333 inherit_files.appendAssumeCapacity(file);
334
335 man.hash.addBytesZ(prefix);
336 _ = try man.addInputPath(file_path, .{});
337 man.hash.addBytesZ(suffix);
338
339 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
340 1 + @sizeOf(Io.File.Handle) +
341 1 + suffix.len + 1);
342 if (prefix.len > 0) {
343 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
344 protocol_args.appendSliceAssumeCapacity(prefix);
345 protocol_args.appendAssumeCapacity(0);
346 }
347 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file_content));
348 const file_handle: *align(1) Io.File.Handle =
349 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
350 file_handle.* = file.handle;
351 if (suffix.len > 0) {
352 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
353 protocol_args.appendSliceAssumeCapacity(prefix);
354 protocol_args.appendAssumeCapacity(0);
355 }
356 },
357 .artifact => {
358 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
359 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
360 const producer_index = arg.producer.value.?;
361 const producer_step = producer_index.ptr(conf);
362 const producer = producer_step.extended.get(conf.extra).compile;
363 const producer_make_comp_step = maker.stepByIndex(producer_index);
364 const producer_make_comp = &producer_make_comp_step.extended.compile;
365
366 const file_path = producer_make_comp.installed_path orelse
367 maker.generatedPath(producer.generated_bin.value.?);
368
369 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
370 try inherit_files.ensureUnusedCapacity(gpa, 1);
371 const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err|
372 return step.fail(maker, "unable to open input artifact {qf}: {t}", .{ file_path, err });
373 inherit_files.appendAssumeCapacity(file);
374
375 man.hash.addBytesZ(prefix);
376 _ = try man.addInputPath(file_path, .{});
377 man.hash.addBytesZ(suffix);
378
379 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
380 1 + @sizeOf(Io.File.Handle) +
381 1 + suffix.len + 1);
382 if (prefix.len > 0) {
383 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
384 protocol_args.appendSliceAssumeCapacity(prefix);
385 protocol_args.appendAssumeCapacity(0);
386 }
387 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.input_file));
388 const file_handle: *align(1) Io.File.Handle =
389 @ptrCast(protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle)));
390 file_handle.* = file.handle;
391 if (suffix.len > 0) {
392 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
393 protocol_args.appendSliceAssumeCapacity(prefix);
394 protocol_args.appendAssumeCapacity(0);
395 }
396 },
397 .output_file => {
398 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
399 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
400 const basename = arg.basename.value.?.slice(conf);
401
402 man.hash.addBytesZ(prefix);
403 man.hash.addBytesZ(basename);
404 man.hash.addBytesZ(suffix);
405 assert(!arg.flags.dep_file);
406
407 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
408 1 + @sizeOf(Io.File.Handle) +
409 1 + suffix.len + 1);
410 if (prefix.len > 0) {
411 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
412 protocol_args.appendSliceAssumeCapacity(prefix);
413 protocol_args.appendAssumeCapacity(0);
414 }
415 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_file));
416
417 // Add a placeholder into the argument list because we need the
418 // manifest hash to be updated with all arguments before the
419 // object directory is computed.
420 try owned_files.resize(gpa, owned_files.bit_length + 1, false);
421 try inherit_files.ensureUnusedCapacity(gpa, 1);
422 try output_placeholders.append(gpa, .{
423 .index = @intCast(inherit_files.items.len),
424 .offset = @intCast(protocol_args.items.len),
425 .arg_index = arg_index,
426 });
427 _ = inherit_files.addOneAssumeCapacity();
459428
460 _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle));
461 if (suffix.len > 0) {
462 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
463 protocol_args.appendSliceAssumeCapacity(prefix);
464 protocol_args.appendAssumeCapacity(0);
465 }
466 },
467 .passthru => if (maker.run_args) |run_args| {
468 man.hash.addListOfBytes(run_args);
429 _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.File.Handle));
430 if (suffix.len > 0) {
431 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
432 protocol_args.appendSliceAssumeCapacity(prefix);
433 protocol_args.appendAssumeCapacity(0);
434 }
435 },
436 .output_directory => {
437 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
438 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
439 const basename = arg.basename.value.?.slice(conf);
440
441 man.hash.addBytesZ(prefix);
442 man.hash.addBytesZ(basename);
443 man.hash.addBytesZ(suffix);
444 assert(!arg.flags.dep_file);
445
446 try protocol_args.ensureUnusedCapacity(gpa, 1 + prefix.len + 1 +
447 1 + @sizeOf(Io.Dir.Handle) +
448 1 + suffix.len + 1);
449 if (prefix.len > 0) {
450 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.prefix));
451 protocol_args.appendSliceAssumeCapacity(prefix);
452 protocol_args.appendAssumeCapacity(0);
453 }
454 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.output_dir));
455
456 // Add a placeholder into the argument list because we need the
457 // manifest hash to be updated with all arguments before the
458 // object directory is computed.
459 try owned_dirs.resize(gpa, owned_dirs.bit_length + 1, false);
460 try inherit_dirs.ensureUnusedCapacity(gpa, 1);
461 try output_placeholders.append(gpa, .{
462 .index = @intCast(inherit_dirs.items.len),
463 .offset = @intCast(protocol_args.items.len),
464 .arg_index = arg_index,
465 });
466 _ = inherit_dirs.addOneAssumeCapacity();
469467
470 for (run_args) |run_arg| {
471 try protocol_args.ensureUnusedCapacity(gpa, 1 + run_arg.len + 1);
472 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));
473 protocol_args.appendSliceAssumeCapacity(run_arg);
474 protocol_args.appendAssumeCapacity(0);
475 }
476 },
477 .enable_darling => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value),
478 .enable_qemu => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value),
479 .enable_rosetta => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value),
480 .enable_wasmtime => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value),
481 .enable_wine => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value),
468 _ = protocol_args.addManyAsArrayAssumeCapacity(@sizeOf(Io.Dir.Handle));
469 if (suffix.len > 0) {
470 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.suffix));
471 protocol_args.appendSliceAssumeCapacity(prefix);
472 protocol_args.appendAssumeCapacity(0);
473 }
474 },
475 .passthru => if (maker.run_args) |run_args| {
476 man.hash.addListOfBytes(run_args);
477
478 for (run_args) |run_arg| {
479 try protocol_args.ensureUnusedCapacity(gpa, 1 + run_arg.len + 1);
480 protocol_args.appendAssumeCapacity(@backingInt(std.zig.Client.Message.Arg.string));
481 protocol_args.appendSliceAssumeCapacity(run_arg);
482 protocol_args.appendAssumeCapacity(0);
483 }
484 },
485 .enable_darling => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value),
486 .enable_qemu => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value),
487 .enable_rosetta => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value),
488 .enable_wasmtime => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value),
489 .enable_wine => try thirdPartyToggleProtocol(gpa, &man.hash, &protocol_args, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value),
490 }
482491 }
483492 },
484493 }
......@@ -561,7 +570,7 @@ pub fn make(
561570 .args = protocol_args.items,
562571 } },
563572 });
564 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, inherit_dirs.items, inherit_files.items, protocol_args.items, has_side_effects, output_dir_path, null);
573 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, &.{}, &.{}, &.{}, &.{}, null, has_side_effects, output_dir_path, null);
565574 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);
566575 return;
567576 }
......@@ -581,7 +590,22 @@ pub fn make(
581590 .args = protocol_args.items,
582591 } },
583592 });
584 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, inherit_dirs.items, inherit_files.items, protocol_args.items, has_side_effects, tmp_dir_path, null);
593 try runCommand(
594 arena,
595 run,
596 run_index,
597 maker,
598 progress_node,
599 argv_list.items,
600 inherit_dirs.items,
601 inherit_files.items,
602 protocol_args.items,
603 input_dirs.items,
604 &man,
605 has_side_effects,
606 tmp_dir_path,
607 null,
608 );
585609
586610 for (output_placeholders.items) |placeholder| {
587611 const arg = placeholder.arg_index.get(conf);
......@@ -720,6 +744,8 @@ fn waitZigTest(
720744 child: *process.Child,
721745 progress_node: std.Progress.Node,
722746 protocol_args: []const u8,
747 input_dirs: []const Cache.Path,
748 man: ?*Cache.Manifest,
723749 multi_reader: *Io.File.MultiReader,
724750 opt_metadata: *?TestMetadata,
725751 results: *Step.TestResults,
......@@ -900,6 +926,16 @@ fn waitZigTest(
900926
901927 requestNextTest(&client, md, &sub_prog_node) catch |err| return .{ .write_failed = err };
902928 },
929 .discovered_inputs => while (body_r.takeEnum(
930 std.zig.Server.Message.InputDir,
931 .little,
932 )) |input_dir| try man.?.addDiscoveredPath(.{ .discovered_path = .{
933 .unresolved = try input_dirs[@backingInt(input_dir)]
934 .join(arena, try body_r.takeSentinel(0)),
935 } }) else |err| switch (err) {
936 else => |e| return e,
937 error.EndOfStream => {},
938 },
903939 }
904940 }
905941}
......@@ -1463,6 +1499,8 @@ fn evalZigTest(
14631499 progress_node: std.Progress.Node,
14641500 spawn_options: process.SpawnOptions,
14651501 protocol_args: []const u8,
1502 input_dirs: []const Cache.Path,
1503 man: ?*Cache.Manifest,
14661504 fuzz_context: ?FuzzContext,
14671505) !void {
14681506 if (fuzz_context != null) {
......@@ -1512,6 +1550,8 @@ fn evalZigTest(
15121550 &child,
15131551 progress_node,
15141552 protocol_args,
1553 input_dirs,
1554 man,
15151555 &multi_reader,
15161556 &test_metadata,
15171557 &test_results,
......@@ -1932,7 +1972,7 @@ pub fn rerunInFuzzMode(
19321972 var rand_int: u64 = undefined;
19331973 io.random(@ptrCast(&rand_int));
19341974 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
1935 try runCommand(arena, run, run_index, maker, prog_node, argv_list.items, &.{}, &.{}, &.{}, has_side_effects, tmp_dir_path, .{
1975 try runCommand(arena, run, run_index, maker, prog_node, argv_list.items, &.{}, &.{}, &.{}, &.{}, null, has_side_effects, tmp_dir_path, .{
19361976 .fuzz = fuzz,
19371977 });
19381978}
......@@ -2084,6 +2124,8 @@ fn runCommand(
20842124 inherit_dirs: []const Io.Dir,
20852125 inherit_files: []const Io.File,
20862126 protocol_args: []const u8,
2127 input_dirs: []const Cache.Path,
2128 man: ?*Cache.Manifest,
20872129 has_side_effects: bool,
20882130 output_dir_path: []const u8,
20892131 fuzz_context: ?FuzzContext,
......@@ -2153,6 +2195,8 @@ fn runCommand(
21532195 inherit_dirs,
21542196 inherit_files,
21552197 protocol_args,
2198 input_dirs,
2199 man,
21562200 has_side_effects,
21572201 fuzz_context,
21582202 ) catch |err| term: {
......@@ -2308,6 +2352,8 @@ fn runCommand(
23082352 inherit_dirs,
23092353 inherit_files,
23102354 protocol_args,
2355 input_dirs,
2356 man,
23112357 has_side_effects,
23122358 fuzz_context,
23132359 ) catch |e| {
......@@ -2569,6 +2615,8 @@ fn spawnChildAndCollect(
25692615 inherit_dirs: []const Io.Dir,
25702616 inherit_files: []const Io.File,
25712617 protocol_args: []const u8,
2618 input_dirs: []const Cache.Path,
2619 man: ?*Cache.Manifest,
25722620 has_side_effects: bool,
25732621 fuzz_context: ?FuzzContext,
25742622) !?EvalGenericResult {
......@@ -2675,7 +2723,17 @@ fn spawnChildAndCollect(
26752723 .zig_test, .protocol => {
26762724 try setColorEnvironmentVariables(&conf_run, environ_map, graph.stderr_mode.?);
26772725 const started: Io.Clock.Timestamp = .now(io, .awake);
2678 const result = evalZigTest(run, run_index, maker, progress_node, spawn_options, protocol_args, fuzz_context) catch |err| switch (err) {
2726 const result = evalZigTest(
2727 run,
2728 run_index,
2729 maker,
2730 progress_node,
2731 spawn_options,
2732 protocol_args,
2733 input_dirs,
2734 man,
2735 fuzz_context,
2736 ) catch |err| switch (err) {
26792737 error.Canceled => |e| return e,
26802738 else => |e| e,
26812739 };
lib/std/zig/Client.zig+4-3
......@@ -60,6 +60,7 @@ pub const Message = struct {
6060 start_fuzzing,
6161 /// The message body has the same format as in Server.
6262 new_fuzz_input,
63 /// Body is a sequence of Arg
6364 args,
6465
6566 /// Asks the server to run a list of steps.
......@@ -72,13 +73,13 @@ pub const Message = struct {
7273
7374 pub const Arg = enum(u8) {
7475 /// Trailing:
75 /// * string: [:0]const u8,
76 /// * string: [:0]u8,
7677 string,
7778 /// Trailing:
78 /// * string: [:0]const u8,
79 /// * string: [:0]u8,
7980 prefix,
8081 /// Trailing:
81 /// * string: [:0]const u8,
82 /// * string: [:0]u8,
8283 suffix,
8384 /// Trailing:
8485 /// * handle: Handle,
lib/std/zig/Server.zig+12
......@@ -74,6 +74,10 @@ pub const Message = struct {
7474 broadcast_fuzz_input,
7575 /// Body is a TimeReport.
7676 time_report,
77 /// Body is a sequence of:
78 /// - root_dir: InputDir,
79 /// - sub_path: [:0]u8,
80 discovered_inputs,
7781
7882 /// The first message sent by the server over the build system protocol.
7983 /// Body is a `Handshake`.
......@@ -212,6 +216,14 @@ pub const Message = struct {
212216 reserved: u7 = 0,
213217 };
214218 };
219
220 /// A reference to one of the `.input_dir`s from the `.args` message.
221 pub const InputDir = enum(u32) {
222 /// Server cwd relative path, or absolute path.
223 cwd,
224 /// Numbered in the order that `.input_dir`s appear in the `.args` message.
225 _,
226 };
215227};
216228
217229pub fn receiveMessage(s: *Server) !InMessage.Header {
test/src/runner.zig+46-11
......@@ -1,6 +1,9 @@
11const std = @import("std");
22const Args = struct {
3 test_dir: ?std.Io.Dir,
3 @"test": ?struct {
4 input_dir: std.zig.Server.Message.InputDir,
5 dir: std.Io.Dir,
6 },
47 manifest_file: ?std.Io.File,
58 zig_file: ?std.Io.File,
69 lib_dir: ?std.Io.Dir,
......@@ -19,7 +22,7 @@ pub fn main(init: std.process.Init) !void {
1922 };
2023 try server.serveStringMessage(.zig_version, @import("builtin").zig_version_string);
2124 var args: Args = .{
22 .test_dir = null,
25 .@"test" = null,
2326 .manifest_file = null,
2427 .zig_file = null,
2528 .lib_dir = null,
......@@ -39,12 +42,13 @@ pub fn main(init: std.process.Init) !void {
3942 const args_body = try init.arena.allocator().alloc(u8, hdr.bytes_len);
4043 try server.in.readSliceAll(args_body);
4144 var state: enum { positional, zig, lib, src } = .positional;
45 var input_dir: std.zig.Server.Message.InputDir = .cwd;
4246 var args_body_offset: usize = 0;
4347 while (args_body.len - args_body_offset > 0) {
4448 const arg: std.zig.Client.Message.Arg =
4549 @fromBackingInt(args_body[args_body_offset]);
4650 args_body_offset += 1;
47 switch (arg) {
51 arg: switch (arg) {
4852 .string => {
4953 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
5054 const string = args_body[args_body_offset..end];
......@@ -66,7 +70,11 @@ pub fn main(init: std.process.Init) !void {
6670 continue;
6771 },
6872 .suffix => unreachable,
69 .input_dir, .output_dir => {
73 .input_dir => {
74 input_dir = @fromBackingInt(@backingInt(input_dir) + 1);
75 continue :arg .output_dir;
76 },
77 .output_dir => {
7078 const dir_handle: *align(1) const std.Io.Dir.Handle = @ptrCast(
7179 args_body[args_body_offset..][0..@sizeOf(std.Io.Dir.Handle)],
7280 );
......@@ -76,10 +84,21 @@ pub fn main(init: std.process.Init) !void {
7684 };
7785 switch (state) {
7886 .positional => {
79 std.debug.assert(args.test_dir == null);
80 args.test_dir = dir;
87 std.debug.assert(args.@"test" == null);
88 args.@"test" = .{ .input_dir = input_dir, .dir = dir };
8189 std.debug.assert(args.manifest_file == null);
82 args.manifest_file = try dir.openFile(init.io, "manifest", .{});
90 const manifest_path = "manifest";
91 args.manifest_file = try dir.openFile(init.io, manifest_path, .{});
92
93 try server.serveMessageHeader(.{
94 .tag = .discovered_inputs,
95 .bytes_len = @sizeOf(std.zig.Server.Message.InputDir) +
96 manifest_path.len + 1,
97 });
98 try server.out.writeInt(u32, @backingInt(input_dir), .little);
99 try server.out.writeAll(manifest_path);
100 try server.out.writeByte(0);
101 try server.out.flush();
83102 },
84103 .zig => unreachable,
85104 .lib => {
......@@ -125,7 +144,7 @@ pub fn main(init: std.process.Init) !void {
125144 .run_test => {
126145 const test_index = try server.receiveBody_u32();
127146 try server.serveBodylessMessage(.test_started);
128 const test_result = runTest(init.io, &stderr.interface, &args);
147 const test_result = runTest(init.io, &stderr.interface, &server, &args);
129148 try stderr.flush();
130149 try server.serveTestResults(.{
131150 .index = test_index,
......@@ -146,7 +165,12 @@ pub fn main(init: std.process.Init) !void {
146165 }
147166 }
148167}
149fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void {
168fn runTest(
169 io: std.Io,
170 stderr: *std.Io.Writer,
171 server: *std.zig.Server,
172 args: *const Args,
173) anyerror!void {
150174 const manifest_file = args.manifest_file orelse return error.MissingManifestArg;
151175 const src_dir = args.src_dir orelse return error.MissingSrcDir;
152176 var manifest_buffer: [512]u8 = undefined;
......@@ -179,6 +203,7 @@ fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void
179203 else => {},
180204 .delete => break :contents_r .ending,
181205 }
206
182207 const contents_path = contents_path: {
183208 const line_rest = line_it.rest();
184209 if (line_rest.len > 0) break :contents_path line_rest;
......@@ -191,8 +216,18 @@ fn runTest(io: std.Io, stderr: *std.Io.Writer, args: *const Args) anyerror!void
191216 skip_delimiter = true;
192217 break :contents_r &contents_impl.dr.interface;
193218 }
194 const test_dir = args.test_dir orelse return error.ContentsFileInFileTest;
195 contents_file = try test_dir.openFile(io, contents_path, .{});
219
220 const @"test" = args.@"test" orelse return error.ContentsFileInFileTest;
221 try server.serveMessageHeader(.{
222 .tag = .discovered_inputs,
223 .bytes_len = @intCast(@sizeOf(std.zig.Server.Message.InputDir) + contents_path.len + 1),
224 });
225 try server.out.writeInt(u32, @backingInt(@"test".input_dir), .little);
226 try server.out.writeAll(contents_path);
227 try server.out.writeByte(0);
228 try server.out.flush();
229
230 contents_file = try @"test".dir.openFile(io, contents_path, .{});
196231 contents_impl = .{ .fr = contents_file.?.reader(io, &.{}) };
197232 break :contents_r &contents_impl.fr.interface;
198233 };