diff --git a/CMakeLists.txt b/CMakeLists.txt index 11f29fc..f15b70f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,8 +53,10 @@ add_subdirectory(tests) set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) + # Target cmkr -unset(cmkr_SOURCES) +set(CMKR_TARGET cmkr) +set(cmkr_SOURCES "") list(APPEND cmkr_SOURCES "src/args.cpp" @@ -79,7 +81,12 @@ list(APPEND cmkr_SOURCES cmake.toml ) -add_executable(cmkr ${cmkr_SOURCES}) +set(CMKR_SOURCES ${cmkr_SOURCES}) +add_executable(cmkr) + +if(cmkr_SOURCES) + target_sources(cmkr PRIVATE ${cmkr_SOURCES}) +endif() get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT) if(NOT CMKR_VS_STARTUP_PROJECT) @@ -103,6 +110,8 @@ target_link_libraries(cmkr PRIVATE ordered_map ) +unset(CMKR_TARGET) +unset(CMKR_SOURCES) install( TARGETS cmkr diff --git a/include/cmake.hpp b/include/cmake.hpp index dd22da0..d790271 100644 --- a/include/cmake.hpp +++ b/include/cmake.hpp @@ -98,7 +98,7 @@ struct CMake { std::string build_dir = "build"; std::string generator; std::string config; - std::vector subdirs; + Condition> subdirs; std::vector cppflags; std::vector cflags; std::vector linkflags; diff --git a/src/gen.cpp b/src/gen.cpp index be67b55..352c678 100644 --- a/src/gen.cpp +++ b/src/gen.cpp @@ -390,7 +390,9 @@ struct Generator { cmd("if")(RawArg(cmake.conditions[condition])); } - fn(condition, itr.second); + if (!itr.second.empty()) { + fn(condition, itr.second); + } if (!condition.empty()) { cmd("endif")(); @@ -573,25 +575,30 @@ int generate_cmake(const char *path, bool root) { // generate_cmake is called on the subdirectories recursively later if (!cmake.subdirs.empty()) { - for (const auto &dir : cmake.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(); - } + gen.handle_condition(cmake.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(); + } + }); endl(); } if (!cmake.targets.empty()) { for (const auto &target : cmake.targets) { comment("Target " + target.name); + cmd("set")("CMKR_TARGET", target.name); + gen.handle_condition(target.include_before, [&](const std::string &, const std::vector &includes) { inject_includes(includes); }); gen.handle_condition(target.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); }); @@ -599,7 +606,7 @@ int generate_cmake(const char *path, bool root) { auto sources_var = target.name + "_SOURCES"; bool added_toml = false; - cmd("unset")(sources_var).endl(); + cmd("set")(sources_var, RawArg("\"\"")).endl(); gen.handle_condition(target.sources, [&](const std::string &condition, const std::vector &condition_sources) { auto sources = expand_cmake_paths(condition_sources, path); if (sources.empty()) { @@ -616,6 +623,7 @@ int generate_cmake(const char *path, bool root) { if (!added_toml && target.type != cmake::target_interface) { cmd("list")("APPEND", sources_var, std::vector{"cmake.toml"}).endl(); } + cmd("set")("CMKR_SOURCES", "${" + sources_var + "}"); std::string add_command; std::string target_type; @@ -656,7 +664,13 @@ int generate_cmake(const char *path, bool root) { assert("Unimplemented enum value" && false); } - cmd(add_command)(target.name, target_type, "${" + target.name + "_SOURCES}").endl(); + cmd(add_command)(target.name, target_type).endl(); + + // clang-format off + cmd("if")(sources_var); + cmd("target_sources")(target.name, target.type == cmake::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}"); + cmd("endif")().endl(); + // clang-format on // The first executable target will become the Visual Studio startup project if (target.type == cmake::target_executable) { @@ -696,6 +710,9 @@ int generate_cmake(const char *path, bool root) { gen.handle_condition(target.include_after, [&](const std::string &, const std::vector &includes) { inject_includes(includes); }); gen.handle_condition(target.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); }); + + cmd("unset")("CMKR_TARGET"); + cmd("unset")("CMKR_SOURCES"); } } @@ -755,10 +772,12 @@ int generate_cmake(const char *path, bool root) { } } - for (const auto &sub : cmake.subdirs) { - auto subpath = fs::path(path) / fs::path(sub); - if (fs::exists(subpath / "cmake.toml")) - generate_cmake(subpath.string().c_str(), false); + for (const auto &itr : cmake.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); + } } return 0; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0c559d8..07a6b28 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,3 +28,13 @@ add_test( build ) +add_test( + NAME + interface + WORKING_DIRECTORY + "${CMAKE_CURRENT_LIST_DIR}/interface" + COMMAND + $ + build +) + diff --git a/tests/cmake.toml b/tests/cmake.toml index 55d4188..f5b57a7 100644 --- a/tests/cmake.toml +++ b/tests/cmake.toml @@ -8,4 +8,10 @@ arguments = ["build"] name = "conditions" command = "$" working-directory = "${CMAKE_CURRENT_LIST_DIR}/conditions" +arguments = ["build"] + +[[test]] +name = "interface" +command = "$" +working-directory = "${CMAKE_CURRENT_LIST_DIR}/interface" arguments = ["build"] \ No newline at end of file diff --git a/tests/interface/cmake.toml b/tests/interface/cmake.toml new file mode 100644 index 0000000..67de6cf --- /dev/null +++ b/tests/interface/cmake.toml @@ -0,0 +1,11 @@ +[project] +name = "interface" + +[target.mylib] +type = "interface" +include-directories = ["include"] + +[target.example] +type = "executable" +sources = ["src/main.cpp"] +link-libraries = ["mylib"] \ No newline at end of file diff --git a/tests/interface/include/mylib/mylib.hpp b/tests/interface/include/mylib/mylib.hpp new file mode 100644 index 0000000..61325db --- /dev/null +++ b/tests/interface/include/mylib/mylib.hpp @@ -0,0 +1,4 @@ +namespace mylib +{ +static const char* version() { return "v1.0"; } +} // namespace mylib \ No newline at end of file diff --git a/tests/interface/src/main.cpp b/tests/interface/src/main.cpp new file mode 100644 index 0000000..9d8c418 --- /dev/null +++ b/tests/interface/src/main.cpp @@ -0,0 +1,8 @@ +#include + +#include "mylib/mylib.hpp" + +int main() +{ + printf("mylib version: %s\n", mylib::version()) +} \ No newline at end of file