[M8] reusable libraries: install layout + cargoxx-path deps

This commit is contained in:
2026-05-17 18:13:15 +00:00
parent fdf97861a4
commit e6c39914b3
25 changed files with 932 additions and 21 deletions

View File

@@ -64,7 +64,10 @@ auto emit_header(const manifest::Manifest& m) -> std::string {
"set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD \"d0edc3af-4c50-42ea-a356-e2862fe7a444\")\n"
"set(CMAKE_CXX_MODULE_STD ON)\n"
"\n"
"project({} LANGUAGES CXX)\n"
"project({} VERSION {} LANGUAGES CXX)\n"
"\n"
"include(GNUInstallDirs)\n"
"include(CMakePackageConfigHelpers)\n"
"\n"
"# Generated by cargoxx — do not edit.\n"
"# Source of truth: ../Cargoxx.toml\n"
@@ -77,7 +80,7 @@ auto emit_header(const manifest::Manifest& m) -> std::string {
"\n"
"add_compile_options(-Wall -Wextra -Wpedantic -Wconversion "
"-Wno-missing-field-initializers)\n",
m.package.name, edition_to_int(m.package.edition));
m.package.name, m.package.version, edition_to_int(m.package.edition));
}
auto emit_find_packages(const std::vector<linkdb::Recipe>& recipes,
@@ -153,9 +156,65 @@ auto any_recipe_is_catch2(const std::vector<linkdb::Recipe>& dev_recipes) -> boo
return std::ranges::any_of(dev_recipes, recipe_is_catch2);
}
auto emit_library_install_rules(const std::string& package_name) -> std::string {
// Installs the static archive + module FILE_SET, exports targets,
// generates Config.cmake + Version.cmake via configure_package_config_file,
// and writes a basic pkg-config descriptor. Inline file(WRITE …) keeps the
// .in templates self-contained in the generated CMakeLists.txt — no
// out-of-tree files to manage.
return std::format(
"\n# ----- install + package-config + pkg-config -----\n"
"install(TARGETS {0}\n"
" EXPORT {0}Targets\n"
" FILE_SET CXX_MODULES DESTINATION ${{CMAKE_INSTALL_INCLUDEDIR}}/{0}\n"
" ARCHIVE DESTINATION ${{CMAKE_INSTALL_LIBDIR}})\n"
"install(EXPORT {0}Targets\n"
" FILE {0}Targets.cmake\n"
" NAMESPACE {0}::\n"
" DESTINATION ${{CMAKE_INSTALL_LIBDIR}}/cmake/{0})\n"
"\n"
"file(WRITE ${{CMAKE_CURRENT_BINARY_DIR}}/{0}Config.cmake.in [[\n"
"@PACKAGE_INIT@\n"
"include(CMakeFindDependencyMacro)\n"
"include(\"${{CMAKE_CURRENT_LIST_DIR}}/{0}Targets.cmake\")\n"
"check_required_components({0})\n"
"]])\n"
"configure_package_config_file(\n"
" ${{CMAKE_CURRENT_BINARY_DIR}}/{0}Config.cmake.in\n"
" ${{CMAKE_CURRENT_BINARY_DIR}}/{0}Config.cmake\n"
" INSTALL_DESTINATION ${{CMAKE_INSTALL_LIBDIR}}/cmake/{0})\n"
"write_basic_package_version_file(\n"
" ${{CMAKE_CURRENT_BINARY_DIR}}/{0}ConfigVersion.cmake\n"
" VERSION ${{PROJECT_VERSION}}\n"
" COMPATIBILITY SameMajorVersion)\n"
"install(FILES\n"
" ${{CMAKE_CURRENT_BINARY_DIR}}/{0}Config.cmake\n"
" ${{CMAKE_CURRENT_BINARY_DIR}}/{0}ConfigVersion.cmake\n"
" DESTINATION ${{CMAKE_INSTALL_LIBDIR}}/cmake/{0})\n"
"\n"
"file(WRITE ${{CMAKE_CURRENT_BINARY_DIR}}/{0}.pc.in [[\n"
"prefix=@CMAKE_INSTALL_PREFIX@\n"
"exec_prefix=${{prefix}}\n"
"libdir=${{prefix}}/${{CMAKE_INSTALL_LIBDIR}}\n"
"includedir=${{prefix}}/${{CMAKE_INSTALL_INCLUDEDIR}}\n"
"\n"
"Name: @PROJECT_NAME@\n"
"Version: @PROJECT_VERSION@\n"
"Description: @PROJECT_NAME@\n"
"Cflags: -I${{includedir}}\n"
"Libs: -L${{libdir}} -l@PROJECT_NAME@\n"
"]])\n"
"configure_file(${{CMAKE_CURRENT_BINARY_DIR}}/{0}.pc.in\n"
" ${{CMAKE_CURRENT_BINARY_DIR}}/{0}.pc @ONLY)\n"
"install(FILES ${{CMAKE_CURRENT_BINARY_DIR}}/{0}.pc\n"
" DESTINATION ${{CMAKE_INSTALL_LIBDIR}}/pkgconfig)\n",
package_name);
}
auto emit_library(const layout::Target& lib, const std::string& package_name,
const std::vector<linkdb::Recipe>& recipes,
const std::vector<std::string>& include_dirs,
manifest::Edition edition,
const fs::path& project_root) -> std::string {
std::string out = "\n# ----- library target -----\n";
out += std::format("add_library({} STATIC)\n", package_name);
@@ -172,6 +231,11 @@ auto emit_library(const layout::Target& lib, const std::string& package_name,
}
}
out += ")\n";
// PUBLIC cxx_std_NN propagates the standard requirement onto the
// exported IMPORTED target, so consumers `find_package`-ing this
// library get the right standard for module BMI regeneration.
out += std::format("target_compile_features({} PUBLIC cxx_std_{})\n",
package_name, edition_to_int(edition));
if (!include_dirs.empty()) {
out += std::format("target_include_directories({} SYSTEM PRIVATE", package_name);
for (const auto& d : include_dirs) {
@@ -181,6 +245,8 @@ auto emit_library(const layout::Target& lib, const std::string& package_name,
}
out += link_block(package_name, "PUBLIC", false, package_name,
collect_dep_targets(recipes));
out += emit_library_install_rules(package_name);
return out;
}
@@ -190,10 +256,14 @@ auto emit_primary_binary(const layout::Target& bin, const std::string& package_n
std::string out = "\n# ----- binary target -----\n";
out += std::format("add_executable({}_bin {})\n", package_name,
rel_to_build(bin.entry, project_root));
out += std::format("set_target_properties({}_bin PROPERTIES OUTPUT_NAME {})\n",
out += std::format("set_target_properties({}_bin PROPERTIES\n"
" OUTPUT_NAME {}\n"
" RUNTIME_OUTPUT_DIRECTORY \"${{CMAKE_BINARY_DIR}}/bin\")\n",
package_name, package_name);
out += link_block(std::format("{}_bin", package_name), "PRIVATE", has_lib, package_name,
collect_dep_targets(recipes));
out += std::format("install(TARGETS {}_bin RUNTIME DESTINATION ${{CMAKE_INSTALL_BINDIR}})\n",
package_name);
return out;
}
@@ -203,8 +273,13 @@ auto emit_extra_binary(const layout::Target& bin, const std::string& package_nam
std::string out = std::format("\n# ----- binary target: {} -----\n", bin.name);
out += std::format("add_executable({} {})\n", bin.name,
rel_to_build(bin.entry, project_root));
out += std::format("set_target_properties({} PROPERTIES\n"
" RUNTIME_OUTPUT_DIRECTORY \"${{CMAKE_BINARY_DIR}}/bin\")\n",
bin.name);
out += link_block(bin.name, "PRIVATE", has_lib, package_name,
collect_dep_targets(recipes));
out += std::format("install(TARGETS {} RUNTIME DESTINATION ${{CMAKE_INSTALL_BINDIR}})\n",
bin.name);
return out;
}
@@ -335,7 +410,8 @@ auto cmake_lists(const GenerateInputs& in) -> std::string {
if (in.layout.library) {
out += emit_library(*in.layout.library, pkg_name, in.recipes,
in.manifest.build.include_dirs, in.project_root);
in.manifest.build.include_dirs,
in.manifest.package.edition, in.project_root);
}
const auto* primary = find_primary_bin(in.layout);