| cf.plan.qualifier(), | cf.plan.qualifier(), | ||||
| fs::relative(source_path, cf.plan.source().basis_path).string()); | fs::relative(source_path, cf.plan.source().basis_path).string()); | ||||
| spdlog::info(msg); | spdlog::info(msg); | ||||
| auto&& [dur_ms, compile_res] | |||||
| auto&& [dur_ms, proc_res] | |||||
| = timed<std::chrono::milliseconds>([&] { return run_proc(cf.cmd_info.command); }); | = timed<std::chrono::milliseconds>([&] { return run_proc(cf.cmd_info.command); }); | ||||
| spdlog::info("{} - {:>7n}ms", msg, dur_ms.count()); | spdlog::info("{} - {:>7n}ms", msg, dur_ms.count()); | ||||
| const bool compiled_okay = proc_res.okay(); | |||||
| const auto compile_retc = proc_res.retc; | |||||
| const auto compile_signal = proc_res.signal; | |||||
| std::string compiler_output = std::move(proc_res.output); | |||||
| std::optional<deps_info> ret_deps_info; | std::optional<deps_info> ret_deps_info; | ||||
| if (env.toolchain.deps_mode() == deps_mode::gnu) { | if (env.toolchain.deps_mode() == deps_mode::gnu) { | ||||
| auto dep_info = dds::parse_mkfile_deps_file(df_path); | auto dep_info = dds::parse_mkfile_deps_file(df_path); | ||||
| assert(dep_info.output == cf.object_file_path); | assert(dep_info.output == cf.object_file_path); | ||||
| dep_info.command = quote_command(cf.cmd_info.command); | dep_info.command = quote_command(cf.cmd_info.command); | ||||
| dep_info.command_output = compile_res.output; | |||||
| dep_info.command_output = compiler_output; | |||||
| ret_deps_info = std::move(dep_info); | ret_deps_info = std::move(dep_info); | ||||
| } | } | ||||
| } else if (env.toolchain.deps_mode() == deps_mode::msvc) { | } else if (env.toolchain.deps_mode() == deps_mode::msvc) { | ||||
| auto msvc_deps = parse_msvc_output_for_deps(compile_res.output, "Note: including file:"); | |||||
| auto msvc_deps = parse_msvc_output_for_deps(compiler_output, "Note: including file:"); | |||||
| msvc_deps.deps_info.inputs.push_back(cf.plan.source_path()); | msvc_deps.deps_info.inputs.push_back(cf.plan.source_path()); | ||||
| msvc_deps.deps_info.output = cf.object_file_path; | msvc_deps.deps_info.output = cf.object_file_path; | ||||
| msvc_deps.deps_info.command = quote_command(cf.cmd_info.command); | msvc_deps.deps_info.command = quote_command(cf.cmd_info.command); | ||||
| msvc_deps.deps_info.command_output = msvc_deps.cleaned_output; | msvc_deps.deps_info.command_output = msvc_deps.cleaned_output; | ||||
| ret_deps_info = std::move(msvc_deps.deps_info); | ret_deps_info = std::move(msvc_deps.deps_info); | ||||
| compile_res.output = std::move(msvc_deps.cleaned_output); | |||||
| compiler_output = std::move(msvc_deps.cleaned_output); | |||||
| } | } | ||||
| // MSVC prints the filename of the source file. Dunno why, but they do. | // MSVC prints the filename of the source file. Dunno why, but they do. | ||||
| if (compile_res.output.find(source_path.filename().string()) == 0) { | |||||
| compile_res.output.erase(0, source_path.filename().string().length()); | |||||
| if (starts_with(compile_res.output, "\r")) { | |||||
| compile_res.output.erase(0, 1); | |||||
| if (compiler_output.find(source_path.filename().string()) == 0) { | |||||
| compiler_output.erase(0, source_path.filename().string().length()); | |||||
| if (starts_with(compiler_output, "\r")) { | |||||
| compiler_output.erase(0, 1); | |||||
| } | } | ||||
| if (starts_with(compile_res.output, "\n")) { | |||||
| compile_res.output.erase(0, 1); | |||||
| if (starts_with(compiler_output, "\n")) { | |||||
| compiler_output.erase(0, 1); | |||||
| } | } | ||||
| } | } | ||||
| if (!compile_res.okay()) { | |||||
| if (!compiled_okay) { | |||||
| spdlog::error("Compilation failed: {}", source_path.string()); | spdlog::error("Compilation failed: {}", source_path.string()); | ||||
| spdlog::error("Subcommand FAILED: {}\n{}", | |||||
| spdlog::error("Subcommand FAILED [Exitted {}]: {}\n{}", | |||||
| compile_retc, | |||||
| quote_command(cf.cmd_info.command), | quote_command(cf.cmd_info.command), | ||||
| compile_res.output); | |||||
| compiler_output); | |||||
| if (compile_signal) { | |||||
| spdlog::error("Process exited via signal {}", compile_signal); | |||||
| } | |||||
| throw compile_failure(fmt::format("Compilation failed for {}", source_path.string())); | throw compile_failure(fmt::format("Compilation failed for {}", source_path.string())); | ||||
| } | } | ||||
| if (!compile_res.output.empty()) { | |||||
| if (!dds::trim_view(compiler_output).empty()) { | |||||
| spdlog::warn("While compiling file {} [{}]:\n{}", | spdlog::warn("While compiling file {} [{}]:\n{}", | ||||
| source_path.string(), | source_path.string(), | ||||
| quote_command(cf.cmd_info.command), | quote_command(cf.cmd_info.command), | ||||
| compile_res.output); | |||||
| compiler_output); | |||||
| } | } | ||||
| // Do not return deps info if compilation failed, or we will incrementally | |||||
| // store the compile failure | |||||
| assert(compile_res.okay() || (!ret_deps_info.has_value())); | |||||
| // We must always generate deps info if it was possible: | |||||
| assert(ret_deps_info.has_value() || env.toolchain.deps_mode() == deps_mode::none); | |||||
| return ret_deps_info; | return ret_deps_info; | ||||
| } | } | ||||
| database& db = env.db; | database& db = env.db; | ||||
| auto rb_info = get_rebuild_info(db, comp.object_file_path); | auto rb_info = get_rebuild_info(db, comp.object_file_path); | ||||
| if (rb_info.previous_command.empty()) { | if (rb_info.previous_command.empty()) { | ||||
| // We have no previous compile command for this file. Assume it is | |||||
| // new. | |||||
| // We have no previous compile command for this file. Assume it is new. | |||||
| return true; | return true; | ||||
| } | } | ||||
| if (!rb_info.newer_inputs.empty()) { | if (!rb_info.newer_inputs.empty()) { | ||||
| | views::transform([&](auto&& plan) { return realize_plan(plan, env); }) // | | views::transform([&](auto&& plan) { return realize_plan(plan, env); }) // | ||||
| | views::filter([&](auto&& real) { return should_compile(real, env); }); | | views::filter([&](auto&& real) { return should_compile(real, env); }); | ||||
| std::vector<deps_info> new_deps; | |||||
| std::vector<deps_info> all_new_deps; | |||||
| std::mutex mut; | std::mutex mut; | ||||
| auto okay = parallel_run(each_realized, njobs, [&](const compile_file_full& full) { | auto okay = parallel_run(each_realized, njobs, [&](const compile_file_full& full) { | ||||
| auto nd = do_compile(full, env); | |||||
| if (nd) { | |||||
| auto new_dep = do_compile(full, env); | |||||
| if (new_dep) { | |||||
| std::unique_lock lk{mut}; | std::unique_lock lk{mut}; | ||||
| new_deps.push_back(std::move(*nd)); | |||||
| all_new_deps.push_back(std::move(*new_dep)); | |||||
| } | } | ||||
| }); | }); | ||||
| stopwatch sw; | |||||
| for (auto& info : new_deps) { | |||||
| auto tr = env.db.transaction(); | |||||
| auto tr = env.db.transaction(); | |||||
| for (auto& info : all_new_deps) { | |||||
| update_deps_info(env.db, info); | update_deps_info(env.db, info); | ||||
| } | } | ||||
| return okay; | return okay; |