| @@ -84,10 +84,15 @@ std::optional<deps_info> do_compile(const compile_file_full& cf, build_env_ref e | |||
| cf.plan.qualifier(), | |||
| fs::relative(source_path, cf.plan.source().basis_path).string()); | |||
| spdlog::info(msg); | |||
| auto&& [dur_ms, compile_res] | |||
| auto&& [dur_ms, proc_res] | |||
| = timed<std::chrono::milliseconds>([&] { return run_proc(cf.cmd_info.command); }); | |||
| 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; | |||
| if (env.toolchain.deps_mode() == deps_mode::gnu) { | |||
| @@ -103,48 +108,51 @@ std::optional<deps_info> do_compile(const compile_file_full& cf, build_env_ref e | |||
| auto dep_info = dds::parse_mkfile_deps_file(df_path); | |||
| assert(dep_info.output == cf.object_file_path); | |||
| 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); | |||
| } | |||
| } 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.output = cf.object_file_path; | |||
| msvc_deps.deps_info.command = quote_command(cf.cmd_info.command); | |||
| msvc_deps.deps_info.command_output = msvc_deps.cleaned_output; | |||
| 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. | |||
| 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("Subcommand FAILED: {}\n{}", | |||
| spdlog::error("Subcommand FAILED [Exitted {}]: {}\n{}", | |||
| compile_retc, | |||
| 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())); | |||
| } | |||
| if (!compile_res.output.empty()) { | |||
| if (!dds::trim_view(compiler_output).empty()) { | |||
| spdlog::warn("While compiling file {} [{}]:\n{}", | |||
| source_path.string(), | |||
| 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; | |||
| } | |||
| @@ -157,8 +165,7 @@ bool should_compile(const compile_file_full& comp, build_env_ref env) { | |||
| database& db = env.db; | |||
| auto rb_info = get_rebuild_info(db, comp.object_file_path); | |||
| 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; | |||
| } | |||
| if (!rb_info.newer_inputs.empty()) { | |||
| @@ -184,19 +191,18 @@ bool dds::detail::compile_all(const ref_vector<const compile_file_plan>& compile | |||
| | views::transform([&](auto&& plan) { return realize_plan(plan, 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; | |||
| 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}; | |||
| 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); | |||
| } | |||
| return okay; | |||