From 3cd84a97082b5ac8ca2ac59da2fde6ab9e858169 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sat, 26 Jun 2021 16:22:26 +0200 Subject: [PATCH] Add basic support for [subdir.mydir] --- include/project_parser.hpp | 14 ++++++- src/cmake_generator.cpp | 80 +++++++++++++++++++++++++++++--------- src/project_parser.cpp | 31 +++++++++++++-- 3 files changed, 102 insertions(+), 23 deletions(-) diff --git a/include/project_parser.hpp b/include/project_parser.hpp index d7aac72..376322b 100644 --- a/include/project_parser.hpp +++ b/include/project_parser.hpp @@ -110,6 +110,15 @@ struct Install { std::string destination; }; +struct Subdir { + std::string name; + std::string condition; + Condition cmake_before; + Condition cmake_after; + ConditionVector include_before; + ConditionVector include_after; +}; + struct Project { // This is the CMake version required to use all cmkr versions. std::string cmake_version = "3.15"; @@ -117,7 +126,7 @@ struct Project { std::string build_dir = "build"; std::string generator; std::string config; - Condition> subdirs; + Condition> project_subdirs; std::vector cppflags; std::vector cflags; std::vector linkflags; @@ -140,9 +149,12 @@ struct Project { std::vector tests; std::vector installs; tsl::ordered_map conditions; + std::vector subdirs; Project(const std::string &path, bool build); }; +bool is_root_path(const std::string &path); + } // namespace parser } // namespace cmkr \ No newline at end of file diff --git a/src/cmake_generator.cpp b/src/cmake_generator.cpp index 5c93b28..ff73252 100644 --- a/src/cmake_generator.cpp +++ b/src/cmake_generator.cpp @@ -1,7 +1,7 @@ #include "cmake_generator.hpp" -#include "project_parser.hpp" #include "error.hpp" #include "literals.hpp" +#include "project_parser.hpp" #include "fs.hpp" #include @@ -639,26 +639,52 @@ int generate_cmake(const char *path, bool root) { endl(); } + auto add_subdir = [&](const std::string &dir) { + // clang-format off + comment(dir); + cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}"); + cmd("if")("CMAKE_FOLDER"); + cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir); + cmd("else")(); + cmd("set")("CMAKE_FOLDER", dir); + cmd("endif")(); + // clang-format on + + cmd("add_subdirectory")(dir); + cmd("set")("CMAKE_FOLDER", "${CMKR_CMAKE_FOLDER}").endl(); + }; + // generate_cmake is called on the subdirectories recursively later - if (!project.subdirs.empty()) { - gen.handle_condition(project.subdirs, [&](const std::string &, const std::vector &subdirs) { + if (!project.project_subdirs.empty()) { + gen.handle_condition(project.project_subdirs, [&](const std::string &, const std::vector &subdirs) { for (const auto &dir : subdirs) { - // clang-format off - comment(dir); - cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}"); - cmd("if")("CMAKE_FOLDER"); - cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir); - cmd("else")(); - cmd("set")("CMAKE_FOLDER", dir); - cmd("endif")(); - // clang-format on - - cmd("add_subdirectory")(dir); - cmd("set")("CMAKE_FOLDER", "${CMKR_CMAKE_FOLDER}").endl(); + add_subdir(dir); } }); endl(); } + for (const auto &subdir : project.subdirs) { + if (!subdir.condition.empty()) { + const auto &condition = subdir.condition; + if (project.conditions.count(condition) == 0) { + throw std::runtime_error("Unknown condition '" + condition + "' for [subdir." + subdir.name + "]"); + } + gen.cmd("if", condition)(RawArg(project.conditions[condition])); + } + + gen.handle_condition(subdir.include_before, + [&](const std::string &, const std::vector &includes) { inject_includes(includes); }); + gen.handle_condition(subdir.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); }); + + add_subdir(subdir.name); + + gen.handle_condition(subdir.include_after, [&](const std::string &, const std::vector &includes) { inject_includes(includes); }); + gen.handle_condition(subdir.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); }); + + if (!subdir.condition.empty()) { + cmd("endif")(); + } + } if (!project.targets.empty()) { for (const auto &target : project.targets) { @@ -875,13 +901,29 @@ int generate_cmake(const char *path, bool root) { } } - for (const auto &itr : project.subdirs) { + auto generate_subdir = [path](const fs::path &sub) { + // Skip generating for subdirectories that have a cmake.toml with a [project] in it + fs::path subpath; + for (const auto &p : sub) { + subpath /= p; + if (parser::is_root_path(subpath.string())) { + return; + } + } + + subpath = path / sub; + if (fs::exists(subpath / "cmake.toml")) { + generate_cmake(subpath.string().c_str(), false); + } + }; + for (const auto &itr : project.project_subdirs) { for (const auto &sub : itr.second) { - auto subpath = fs::path(path) / fs::path(sub); - if (fs::exists(subpath / "cmake.toml")) - generate_cmake(subpath.string().c_str(), false); + generate_subdir(sub); } } + for (const auto &subdir : project.subdirs) { + generate_subdir(subdir.name); + } return 0; } diff --git a/src/project_parser.cpp b/src/project_parser.cpp index 876aa85..882f6f4 100644 --- a/src/project_parser.cpp +++ b/src/project_parser.cpp @@ -62,10 +62,11 @@ static void get_optional(const TomlBasicValue &v, const toml::key &ky, T &destin } Project::Project(const std::string &path, bool build) { - if (!fs::exists(fs::path(path) / "cmake.toml")) { + const auto toml_path = fs::path(path) / "cmake.toml"; + if (!fs::exists(toml_path)) { throw std::runtime_error("No cmake.toml was found!"); } - const auto toml = toml::parse((fs::path(path) / "cmake.toml").string()); + const auto toml = toml::parse(toml_path.string()); if (build) { if (toml.contains("cmake")) { const auto &cmake = toml::find(toml, "cmake"); @@ -99,7 +100,21 @@ Project::Project(const std::string &path, bool build) { get_optional(project, "cmake-after", cmake_after); get_optional(project, "include-before", include_before); get_optional(project, "include-after", include_after); - get_optional(project, "subdirs", subdirs); + get_optional(project, "subdirs", project_subdirs); + } + + if (toml.contains("subdir")) { + const auto &subs = toml::find(toml, "subdir").as_table(); + for (const auto &sub : subs) { + Subdir subdir; + subdir.name = sub.first; + get_optional(sub.second, "condition", subdir.condition); + get_optional(sub.second, "cmake-before", subdir.cmake_before); + get_optional(sub.second, "cmake-after", subdir.cmake_after); + get_optional(sub.second, "include-before", subdir.include_before); + get_optional(sub.second, "include-after", subdir.include_after); + subdirs.push_back(subdir); + } } if (toml.contains("settings")) { @@ -311,5 +326,15 @@ Project::Project(const std::string &path, bool build) { } } } + +bool is_root_path(const std::string &path) { + const auto toml_path = fs::path(path) / "cmake.toml"; + if (!fs::exists(toml_path)) { + return false; + } + const auto toml = toml::parse(toml_path.string()); + return toml.contains("project"); +} + } // namespace parser } // namespace cmkr