Minor improvements

- Drastically improve quality of generated CMake
- Fix a regression with recursive globbing in the root
- Automatically include CSharpUtilities when using CSharp
main
Duncan Ogilvie 2 years ago
parent 6e4006ec07
commit 2437eb90fe

1
.gitignore vendored

@ -9,3 +9,4 @@ build*/
.idea/ .idea/
cmake-build*/ cmake-build*/
CMakeLists.txt.user CMakeLists.txt.user
.vscode/

55
CMakeLists.txt generated

@ -7,17 +7,14 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build") message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build")
endif() endif()
# Regenerate CMakeLists.txt automatically in the root project
set(CMKR_ROOT_PROJECT OFF) set(CMKR_ROOT_PROJECT OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CMKR_ROOT_PROJECT ON) set(CMKR_ROOT_PROJECT ON)
# Enable folder support # Enable folder support
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
endif()
# Create a configure-time dependency on cmake.toml to improve IDE support # Create a configure-time dependency on cmake.toml to improve IDE support
if(CMKR_ROOT_PROJECT)
configure_file(cmake.toml cmake.toml COPYONLY) configure_file(cmake.toml cmake.toml COPYONLY)
endif() endif()
@ -33,7 +30,7 @@ project(cmkr
include("cmake/generate_documentation.cmake") include("cmake/generate_documentation.cmake")
include("cmake/generate_resources.cmake") include("cmake/generate_resources.cmake")
# third_party # Subdirectory: third_party
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER) if(CMAKE_FOLDER)
set(CMAKE_FOLDER "${CMAKE_FOLDER}/third_party") set(CMAKE_FOLDER "${CMAKE_FOLDER}/third_party")
@ -43,7 +40,7 @@ endif()
add_subdirectory(third_party) add_subdirectory(third_party)
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
# tests # Subdirectory: tests
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER) if(CMAKE_FOLDER)
set(CMAKE_FOLDER "${CMAKE_FOLDER}/tests") set(CMAKE_FOLDER "${CMAKE_FOLDER}/tests")
@ -53,29 +50,14 @@ endif()
add_subdirectory(tests) add_subdirectory(tests)
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
# Target: cmkr_generate_documentation
# Target cmkr_generate_documentation
set(CMKR_TARGET cmkr_generate_documentation)
set(cmkr_generate_documentation_SOURCES "")
set(CMKR_SOURCES ${cmkr_generate_documentation_SOURCES})
add_library(cmkr_generate_documentation INTERFACE) add_library(cmkr_generate_documentation INTERFACE)
if(cmkr_generate_documentation_SOURCES) set(CMKR_TARGET cmkr_generate_documentation)
target_sources(cmkr_generate_documentation INTERFACE ${cmkr_generate_documentation_SOURCES})
endif()
generate_documentation() generate_documentation()
unset(CMKR_TARGET) # Target: cmkr
unset(CMKR_SOURCES) set(cmkr_SOURCES
# Target cmkr
set(CMKR_TARGET cmkr)
set(cmkr_SOURCES "")
list(APPEND cmkr_SOURCES
"src/arguments.cpp" "src/arguments.cpp"
"src/build.cpp" "src/build.cpp"
"src/cmake_generator.cpp" "src/cmake_generator.cpp"
@ -93,24 +75,12 @@ list(APPEND cmkr_SOURCES
"include/project_parser.hpp" "include/project_parser.hpp"
"cmake/cmkr.cmake" "cmake/cmkr.cmake"
"cmake/version.hpp.in" "cmake/version.hpp.in"
)
list(APPEND cmkr_SOURCES
cmake.toml cmake.toml
) )
set(CMKR_SOURCES ${cmkr_SOURCES})
add_executable(cmkr) add_executable(cmkr)
if(cmkr_SOURCES) target_sources(cmkr PRIVATE ${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)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT cmkr)
endif()
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES})
target_compile_features(cmkr PRIVATE target_compile_features(cmkr PRIVATE
@ -129,10 +99,13 @@ target_link_libraries(cmkr PRIVATE
nlohmann_json nlohmann_json
) )
generate_resources(${CMKR_TARGET}) get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
if(NOT CMKR_VS_STARTUP_PROJECT)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT cmkr)
endif()
unset(CMKR_TARGET) set(CMKR_TARGET cmkr)
unset(CMKR_SOURCES) generate_resources(${CMKR_TARGET})
install( install(
TARGETS TARGETS

@ -64,10 +64,10 @@ arguments:
## Credits ## Credits
- https://github.com/gulrak/filesystem - [gulrak/filesystem](https://github.com/gulrak/filesystem)
- https://github.com/Tessil/ordered-map - [Tessil/ordered-map](https://github.com/Tessil/ordered-map)
- https://github.com/ToruNiina/toml11 - [ToruNiina/toml11](https://github.com/ToruNiina/toml11)
- https://github.com/mpark/variant - [mpark/variant](https://github.com/mpark/variant)
- https://www.svgrepo.com/svg/192268/hammer - [SVG Repo Hammer](https://www.svgrepo.com/svg/192268/hammer)
- https://github.com/can1357 for buying `cmkr.build` ❤️ - [can1357](https://github.com/can1357) for buying `cmkr.build` ❤️
- https://github.com/JustasMasiulis for fixing the dark theme ❤️ - [JustasMasiulis](https://github.com/JustasMasiulis) for fixing the dark theme ❤️

@ -7,11 +7,11 @@ name = "cmkr"
version = "0.2.16" version = "0.2.16"
description = "CMakeLists generator from TOML" description = "CMakeLists generator from TOML"
languages = ["CXX"] languages = ["CXX"]
subdirs = ["third_party", "tests"]
include-after = [ include-after = [
"cmake/generate_documentation.cmake", "cmake/generate_documentation.cmake",
"cmake/generate_resources.cmake" "cmake/generate_resources.cmake"
] ]
subdirs = ["third_party", "tests"]
[target.cmkr_generate_documentation] [target.cmkr_generate_documentation]
type = "interface" type = "interface"

@ -70,8 +70,10 @@ arguments:
## Credits ## Credits
- https://github.com/gulrak/filesystem - [gulrak/filesystem](https://github.com/gulrak/filesystem)
- https://github.com/Tessil/ordered-map - [Tessil/ordered-map](https://github.com/Tessil/ordered-map)
- https://github.com/ToruNiina/toml11 - [ToruNiina/toml11](https://github.com/ToruNiina/toml11)
- https://github.com/mpark/variant - [mpark/variant](https://github.com/mpark/variant)
- https://www.svgrepo.com/svg/192268/hammer - [SVG Repo Hammer](https://www.svgrepo.com/svg/192268/hammer)
- [can1357](https://github.com/can1357) for buying `cmkr.build` ❤️
- [JustasMasiulis](https://github.com/JustasMasiulis) for fixing the dark theme ❤️

@ -3,6 +3,7 @@
#include <mpark/variant.hpp> #include <mpark/variant.hpp>
#include <string> #include <string>
#include <tsl/ordered_map.h> #include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
#include <vector> #include <vector>
namespace cmkr { namespace cmkr {

@ -4,6 +4,7 @@
#include <resources/cmkr.hpp> #include <resources/cmkr.hpp>
#include "fs.hpp" #include "fs.hpp"
#include "project_parser.hpp"
#include <cstdio> #include <cstdio>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
@ -25,7 +26,7 @@ static std::string format(const char *format, tsl::ordered_map<std::string, std:
return s; return s;
} }
static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs::path &toml_dir, bool root_project) { static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs::path &toml_dir, bool is_root_project) {
std::vector<std::string> temp; std::vector<std::string> temp;
auto extract_suffix = [](const fs::path &base, const fs::path &full) { auto extract_suffix = [](const fs::path &base, const fs::path &full) {
@ -38,7 +39,7 @@ static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs
auto stem = name.filename().stem().string(); auto stem = name.filename().stem().string();
auto ext = name.extension(); auto ext = name.extension();
if (root_project && stem == "**" && name == name.filename()) { if (is_root_project && stem == "**" && name == name.filename()) {
throw std::runtime_error("Recursive globbing not allowed in project root: " + name.string()); throw std::runtime_error("Recursive globbing not allowed in project root: " + name.string());
} }
@ -66,11 +67,11 @@ static std::vector<std::string> expand_cmake_path(const fs::path &name, const fs
return temp; return temp;
} }
static std::vector<std::string> expand_cmake_paths(const std::vector<std::string> &sources, const fs::path &toml_dir, bool root_project) { static std::vector<std::string> expand_cmake_paths(const std::vector<std::string> &sources, const fs::path &toml_dir, bool is_root_project) {
// TODO: add duplicate checking // TODO: add duplicate checking
std::vector<std::string> result; std::vector<std::string> result;
for (const auto &src : sources) { for (const auto &src : sources) {
auto expanded = expand_cmake_path(src, toml_dir, root_project); auto expanded = expand_cmake_path(src, toml_dir, is_root_project);
for (const auto &f : expanded) { for (const auto &f : expanded) {
result.push_back(f); result.push_back(f);
} }
@ -416,12 +417,13 @@ struct Generator {
} }
if (!condition.empty()) { if (!condition.empty()) {
cmd("endif")(); cmd("endif")().endl();
} } else if (!itr.second.empty()) {
endl(); endl();
} }
} }
} }
}
void conditional_includes(const parser::ConditionVector &include) { void conditional_includes(const parser::ConditionVector &include) {
handle_condition(include, [this](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); }); handle_condition(include, [this](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
@ -505,7 +507,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
} }
// Root project doesn't have a parent // Root project doesn't have a parent
auto root_project = parent_project == nullptr; auto is_root_project = parent_project == nullptr;
parser::Project project(parent_project, path, false); parser::Project project(parent_project, path, false);
Generator gen(project); Generator gen(project);
@ -521,12 +523,12 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
comment("See " + cmkr_url + " for more information"); comment("See " + cmkr_url + " for more information");
endl(); endl();
if (root_project) { if (is_root_project) {
cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl(); cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl();
if (project.project_msvc_runtime != parser::msvc_last) { if (project.project_msvc_runtime != parser::msvc_last) {
comment("Enable support for MSVC_RUNTIME_LIBRARY"); comment("Enable support for MSVC_RUNTIME_LIBRARY");
cmd("cmake_policy")("SET", "CMP0091", "NEW").endl(); cmd("cmake_policy")("SET", "CMP0091", "NEW");
switch (project.project_msvc_runtime) { switch (project.project_msvc_runtime) {
case parser::msvc_dynamic: case parser::msvc_dynamic:
@ -538,6 +540,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
default: default:
break; break;
} }
endl();
} }
// clang-format on // clang-format on
@ -549,14 +552,13 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
// clang-format on // clang-format on
} }
comment("Regenerate CMakeLists.txt automatically in the root project");
cmd("set")("CMKR_ROOT_PROJECT", "OFF"); cmd("set")("CMKR_ROOT_PROJECT", "OFF");
// clang-format off // clang-format off
cmd("if")("CMAKE_CURRENT_SOURCE_DIR", "STREQUAL", "CMAKE_SOURCE_DIR"); cmd("if")("CMAKE_CURRENT_SOURCE_DIR", "STREQUAL", "CMAKE_SOURCE_DIR");
cmd("set")("CMKR_ROOT_PROJECT", "ON").endl(); cmd("set")("CMKR_ROOT_PROJECT", "ON").endl();
if (!project.cmkr_include.empty()) { if (!project.cmkr_include.empty()) {
comment("Bootstrap cmkr"); comment("Bootstrap cmkr and automatically regenerate CMakeLists.txt");
cmd("include")(project.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT"); cmd("include")(project.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT");
cmd("if")("CMKR_INCLUDE_RESULT"); cmd("if")("CMKR_INCLUDE_RESULT");
cmd("cmkr")(); cmd("cmkr")();
@ -564,7 +566,10 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
} }
comment("Enable folder support"); comment("Enable folder support");
cmd("set_property")("GLOBAL", "PROPERTY", "USE_FOLDERS", "ON"); cmd("set_property")("GLOBAL", "PROPERTY", "USE_FOLDERS", "ON").endl();
comment("Create a configure-time dependency on cmake.toml to improve IDE support");
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY");
cmd("endif")().endl(); cmd("endif")().endl();
// clang-format on // clang-format on
@ -572,14 +577,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
if (!project.cmkr_include.empty() && !fs::exists(cmkr_include) && cmkr_include.is_relative()) { if (!project.cmkr_include.empty() && !fs::exists(cmkr_include) && cmkr_include.is_relative()) {
create_file(cmkr_include, resources::cmkr); create_file(cmkr_include, resources::cmkr);
} }
} } else {
// clang-format off // clang-format off
comment("Create a configure-time dependency on cmake.toml to improve IDE support"); comment("Create a configure-time dependency on cmake.toml to improve IDE support");
cmd("if")("CMKR_ROOT_PROJECT"); cmd("if")("CMKR_ROOT_PROJECT");
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY"); cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY");
cmd("endif")().endl(); cmd("endif")().endl();
// clang-format on // clang-format on
}
// TODO: remove support and replace with global compile-features // TODO: remove support and replace with global compile-features
if (!project.cppflags.empty()) { if (!project.cppflags.empty()) {
@ -616,6 +621,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
endl(); endl();
} }
// TODO: rename to 'variables'?
if (!project.settings.empty()) { if (!project.settings.empty()) {
comment("Settings"); comment("Settings");
for (const auto &set : project.settings) { for (const auto &set : project.settings) {
@ -645,6 +651,13 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
auto version = std::make_pair("VERSION", project.project_version); auto version = std::make_pair("VERSION", project.project_version);
auto description = std::make_pair("DESCRIPTION", project.project_description); auto description = std::make_pair("DESCRIPTION", project.project_description);
cmd("project")(project.project_name, languages, version, description).endl(); cmd("project")(project.project_name, languages, version, description).endl();
for (const auto &language : project.project_languages) {
if (language == "CSharp") {
cmd("include")("CSharpUtilities").endl();
break;
}
}
} }
gen.conditional_includes(project.include_after); gen.conditional_includes(project.include_after);
@ -788,7 +801,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
auto add_subdir = [&](const std::string &dir) { auto add_subdir = [&](const std::string &dir) {
// clang-format off // clang-format off
comment(dir); comment("Subdirectory: " + dir);
cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}"); cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}");
cmd("if")("CMAKE_FOLDER"); cmd("if")("CMAKE_FOLDER");
cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir); cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir);
@ -798,17 +811,19 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
// clang-format on // clang-format on
cmd("add_subdirectory")(dir); cmd("add_subdirectory")(dir);
cmd("set")("CMAKE_FOLDER", "${CMKR_CMAKE_FOLDER}").endl(); cmd("set")("CMAKE_FOLDER", "${CMKR_CMAKE_FOLDER}");
}; };
// generate_cmake is called on the subdirectories recursively later // generate_cmake is called on the subdirectories recursively later
if (!project.project_subdirs.empty()) { if (!project.project_subdirs.empty()) {
gen.handle_condition(project.project_subdirs, [&](const std::string &, const std::vector<std::string> &subdirs) { gen.handle_condition(project.project_subdirs, [&](const std::string &, const std::vector<std::string> &subdirs) {
for (const auto &dir : subdirs) { for (size_t i = 0; i < subdirs.size(); i++) {
add_subdir(dir); add_subdir(subdirs[i]);
if (i + 1 < subdirs.size()) {
endl();
}
} }
}); });
endl();
} }
for (const auto &subdir : project.subdirs) { for (const auto &subdir : project.subdirs) {
ConditionScope cs(gen, subdir.condition); ConditionScope cs(gen, subdir.condition);
@ -817,23 +832,20 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
gen.conditional_cmake(subdir.cmake_before); gen.conditional_cmake(subdir.cmake_before);
add_subdir(subdir.name); add_subdir(subdir.name);
endl();
gen.conditional_includes(subdir.include_after); gen.conditional_includes(subdir.include_after);
gen.conditional_cmake(subdir.cmake_after); gen.conditional_cmake(subdir.cmake_after);
} }
if (!project.targets.empty()) { if (!project.targets.empty()) {
auto root_project = project.root(); auto project_root = project.root();
for (size_t i = 0; i < project.targets.size(); i++) { for (size_t i = 0; i < project.targets.size(); i++) {
if (i > 0) {
endl();
}
const auto &target = project.targets[i]; const auto &target = project.targets[i];
const parser::Template *tmplate = nullptr; const parser::Template *tmplate = nullptr;
std::unique_ptr<ConditionScope> tmplate_cs{}; std::unique_ptr<ConditionScope> tmplate_cs{};
comment("Target " + target.name); comment("Target: " + target.name);
// Check if this target is using a template. // Check if this target is using a template.
if (target.type == parser::target_template) { if (target.type == parser::target_template) {
@ -847,55 +859,114 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
ConditionScope cs(gen, target.condition); ConditionScope cs(gen, target.condition);
cmd("set")("CMKR_TARGET", target.name); // Detect if there is cmake included before/after the target
auto has_include_before = false;
auto has_include_after = false;
{
auto has_include = [](const parser::ConditionVector &includes) {
for (const auto &itr : includes) {
for (const auto &jtr : itr.second) {
return true;
}
}
return false;
};
auto has_include_helper = [&](const parser::Target &target) {
if (!target.cmake_before.empty() || has_include(target.include_before)) {
has_include_before = true;
}
if (!target.cmake_after.empty() || has_include(target.include_after)) {
has_include_after = true;
}
};
if (tmplate != nullptr) {
has_include_helper(tmplate->outline);
}
has_include_helper(target);
}
// Generate the include before
if (has_include_before) {
cmd("set")("CMKR_TARGET", target.name);
}
if (tmplate != nullptr) { if (tmplate != nullptr) {
gen.conditional_includes(tmplate->outline.include_before); gen.conditional_includes(tmplate->outline.include_before);
gen.conditional_cmake(tmplate->outline.cmake_before); gen.conditional_cmake(tmplate->outline.cmake_before);
} }
gen.conditional_includes(target.include_before); gen.conditional_includes(target.include_before);
gen.conditional_cmake(target.cmake_before); gen.conditional_cmake(target.cmake_before);
auto sources_var = target.name + "_SOURCES"; // Merge the sources from the template and the target. The sources
// without condition need to be processed first
bool added_toml = false; parser::Condition<tsl::ordered_set<std::string>> msources;
cmd("set")(sources_var, RawArg("\"\"")).endl(); msources[""].clear();
auto merge_sources = [&msources](const parser::ConditionVector &sources) {
for (const auto &itr : sources) {
auto &source_list = msources[itr.first];
for (const auto &source : itr.second) {
source_list.insert(source);
}
}
};
if (tmplate != nullptr) { if (tmplate != nullptr) {
gen.handle_condition(tmplate->outline.sources, [&](const std::string &condition, const std::vector<std::string> &condition_sources) { merge_sources(tmplate->outline.sources);
auto sources = expand_cmake_paths(condition_sources, path, root_project);
if (sources.empty()) {
auto source_key = condition.empty() ? "sources" : (condition + ".sources");
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
} }
cmd("list")("APPEND", sources_var, sources); merge_sources(target.sources);
});
// Improve IDE support
if (target.type != parser::target_interface) {
msources[""].insert("cmake.toml");
} }
gen.handle_condition(target.sources, [&](const std::string &condition, const std::vector<std::string> &condition_sources) { // If there are only conditional sources we generate a 'set' to
auto sources = expand_cmake_paths(condition_sources, path, root_project); // create an empty source list. The rest is then appended using
// 'list(APPEND ...)'
auto has_sources = false;
for (const auto &itr : msources) {
if (!itr.second.empty()) {
has_sources = true;
break;
}
}
auto sources_var = target.name + "_SOURCES";
auto sources_with_set = true;
if (has_sources && msources[""].empty()) {
sources_with_set = false;
cmd("set")(sources_var, RawArg("\"\"")).endl();
}
gen.handle_condition(msources, [&](const std::string &condition, const tsl::ordered_set<std::string> &source_set) {
std::vector<std::string> condition_sources;
condition_sources.reserve(source_set.size());
for (const auto &source : source_set) {
condition_sources.push_back(source);
}
auto sources = expand_cmake_paths(condition_sources, path, is_root_project);
if (sources.empty()) { if (sources.empty()) {
auto source_key = condition.empty() ? "sources" : (condition + ".sources"); auto source_key = condition.empty() ? "sources" : (condition + ".sources");
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files"); throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
} }
// Do not add cmake.toml twice if (sources_with_set) {
if (!added_toml && std::find(sources.begin(), sources.end(), "cmake.toml") != sources.end()) { // This is a sanity check to make sure the unconditional sources are first
added_toml = true; if (!condition.empty()) {
throw std::runtime_error("Unreachable code, make sure unconditional sources are first");
} }
cmd("set")(sources_var, sources);
sources_with_set = false;
} else {
cmd("list")("APPEND", sources_var, sources); cmd("list")("APPEND", sources_var, sources);
}
}); });
auto target_type = target.type; auto target_type = target.type;
if (tmplate != nullptr) { if (tmplate != nullptr) {
target_type = tmplate->outline.type; if (target_type != parser::target_template) {
throw std::runtime_error("Unreachable code, unexpected target type for template");
} }
target_type = tmplate->outline.type;
if (!added_toml && target_type != parser::target_interface) {
cmd("list")("APPEND", sources_var, std::vector<std::string>{"cmake.toml"}).endl();
} }
cmd("set")("CMKR_SOURCES", "${" + sources_var + "}");
std::string add_command; std::string add_command;
std::string target_type_string; std::string target_type_string;
@ -952,34 +1023,20 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
cmd(add_command)(target.name, target_type_string, "${" + sources_var + "}"); cmd(add_command)(target.name, target_type_string, "${" + sources_var + "}");
} else { } else {
cmd(add_command)(target.name, target_type_string).endl(); cmd(add_command)(target.name, target_type_string).endl();
if (has_sources) {
// clang-format off cmd("target_sources")(target.name, target_type == parser::target_interface ? "INTERFACE" : "PRIVATE",
cmd("if")(sources_var); "${" + sources_var + "}");
cmd("target_sources")(target.name, target_type == parser::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}"); }
cmd("endif")().endl();
// clang-format on
} }
} else { } else {
cmd(add_command)(target.name, target_type_string).endl(); cmd(add_command)(target.name, target_type_string).endl();
if (has_sources) {
// clang-format off
cmd("if")(sources_var);
cmd("target_sources")(target.name, target_type == parser::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}"); cmd("target_sources")(target.name, target_type == parser::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 == parser::target_executable) {
cmd("get_directory_property")("CMKR_VS_STARTUP_PROJECT", "DIRECTORY", "${PROJECT_SOURCE_DIR}", "DEFINITION", "VS_STARTUP_PROJECT");
// clang-format off
cmd("if")("NOT", "CMKR_VS_STARTUP_PROJECT");
cmd("set_property")("DIRECTORY", "${PROJECT_SOURCE_DIR}", "PROPERTY", "VS_STARTUP_PROJECT", target.name);
cmd("endif")().endl();
// clang-format on
} }
if (!target.sources.empty()) { // TODO: support sources from other directories
if (has_sources) {
cmd("source_group")("TREE", "${CMAKE_CURRENT_SOURCE_DIR}", "FILES", "${" + sources_var + "}").endl(); cmd("source_group")("TREE", "${CMAKE_CURRENT_SOURCE_DIR}", "FILES", "${" + sources_var + "}").endl();
} }
@ -1034,7 +1091,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
gen.handle_condition(props, [&](const std::string &, const tsl::ordered_map<std::string, std::string> &properties) { gen.handle_condition(props, [&](const std::string &, const tsl::ordered_map<std::string, std::string> &properties) {
for (const auto &propItr : properties) { for (const auto &propItr : properties) {
if (propItr.first == "MSVC_RUNTIME_LIBRARY") { if (propItr.first == "MSVC_RUNTIME_LIBRARY") {
if (root_project->project_msvc_runtime == parser::msvc_last) { if (project_root->project_msvc_runtime == parser::msvc_last) {
throw std::runtime_error("You cannot set [target].msvc-runtime without setting the root [project].msvc-runtime"); throw std::runtime_error("You cannot set [target].msvc-runtime without setting the root [project].msvc-runtime");
} }
} }
@ -1043,19 +1100,28 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
}); });
} }
// The first executable target will become the Visual Studio startup project
// TODO: this is not working properly
if (target_type == parser::target_executable) {
cmd("get_directory_property")("CMKR_VS_STARTUP_PROJECT", "DIRECTORY", "${PROJECT_SOURCE_DIR}", "DEFINITION", "VS_STARTUP_PROJECT");
// clang-format off
cmd("if")("NOT", "CMKR_VS_STARTUP_PROJECT");
cmd("set_property")("DIRECTORY", "${PROJECT_SOURCE_DIR}", "PROPERTY", "VS_STARTUP_PROJECT", target.name);
cmd("endif")().endl();
// clang-format on
}
// Generate the include after
if (!has_include_before && has_include_after) {
cmd("set")("CMKR_TARGET", target.name);
}
gen.conditional_includes(target.include_after); gen.conditional_includes(target.include_after);
gen.conditional_cmake(target.cmake_after); gen.conditional_cmake(target.cmake_after);
if (tmplate != nullptr) { if (tmplate != nullptr) {
gen.conditional_includes(tmplate->outline.include_after); gen.conditional_includes(tmplate->outline.include_after);
gen.conditional_cmake(tmplate->outline.cmake_after); gen.conditional_cmake(tmplate->outline.cmake_after);
} }
cmd("unset")("CMKR_TARGET");
cmd("unset")("CMKR_SOURCES");
} }
endl();
} }
if (!project.tests.empty()) { if (!project.tests.empty()) {
@ -1081,7 +1147,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
auto dirs = std::make_pair("DIRS", inst.dirs); auto dirs = std::make_pair("DIRS", inst.dirs);
std::vector<std::string> files_data; std::vector<std::string> files_data;
if (!inst.files.empty()) { if (!inst.files.empty()) {
files_data = expand_cmake_paths(inst.files, path, root_project); files_data = expand_cmake_paths(inst.files, path, is_root_project);
if (files_data.empty()) { if (files_data.empty()) {
throw std::runtime_error("[[install]] files wildcard did not resolve to any files"); throw std::runtime_error("[[install]] files wildcard did not resolve to any files");
} }

@ -4,8 +4,6 @@
#include <deque> #include <deque>
#include <stdexcept> #include <stdexcept>
#include <toml.hpp> #include <toml.hpp>
#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
namespace cmkr { namespace cmkr {
namespace parser { namespace parser {

Loading…
Cancel
Save