@@ -5,6 +5,7 @@ | |||
#include <dds/proc.hpp> | |||
#include <dds/source.hpp> | |||
#include <dds/toolchain.hpp> | |||
#include <dds/compdb.hpp> | |||
#include <dds/usage_reqs.hpp> | |||
#include <dds/util/algo.hpp> | |||
#include <dds/util/string.hpp> | |||
@@ -153,6 +154,9 @@ void dds::build(const build_params& params, const package_manifest& man) { | |||
} | |||
dds::build_env env{params.toolchain, params.out_root}; | |||
if (params.generate_compdb) { | |||
generate_compdb(plan, env); | |||
} | |||
plan.compile_all(env, params.parallel_jobs); | |||
plan.archive_all(env, params.parallel_jobs); | |||
plan.link_all(env, params.parallel_jobs); |
@@ -0,0 +1,39 @@ | |||
#pragma once | |||
#include <dds/build/plan.hpp> | |||
#include <range/v3/view/concat.hpp> | |||
#include <range/v3/view/filter.hpp> | |||
#include <range/v3/view/join.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
namespace dds { | |||
inline auto iter_libraries(const build_plan& plan) { | |||
return // | |||
plan.packages() // | |||
| ranges::views::transform(&package_plan::libraries) // | |||
| ranges::views::join // | |||
; | |||
} | |||
inline auto iter_compilations(const build_plan& plan) { | |||
auto lib_compiles = // | |||
iter_libraries(plan) // | |||
| ranges::views::transform(&library_plan::create_archive) // | |||
| ranges::views::filter([&](auto&& opt) { return bool(opt); }) // | |||
| ranges::views::transform([&](auto&& opt) -> auto& { return opt->compile_files(); }) // | |||
| ranges::views::join // | |||
; | |||
auto exe_compiles = // | |||
iter_libraries(plan) // | |||
| ranges::views::transform(&library_plan::executables) // | |||
| ranges::views::join // | |||
| ranges::views::transform(&link_executable_plan::main_compile_file) // | |||
; | |||
return ranges::views::concat(lib_compiles, exe_compiles); | |||
} | |||
} // namespace dds |
@@ -15,6 +15,7 @@ struct build_params { | |||
bool enable_warnings = false; | |||
bool build_apps = false; | |||
bool build_deps = false; | |||
bool generate_compdb = true; | |||
int parallel_jobs = 0; | |||
}; | |||
@@ -1,5 +1,6 @@ | |||
#include "./plan.hpp" | |||
#include <dds/build/iter_compilations.hpp> | |||
#include <dds/proc.hpp> | |||
#include <range/v3/action/join.hpp> | |||
@@ -72,45 +73,17 @@ bool parallel_run(Range&& rng, int n_jobs, Fn&& fn) { | |||
} // namespace | |||
namespace { | |||
auto all_libraries(const build_plan& plan) { | |||
return // | |||
plan.packages() // | |||
| ranges::views::transform(&package_plan::libraries) // | |||
| ranges::views::join // | |||
; | |||
} | |||
} // namespace | |||
void build_plan::compile_all(const build_env& env, int njobs) const { | |||
auto lib_compiles = // | |||
all_libraries(*this) // | |||
| ranges::views::transform(&library_plan::create_archive) // | |||
| ranges::views::filter([&](auto&& opt) { return bool(opt); }) // | |||
| ranges::views::transform([&](auto&& opt) -> auto& { return opt->compile_files(); }) // | |||
| ranges::views::join // | |||
; | |||
auto exe_compiles = // | |||
all_libraries(*this) // | |||
| ranges::views::transform(&library_plan::executables) // | |||
| ranges::views::join // | |||
| ranges::views::transform(&link_executable_plan::main_compile_file) // | |||
; | |||
auto all_compiles = ranges::views::concat(lib_compiles, exe_compiles); | |||
auto okay | |||
= parallel_run(all_compiles, njobs, [&](const compile_file_plan& cf) { cf.compile(env); }); | |||
auto okay = parallel_run(iter_compilations(*this), njobs, [&](const compile_file_plan& cf) { | |||
cf.compile(env); | |||
}); | |||
if (!okay) { | |||
throw std::runtime_error("Compilation failed."); | |||
} | |||
} | |||
void build_plan::archive_all(const build_env& env, int njobs) const { | |||
parallel_run(all_libraries(*this), njobs, [&](const library_plan& lib) { | |||
parallel_run(iter_libraries(*this), njobs, [&](const library_plan& lib) { | |||
if (lib.create_archive()) { | |||
lib.create_archive()->archive(env); | |||
} | |||
@@ -118,7 +91,7 @@ void build_plan::archive_all(const build_env& env, int njobs) const { | |||
} | |||
void build_plan::link_all(const build_env& env, int) const { | |||
for (auto&& lib : all_libraries(*this)) { | |||
for (auto&& lib : iter_libraries(*this)) { | |||
for (auto&& exe : lib.executables()) { | |||
exe.link(env, lib); | |||
} |
@@ -13,6 +13,15 @@ | |||
using namespace dds; | |||
std::vector<std::string> compile_file_plan::generate_compile_command(build_env_ref env) const | |||
noexcept { | |||
compile_file_spec spec{_source.path, calc_object_file_path(env)}; | |||
spec.enable_warnings = _rules.enable_warnings(); | |||
extend(spec.include_dirs, _rules.include_dirs()); | |||
extend(spec.definitions, _rules.defs()); | |||
return env.toolchain.create_compile_command(spec); | |||
} | |||
void compile_file_plan::compile(const build_env& env) const { | |||
const auto obj_path = calc_object_file_path(env); | |||
fs::create_directories(obj_path.parent_path()); | |||
@@ -22,13 +31,7 @@ void compile_file_plan::compile(const build_env& env) const { | |||
fs::relative(_source.path, _source.basis_path).string()); | |||
auto start_time = std::chrono::steady_clock::now(); | |||
compile_file_spec spec{_source.path, obj_path}; | |||
spec.enable_warnings = _rules.enable_warnings(); | |||
extend(spec.include_dirs, _rules.include_dirs()); | |||
extend(spec.definitions, _rules.defs()); | |||
auto cmd = env.toolchain.create_compile_command(spec); | |||
auto cmd = generate_compile_command(env); | |||
auto compile_res = run_proc(cmd); | |||
auto end_time = std::chrono::steady_clock::now(); | |||
@@ -46,13 +49,13 @@ void compile_file_plan::compile(const build_env& env) const { | |||
} | |||
// MSVC prints the filename of the source file. Dunno why, but they do. | |||
if (compile_res.output.find(spec.source_path.filename().string() + "\r\n") == 0) { | |||
compile_res.output.erase(0, spec.source_path.filename().string().length() + 2); | |||
if (compile_res.output.find(_source.path.filename().string() + "\r\n") == 0) { | |||
compile_res.output.erase(0, _source.path.filename().string().length() + 2); | |||
} | |||
if (!compile_res.output.empty()) { | |||
spdlog::warn("While compiling file {} [{}]:\n{}", | |||
spec.source_path.string(), | |||
_source.path.string(), | |||
quote_command(cmd), | |||
compile_res.output); | |||
} |
@@ -49,6 +49,8 @@ public: | |||
, _qualifier(qual) | |||
, _subdir(subdir) {} | |||
std::vector<std::string> generate_compile_command(build_env_ref) const noexcept; | |||
const source_file& source() const noexcept { return _source; } | |||
path_ref source_path() const noexcept { return _source.path; } | |||
@@ -0,0 +1,31 @@ | |||
#include "./compdb.hpp" | |||
#include <dds/build/iter_compilations.hpp> | |||
#include <dds/proc.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <nlohmann/json.hpp> | |||
#include <range/v3/view/join.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
using namespace dds; | |||
void dds::generate_compdb(const build_plan& plan, build_env_ref env) { | |||
auto compdb = nlohmann::json::array(); | |||
for (const compile_file_plan& cf : iter_compilations(plan)) { | |||
auto command = cf.generate_compile_command(env); | |||
auto entry = nlohmann::json::object({ | |||
{"directory", env.output_root}, | |||
{"arguments", command}, | |||
{"file", cf.source_path().string()}, | |||
}); | |||
compdb.push_back(std::move(entry)); | |||
} | |||
fs::create_directories(env.output_root); | |||
auto compdb_file = env.output_root / "compile_commands.json"; | |||
auto ostream = open(compdb_file, std::ios::binary | std::ios::out); | |||
ostream << compdb.dump(2); | |||
} |
@@ -0,0 +1,9 @@ | |||
#pragma once | |||
#include <dds/build/plan.hpp> | |||
namespace dds { | |||
void generate_compdb(const build_plan&, build_env_ref); | |||
} // namespace dds |