Skip to content

Commit 7a27984

Browse files
committed
feat(build): make graph target executor default
1 parent 78459b5 commit 7a27984

4 files changed

Lines changed: 507 additions & 181 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ vix.log
4545
cmd.md
4646
command.md
4747
docs/
48+
future.md

src/build/BuildGraph.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,7 @@ namespace vix::cli::build
844844
task.id = compile_task_id_for_source(sourcePath);
845845
task.workingDirectory = entry.directory;
846846
task.logFile = dependencyPath;
847+
task.commandHash = command_hash_for_argv(task.command);
847848

848849
add_task(task);
849850

@@ -1128,6 +1129,33 @@ namespace vix::cli::build
11281129

11291130
bool BuildGraph::task_is_dirty(const BuildTask &task) const
11301131
{
1132+
if (task.kind == BuildTaskKind::Compile)
1133+
{
1134+
for (const auto &inputId : task.inputs)
1135+
{
1136+
const BuildNode *node = find_node(inputId);
1137+
1138+
if (!node)
1139+
return true;
1140+
1141+
if (node->dirty() || node->missing())
1142+
return true;
1143+
}
1144+
1145+
for (const auto &outputId : task.outputs)
1146+
{
1147+
const BuildNode *node = find_node(outputId);
1148+
1149+
if (!node)
1150+
return true;
1151+
1152+
if (node->missing())
1153+
return true;
1154+
}
1155+
1156+
return false;
1157+
}
1158+
11311159
for (const auto &inputId : task.inputs)
11321160
{
11331161
const BuildNode *node = find_node(inputId);

src/build/BuildGraphExecutor.cpp

Lines changed: 152 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@
2525
#include <unordered_map>
2626
#include <unordered_set>
2727
#include <vector>
28+
#include <cctype>
29+
#include <cstdlib>
2830

2931
#include <vix/cli/build/DependencyFile.hpp>
3032
#include <vix/cli/build/ObjectCache.hpp>
33+
#include <vix/cli/cmake/CMakeBuild.hpp>
3134

3235
namespace vix::cli::build
3336
{
@@ -326,6 +329,38 @@ namespace vix::cli::build
326329

327330
return task;
328331
}
332+
333+
static bool graph_debug_logs_enabled()
334+
{
335+
const char *level = std::getenv("VIX_LOG_LEVEL");
336+
337+
if (!level || !*level)
338+
return false;
339+
340+
std::string value(level);
341+
342+
for (char &c : value)
343+
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
344+
345+
return value == "debug" || value == "trace";
346+
}
347+
348+
static void graph_log(
349+
const BuildGraphExecutorOptions &options,
350+
const std::string &message)
351+
{
352+
if (options.quiet)
353+
return;
354+
355+
if (!options.verbose)
356+
return;
357+
358+
if (!graph_debug_logs_enabled())
359+
return;
360+
361+
std::cout << " " << message << "\n";
362+
std::cout.flush();
363+
}
329364
} // namespace
330365

331366
BuildGraphExecutor::BuildGraphExecutor(BuildGraphExecutorOptions options)
@@ -343,6 +378,10 @@ namespace vix::cli::build
343378
BuildGraphExecutorResult result;
344379
result.target = options_.target;
345380

381+
graph_log(
382+
options_,
383+
"graph: starting target executor for `" + options_.target + "`");
384+
346385
if (options_.target.empty())
347386
{
348387
result.ok = false;
@@ -351,6 +390,8 @@ namespace vix::cli::build
351390
return result;
352391
}
353392

393+
graph_log(options_, "graph: resolving target task");
394+
354395
const BuildTask *targetTask =
355396
find_target_task(graph, options_.target);
356397

@@ -362,8 +403,18 @@ namespace vix::cli::build
362403
return result;
363404
}
364405

406+
graph_log(
407+
options_,
408+
"graph: target task resolved: " + targetTask->id);
409+
410+
graph_log(options_, "graph: building output-to-task map");
411+
365412
const auto outputToTask = make_output_to_task_map(graph);
366413

