| plan.archive_all(env, params.parallel_jobs); | plan.archive_all(env, params.parallel_jobs); | ||||
| plan.link_all(env, params.parallel_jobs); | plan.link_all(env, params.parallel_jobs); | ||||
| // int n_test_fails = 0; | |||||
| // for (path_ref test_exe : all_tests) { | |||||
| // spdlog::info("Running test: {}", fs::relative(test_exe, params.out_root).string()); | |||||
| // const auto test_res = run_proc({test_exe.string()}); | |||||
| // if (!test_res.okay()) { | |||||
| // spdlog::error("TEST FAILED\n{}", test_res.output); | |||||
| // n_test_fails++; | |||||
| // } | |||||
| // } | |||||
| // if (n_test_fails) { | |||||
| // throw compile_failure("Test failures during build"); | |||||
| // } | |||||
| auto test_failures = plan.run_all_tests(env, params.parallel_jobs); | |||||
| for (auto& failures : test_failures) { | |||||
| spdlog::error("Test {} failed! Output:\n{}[dds - test output end]", failures.executable_path.string(), failures.output); | |||||
| } | |||||
| if (!test_failures.empty()) { | |||||
| throw compile_failure("Test failures during the build!"); | |||||
| } | |||||
| if (params.do_export) { | if (params.do_export) { | ||||
| export_project(pkg, env); | export_project(pkg, env); |
| #include <spdlog/spdlog.h> | #include <spdlog/spdlog.h> | ||||
| #include <chrono> | |||||
| #include <algorithm> | #include <algorithm> | ||||
| #include <cassert> | #include <cassert> | ||||
| proc_res.output)); | proc_res.output)); | ||||
| } | } | ||||
| } | } | ||||
| bool link_executable_plan::is_app() const noexcept { | |||||
| return _main_compile.source().kind == source_kind::app; | |||||
| } | |||||
| bool link_executable_plan::is_test() const noexcept { | |||||
| return _main_compile.source().kind == source_kind::test; | |||||
| } | |||||
| std::optional<test_failure> link_executable_plan::run_test(build_env_ref env) const { | |||||
| auto exe_path = calc_executable_path(env); | |||||
| auto msg = fmt::format("Run test: {:30}", fs::relative(exe_path, env.output_root).string()); | |||||
| spdlog::info(msg); | |||||
| auto start = std::chrono::high_resolution_clock::now(); | |||||
| auto res = run_proc({exe_path}); | |||||
| auto end = std::chrono::high_resolution_clock::now(); | |||||
| auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end - start); | |||||
| if (res.okay()) { | |||||
| spdlog::info("{} - PASSED in {:>6n}μs", msg, dur.count()); | |||||
| return std::nullopt; | |||||
| } else { | |||||
| spdlog::error("{} - FAILED in {:>6n}μs [exitted {}]", msg, dur.count(), res.retc); | |||||
| test_failure f; | |||||
| f.executable_path = exe_path; | |||||
| f.output = res.output; | |||||
| f.retc = res.retc; | |||||
| return f; | |||||
| } | |||||
| } |
| class library_plan; | class library_plan; | ||||
| struct test_failure { | |||||
| fs::path executable_path; | |||||
| std::string output; | |||||
| int retc; | |||||
| }; | |||||
| class link_executable_plan { | class link_executable_plan { | ||||
| std::vector<fs::path> _input_libs; | std::vector<fs::path> _input_libs; | ||||
| compile_file_plan _main_compile; | compile_file_plan _main_compile; | ||||
| fs::path calc_executable_path(const build_env& env) const noexcept; | fs::path calc_executable_path(const build_env& env) const noexcept; | ||||
| void link(const build_env&, const library_plan&) const; | void link(const build_env&, const library_plan&) const; | ||||
| std::optional<test_failure> run_test(build_env_ref) const; | |||||
| bool is_test() const noexcept; | |||||
| bool is_app() const noexcept; | |||||
| }; | }; | ||||
| } // namespace dds | } // namespace dds |
| } | } | ||||
| } | } | ||||
| std::vector<test_failure> build_plan::run_all_tests(build_env_ref env, int njobs) const { | |||||
| using namespace ranges::views; | |||||
| auto test_executables = // | |||||
| iter_libraries(*this) // | |||||
| | transform(&library_plan::executables) // | |||||
| | join // | |||||
| | filter(&link_executable_plan::is_test) // | |||||
| ; | |||||
| std::mutex mut; | |||||
| std::vector<test_failure> fails; | |||||
| parallel_run(test_executables, njobs, [&](const auto& exe) { | |||||
| auto fail_info = exe.run_test(env); | |||||
| if (fail_info) { | |||||
| std::scoped_lock lk{mut}; | |||||
| fails.emplace_back(std::move(*fail_info)); | |||||
| } | |||||
| }); | |||||
| return fails; | |||||
| } | } |
| void compile_all(const build_env& env, int njobs) const; | void compile_all(const build_env& env, int njobs) const; | ||||
| void archive_all(const build_env& env, int njobs) const; | void archive_all(const build_env& env, int njobs) const; | ||||
| void link_all(const build_env& env, int njobs) const; | void link_all(const build_env& env, int njobs) const; | ||||
| std::vector<test_failure> run_all_tests(build_env_ref env, int njobs) const; | |||||
| }; | }; | ||||
| } // namespace dds | } // namespace dds |