| 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); |