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
3235namespace 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