414+
graph_log(
415+
options_,
416+
"graph: collecting task closure");
417+
367418
std::unordered_set<std::string> selected;
368419
collect_task_closure(
369420
graph,
@@ -373,15 +424,51 @@ namespace vix::cli::build
373424

374425
result.selectedTasks = selected.size();
375426

427+
graph_log(
428+
options_,
429+
"graph: selected " + std::to_string(result.selectedTasks) + " tasks");
430+
431+
graph_log(
432+
options_,
433+
"graph: collecting compile tasks");
434+
376435
const std::vector<BuildTask> compileTasks =
377436
selected_compile_tasks(graph, selected);
378437

438+
graph_log(
439+
options_,
440+
"graph: selected " + std::to_string(compileTasks.size()) +
441+
" compile tasks");
442+
443+
graph_log(
444+
options_,
445+
"graph: checking dirty compile tasks");
446+
379447
const std::vector<BuildTask> dirtyCompileTasks =
380448
dirty_tasks_only(graph, compileTasks);
381449

382450
result.selectedCompileTasks = compileTasks.size();
383451
result.dirtyCompileTasks = dirtyCompileTasks.size();
384452

453+
graph_log(
454+
options_,
455+
"graph: dirty compile tasks: " +
456+
std::to_string(result.dirtyCompileTasks));
457+
458+
if (result.dirtyCompileTasks > 128)
459+
{
460+
result.ok = false;
461+
result.exitCode = 2;
462+
result.output =
463+
"Graph target has too many dirty compile tasks: " +
464+
std::to_string(result.dirtyCompileTasks) +
465+
" dirty tasks from " +
466+
std::to_string(result.selectedCompileTasks) +
467+
" selected compile tasks. Falling back to Ninja.\n";
468+
469+
return result;
470+
}
471+
385472
if (!dirtyCompileTasks.empty())
386473
{
387474
ObjectCache objectCache(options_.buildDir);
@@ -396,7 +483,7 @@ namespace vix::cli::build
396483

397484
BuildSchedulerOptions schedulerOptions;
398485
schedulerOptions.jobs = options_.jobs;
399-
schedulerOptions.quiet = options_.quiet;
486+
schedulerOptions.quiet = true;
400487
schedulerOptions.stopOnFirstFailure = true;
401488

402489
BuildScheduler scheduler(schedulerOptions);
@@ -406,6 +493,10 @@ namespace vix::cli::build
406493
scheduler.run(
407494
[&](BuildTask &task)
408495
{
496+
graph_log(
497+
options_,
498+
"graph: compile " + task.id);
499+
409500
return run_cached_compile_task(
410501
graph,
411502
objectCache,
@@ -415,32 +506,84 @@ namespace vix::cli::build
415506
result.executedCompileTasks = compileResult.done;
416507
result.skippedCompileTasks = compileResult.skipped;
417508

509+
for (const BuildTaskResult &taskResult : compileResult.results)
510+
{
511+
if (!taskResult.output.empty())
512+
result.output += taskResult.output;
513+
}
514+
418515
if (!compileResult.success())
419516
{
420517
result.ok = false;
421518
result.exitCode = 1;
519+
return result;
520+
}
521+
}
522+
else
523+
{
524+
graph_log(options_, "graph: no dirty compile tasks");
525+
}
526+
527+
if (dirtyCompileTasks.empty())
528+
{
529+
bool outputsExist = true;
422530

423-
for (const BuildTaskResult &taskResult : compileResult.results)
531+
for (const std::string &outputId : targetTask->outputs)
532+
{
533+
const BuildNode *node = graph.find_node(outputId);
534+
535+
if (!node || node->missing())
424536
{
425-
if (!taskResult.output.empty())
426-
result.output += taskResult.output;
537+
outputsExist = false;
538+
break;
427539
}
540+
}
541+
542+
if (outputsExist)
543+
{
544+
result.ok = true;
545+
result.exitCode = 0;
546+
result.executedCompileTasks = 0;
547+
result.skippedCompileTasks = result.selectedCompileTasks;
548+
result.output += "Graph target is up to date.\n";
549+
550+
graph_log(options_, "graph: target outputs exist, skipping ninja");
428551

429552
return result;
430553
}
431554
}
432555

556+
graph_log(
557+
options_,
558+
"graph: running ninja target `" + options_.target + "`");
559+
433560
BuildTask ninjaTargetTask =
434561
make_ninja_target_task(
435562
options_.buildDir,
436563
options_.target);
437564

438-
BuildTaskResult linkResult =
439-
BuildScheduler::execute_command_task(ninjaTargetTask);
565+
const process::ExecResult ninjaResult =
566+
run_process_live_to_log(
567+
ninjaTargetTask.command,
568+
{},
569+
options_.buildDir / "build.log",
570+
options_.quiet,
571+
/*cmakeVerbose=*/false,
572+
/*progressOnly=*/false);
573+
574+
result.exitCode = ninjaResult.exitCode;
575+
result.ok = ninjaResult.exitCode == 0;
440576

441-
result.output += linkResult.output;
442-
result.exitCode = linkResult.exitCode;
443-
result.ok = linkResult.exitCode == 0;
577+
graph_log(
578+
options_,
579+
"graph: ninja target finished with exit code " +
580+
std::to_string(result.exitCode));
581+
582+
if (!result.ok)
583+
{
584+
result.output += "Ninja target failed: " + options_.target + "\n";
585+
result.output += ninjaResult.displayCommand + "\n";
586+
}
444587

445588
return result;
446589
}

0 commit comments

Comments
 (0)