fs::path lib_archive_path(const build_params& params, const library& lib) { | fs::path lib_archive_path(const build_params& params, const library& lib) { | ||||
return params.out_root | return params.out_root | ||||
/ (fmt::format("lib{}{}", lib.name(), params.toolchain.archive_suffix())); | |||||
/ (fmt::format("lib{}{}", lib.manifest().name, params.toolchain.archive_suffix())); | |||||
} | } | ||||
void copy_headers(const fs::path& source, const fs::path& dest, const source_list& sources) { | void copy_headers(const fs::path& source, const fs::path& dest, const source_list& sources) { | ||||
header_root = lib.path() / "src"; | header_root = lib.path() / "src"; | ||||
} | } | ||||
auto lml_path = export_root / fmt::format("{}.lml", lib.name()); | |||||
auto lml_path = export_root / fmt::format("{}.lml", lib.manifest().name); | |||||
auto lml_parent_dir = lml_path.parent_path(); | auto lml_parent_dir = lml_path.parent_path(); | ||||
std::vector<lm::pair> pairs; | std::vector<lm::pair> pairs; | ||||
pairs.emplace_back("Type", "Library"); | pairs.emplace_back("Type", "Library"); | ||||
pairs.emplace_back("Name", lib.name()); | |||||
pairs.emplace_back("Name", lib.manifest().name); | |||||
if (fs::is_directory(header_root)) { | if (fs::is_directory(header_root)) { | ||||
auto header_dest = lib_out_root / "include"; | auto header_dest = lib_out_root / "include"; | ||||
sources // | sources // | ||||
| filter(should_compile_source) // | | filter(should_compile_source) // | ||||
| transform([&](auto&& src) { | | transform([&](auto&& src) { | ||||
return compile_file_plan{rules, "obj/" + lib.name(), src, lib.name()}; | |||||
return compile_file_plan{rules, | |||||
"obj/" + lib.manifest().name, | |||||
src, | |||||
lib.manifest().name}; | |||||
}) // | }) // | ||||
| to_vector; | | to_vector; | ||||
} | } | ||||
fs::remove(arc.out_path); | fs::remove(arc.out_path); | ||||
} | } | ||||
spdlog::info("Create archive for {}: {}", lib.name(), arc.out_path.string()); | |||||
spdlog::info("Create archive for {}: {}", lib.manifest().name, arc.out_path.string()); | |||||
fs::create_directories(arc.out_path.parent_path()); | fs::create_directories(arc.out_path.parent_path()); | ||||
auto ar_res = run_proc(ar_cmd); | auto ar_res = run_proc(ar_cmd); | ||||
if (!ar_res.okay()) { | if (!ar_res.okay()) { | ||||
ranges::views::all(compilations) // | ranges::views::all(compilations) // | ||||
| transform([&](const compile_file_plan& comp) -> std::pair<fs::path, fs::path> { | | transform([&](const compile_file_plan& comp) -> std::pair<fs::path, fs::path> { | ||||
return std::pair(comp.source.path, | return std::pair(comp.source.path, | ||||
comp.get_object_file_path(build_env{params.toolchain, params.out_root})); | |||||
comp.get_object_file_path( | |||||
build_env{params.toolchain, params.out_root})); | |||||
}) // | }) // | ||||
| ranges::to<object_file_index>() // | | ranges::to<object_file_index>() // | ||||
; | ; | ||||
} // namespace | } // namespace | ||||
void dds::build(const build_params& params, const package_manifest& man) { | |||||
auto libs = collect_libraries(params.root, man.name); | |||||
void dds::build(const build_params& params, const package_manifest&) { | |||||
auto libs = collect_libraries(params.root); | |||||
// auto sroot = dds::sroot{params.root}; | // auto sroot = dds::sroot{params.root}; | ||||
// auto comp_rules = sroot.base_compile_rules(); | // auto comp_rules = sroot.base_compile_rules(); | ||||
for (const auto& sfile : to_compile) { | for (const auto& sfile : to_compile) { | ||||
compile_file_plan cf_plan; | compile_file_plan cf_plan; | ||||
cf_plan.source = sfile; | cf_plan.source = sfile; | ||||
cf_plan.qualifier = lib.name(); | |||||
cf_plan.qualifier = lib.manifest().name; | |||||
cf_plan.rules = params.compile_rules; | cf_plan.rules = params.compile_rules; | ||||
cf_plan.subdir = fs::path("obj") / lib.name(); | |||||
cf_plan.subdir = fs::path("obj") / lib.manifest().name; | |||||
compile_files.push_back(std::move(cf_plan)); | compile_files.push_back(std::move(cf_plan)); | ||||
if (sfile.kind == source_kind::test) { | if (sfile.kind == source_kind::test) { | ||||
test_sources.push_back(sfile); | test_sources.push_back(sfile); | ||||
if (should_create_archive) { | if (should_create_archive) { | ||||
create_archive_plan ar_plan; | create_archive_plan ar_plan; | ||||
ar_plan.name = lib.name(); | |||||
ar_plan.name = lib.manifest().name; | |||||
ar_plan.out_dir = params.out_subdir; | ar_plan.out_dir = params.out_subdir; | ||||
create_archive.emplace(std::move(ar_plan)); | create_archive.emplace(std::move(ar_plan)); | ||||
} | } | ||||
return library_plan{lib.name(), | |||||
return library_plan{lib.manifest().name, | |||||
lib.path(), | lib.path(), | ||||
params.out_subdir, | params.out_subdir, | ||||
compile_files, | compile_files, | ||||
return env.output_root / fmt::format("{}{}{}", "lib", name, env.toolchain.archive_suffix()); | return env.output_root / fmt::format("{}{}{}", "lib", name, env.toolchain.archive_suffix()); | ||||
} | } | ||||
void create_archive_plan::archive(const build_env& env, | |||||
void create_archive_plan::archive(const build_env& env, | |||||
const std::vector<fs::path>& objects) const { | const std::vector<fs::path>& objects) const { | ||||
archive_spec ar; | archive_spec ar; | ||||
ar.input_files = objects; | ar.input_files = objects; | ||||
if (!lib.create_archive) { | if (!lib.create_archive) { | ||||
return; | return; | ||||
} | } | ||||
const auto& objects | |||||
= ranges::views::all(lib.compile_files) // | |||||
| ranges::views::filter( | |||||
[](auto&& comp) { return comp.source.kind == source_kind::source; }) // | |||||
| ranges::views::transform([&](auto&& comp) { | |||||
return comp.get_object_file_path(env); | |||||
}) // | |||||
| ranges::to_vector // | |||||
const auto& objects = ranges::views::all(lib.compile_files) // | |||||
| ranges::views::filter([](auto&& comp) { | |||||
return comp.source.kind == source_kind::source; | |||||
}) // | |||||
| ranges::views::transform( | |||||
[&](auto&& comp) { return comp.get_object_file_path(env); }) // | |||||
| ranges::to_vector // | |||||
; | ; | ||||
lib.create_archive->archive(env, objects); | lib.create_archive->archive(env, objects); | ||||
}); | }); |
struct package_plan { | struct package_plan { | ||||
std::string name; | std::string name; | ||||
std::string namespace_; | |||||
std::vector<std::string> pkg_requires; | std::vector<std::string> pkg_requires; | ||||
std::vector<library_plan> create_libraries; | std::vector<library_plan> create_libraries; | ||||
} | } | ||||
void add_sdist_to_dep_plan(build_plan& plan, const sdist& sd, const sdist_index_type& sd_idx) { | void add_sdist_to_dep_plan(build_plan& plan, const sdist& sd, const sdist_index_type& sd_idx) { | ||||
auto& pkg = plan.build_packages.emplace_back(); | |||||
pkg.name = sd.manifest.name; | |||||
auto libs = collect_libraries(sd.path, sd.manifest.name); | |||||
auto& pkg = plan.build_packages.emplace_back(); | |||||
pkg.name = sd.manifest.name; | |||||
pkg.namespace_ = sd.manifest.namespace_; | |||||
auto libs = collect_libraries(sd.path); | |||||
for (const auto& lib : libs) { | for (const auto& lib : libs) { | ||||
shared_compile_file_rules comp_rules = lib.base_compile_rules(); | shared_compile_file_rules comp_rules = lib.base_compile_rules(); | ||||
linkup_dependencies(comp_rules, sd.manifest, sd_idx); | linkup_dependencies(comp_rules, sd.manifest, sd_idx); | ||||
if (lib.create_archive) { | if (lib.create_archive) { | ||||
kvs.emplace_back("Path", | kvs.emplace_back("Path", | ||||
fs::relative(lib.create_archive->archive_file_path(env), | fs::relative(lib.create_archive->archive_file_path(env), | ||||
lml_path.parent_path()).string()); | |||||
lml_path.parent_path()) | |||||
.string()); | |||||
} | } | ||||
auto pub_inc_dir = lib.source_root / "include"; | auto pub_inc_dir = lib.source_root / "include"; | ||||
auto src_dir = lib.source_root / "src"; | |||||
auto src_dir = lib.source_root / "src"; | |||||
if (fs::exists(src_dir)) { | if (fs::exists(src_dir)) { | ||||
pub_inc_dir = src_dir; | pub_inc_dir = src_dir; | ||||
} | } | ||||
std::vector<lm::pair> kvs; | std::vector<lm::pair> kvs; | ||||
kvs.emplace_back("Type", "Package"); | kvs.emplace_back("Type", "Package"); | ||||
kvs.emplace_back("Name", pkg.name); | kvs.emplace_back("Name", pkg.name); | ||||
kvs.emplace_back("Namespace", pkg.name); | |||||
kvs.emplace_back("Namespace", pkg.namespace_); | |||||
for (auto&& lib : pkg.create_libraries) { | for (auto&& lib : pkg.create_libraries) { | ||||
auto lml = generate_lml(lib, basedir / pkg.name, env); | auto lml = generate_lml(lib, basedir / pkg.name, env); | ||||
void dds::write_libman_index(path_ref out_filepath, const build_plan& plan, const build_env& env) { | void dds::write_libman_index(path_ref out_filepath, const build_plan& plan, const build_env& env) { | ||||
fs::create_directories(out_filepath.parent_path()); | fs::create_directories(out_filepath.parent_path()); | ||||
auto lm_items_dir = out_filepath.parent_path() / "_libman"; | |||||
auto lm_items_dir = out_filepath.parent_path() / "_libman"; | |||||
std::vector<lm::pair> kvs; | std::vector<lm::pair> kvs; | ||||
kvs.emplace_back("Type", "Index"); | kvs.emplace_back("Type", "Index"); | ||||
for (const package_plan& pkg : plan.build_packages) { | for (const package_plan& pkg : plan.build_packages) { | ||||
auto pkg_lmp = generate_lmp(pkg, lm_items_dir, env); | auto pkg_lmp = generate_lmp(pkg, lm_items_dir, env); | ||||
kvs.emplace_back("Package", fmt::format( | |||||
"{}; {}", | |||||
pkg.name, | |||||
fs::relative(pkg_lmp, out_filepath.parent_path()).string() | |||||
)); | |||||
kvs.emplace_back("Package", | |||||
fmt::format("{}; {}", | |||||
pkg.name, | |||||
fs::relative(pkg_lmp, out_filepath.parent_path()).string())); | |||||
} | } | ||||
lm::write_pairs(out_filepath, kvs); | lm::write_pairs(out_filepath, kvs); | ||||
} | } |
} // namespace | } // namespace | ||||
library library::from_directory(path_ref lib_dir, std::string_view name) { | |||||
library library::from_directory(path_ref lib_dir) { | |||||
auto sources = collect_pf_sources(lib_dir); | auto sources = collect_pf_sources(lib_dir); | ||||
library_manifest man; | library_manifest man; | ||||
auto man_path = lib_dir / "library.dds"; | |||||
man.name = lib_dir.filename().string(); | |||||
auto man_path = lib_dir / "library.dds"; | |||||
if (fs::is_regular_file(man_path)) { | if (fs::is_regular_file(man_path)) { | ||||
man = library_manifest::load_from_file(man_path); | man = library_manifest::load_from_file(man_path); | ||||
} | } | ||||
auto lib = library(lib_dir, name, std::move(sources), std::move(man)); | |||||
auto lib = library(lib_dir, std::move(sources), std::move(man)); | |||||
return lib; | return lib; | ||||
} | } | ||||
auto has_library_dirs | auto has_library_dirs | ||||
= [](path_ref dir) { return fs::exists(dir / "src") || fs::exists(dir / "include"); }; | = [](path_ref dir) { return fs::exists(dir / "src") || fs::exists(dir / "include"); }; | ||||
std::vector<library> dds::collect_libraries(path_ref root, std::string_view basename) { | |||||
std::vector<library> dds::collect_libraries(path_ref root) { | |||||
std::vector<library> ret; | std::vector<library> ret; | ||||
if (has_library_dirs(root)) { | if (has_library_dirs(root)) { | ||||
ret.emplace_back(library::from_directory(root, basename)); | |||||
ret.emplace_back(library::from_directory(root)); | |||||
} | } | ||||
auto pf_libs_dir = root / "libs"; | auto pf_libs_dir = root / "libs"; | ||||
extend(ret, | extend(ret, | ||||
fs::directory_iterator(pf_libs_dir) // | fs::directory_iterator(pf_libs_dir) // | ||||
| ranges::views::filter(has_library_dirs) // | | ranges::views::filter(has_library_dirs) // | ||||
| ranges::views::transform([&](auto p) { | |||||
return library::from_directory(p, | |||||
fmt::format("{}-{}", | |||||
basename, | |||||
p.path().filename().string())); | |||||
})); | |||||
| ranges::views::transform([&](auto p) { return library::from_directory(p); })); | |||||
} | } | ||||
return ret; | return ret; | ||||
} | } |
class library { | class library { | ||||
fs::path _path; | fs::path _path; | ||||
std::string _name; | |||||
source_list _sources; | source_list _sources; | ||||
library_manifest _man; | library_manifest _man; | ||||
library(path_ref dir, std::string_view name, source_list&& src, library_manifest&& man) | |||||
library(path_ref dir, source_list&& src, library_manifest&& man) | |||||
: _path(dir) | : _path(dir) | ||||
, _name(name) | |||||
, _sources(std::move(src)) | , _sources(std::move(src)) | ||||
, _man(std::move(man)) {} | , _man(std::move(man)) {} | ||||
public: | public: | ||||
static library from_directory(path_ref, std::string_view name); | |||||
static library from_directory(path_ref path) { | |||||
return from_directory(path, path.filename().string()); | |||||
} | |||||
auto& name() const noexcept { return _name; } | |||||
static library from_directory(path_ref); | |||||
auto& manifest() const noexcept { return _man; } | auto& manifest() const noexcept { return _man; } | ||||
shared_compile_file_rules compile_rules; | shared_compile_file_rules compile_rules; | ||||
}; | }; | ||||
std::vector<library> collect_libraries(path_ref where, std::string_view basename); | |||||
std::vector<library> collect_libraries(path_ref where); | |||||
} // namespace dds | } // namespace dds |
library_manifest library_manifest::load_from_file(const fs::path& fpath) { | library_manifest library_manifest::load_from_file(const fs::path& fpath) { | ||||
auto kvs = lm::parse_file(fpath); | auto kvs = lm::parse_file(fpath); | ||||
library_manifest ret; | library_manifest ret; | ||||
for (auto& pair : kvs.items()) { | |||||
if (pair.key() == "Private-Include") { | |||||
ret.private_includes.emplace_back(pair.value()); | |||||
} else if (pair.key() == "Private-Define") { | |||||
ret.private_defines.emplace_back(pair.value()); | |||||
} else if (pair.key() == "Uses") { | |||||
ret.uses.emplace_back(pair.value()); | |||||
} else if (pair.key() == "Links") { | |||||
ret.uses.emplace_back(pair.value()); | |||||
} else { | |||||
throw std::runtime_error( | |||||
fmt::format("Unknown key in file '{}': {}", fpath.string(), pair.key())); | |||||
} | |||||
} | |||||
ret.name = fpath.parent_path().filename().string(); | |||||
lm::read(fmt::format("Reading library manifest {}", fpath.string()), | |||||
kvs, | |||||
lm::read_accumulate("Private-Include", ret.private_includes), | |||||
lm::read_accumulate("Private-Define", ret.private_defines), | |||||
lm::read_accumulate("Uses", ret.uses), | |||||
lm::read_accumulate("Links", ret.links), | |||||
lm::read_opt("Name", ret.name), | |||||
lm::reject_unknown()); | |||||
return ret; | return ret; | ||||
} | } |
namespace dds { | namespace dds { | ||||
struct library_manifest { | struct library_manifest { | ||||
std::string name; | |||||
std::vector<fs::path> private_includes; | std::vector<fs::path> private_includes; | ||||
std::vector<std::string> private_defines; | std::vector<std::string> private_defines; | ||||
std::vector<std::string> uses; | std::vector<std::string> uses; |
lm::read(fmt::format("Reading package manifest '{}'", fpath.string()), | lm::read(fmt::format("Reading package manifest '{}'", fpath.string()), | ||||
kvs, | kvs, | ||||
lm::read_required("Name", ret.name), | lm::read_required("Name", ret.name), | ||||
lm::read_opt("Namespace", ret.namespace_), | |||||
lm::read_required("Version", version_str), | lm::read_required("Version", version_str), | ||||
lm::read_accumulate("Depends", depends_strs), | lm::read_accumulate("Depends", depends_strs), | ||||
lm::reject_unknown()); | lm::reject_unknown()); |
struct package_manifest { | struct package_manifest { | ||||
std::string name; | std::string name; | ||||
std::string namespace_; | |||||
semver::version version; | semver::version version; | ||||
std::vector<dependency> dependencies; | std::vector<dependency> dependencies; | ||||
static package_manifest load_from_file(path_ref); | static package_manifest load_from_file(path_ref); |
ranges::sort(sources_to_keep, std::less<>(), [](auto&& s) { return s.path; }); | ranges::sort(sources_to_keep, std::less<>(), [](auto&& s) { return s.path; }); | ||||
auto lib_dds_path = lib.path() / "library.dds"; | auto lib_dds_path = lib.path() / "library.dds"; | ||||
if (fs::is_regular_file(lib_dds_path)) { | |||||
sdist_export_file(out_root, params.project_dir, lib_dds_path, hash); | |||||
if (!fs::is_regular_file(lib_dds_path)) { | |||||
throw std::runtime_error(fmt::format( | |||||
"Each library in a source distribution requires a library manifest (Expected [{}])", | |||||
lib_dds_path.string())); | |||||
} | } | ||||
sdist_export_file(out_root, params.project_dir, lib_dds_path, hash); | |||||
spdlog::info("sdist: Export library from {}", lib.path().string()); | spdlog::info("sdist: Export library from {}", lib.path().string()); | ||||
fs::create_directories(out_root); | fs::create_directories(out_root); |