mirror of
https://github.com/build-cpp/cmkr
synced 2026-06-08 13:22:55 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 109c4bc99f | |||
| cad85f0bb1 | |||
| 53c88ceafa | |||
| d2aa15b1c7 | |||
| e6ded077cf | |||
| 3615ccab94 | |||
| 73622aa5ba | |||
| 69d844a152 | |||
| af9a117f50 | |||
| 5fe8220728 | |||
| 28f541cd3c | |||
| 2f3fd7b95e | |||
| 07d99c582d | |||
| 5af2385cc3 | |||
| 981c48dbc5 |
Generated
+1
-1
@@ -25,7 +25,7 @@ project(cmkr
|
||||
LANGUAGES
|
||||
CXX
|
||||
VERSION
|
||||
0.2.14
|
||||
0.2.16
|
||||
DESCRIPTION
|
||||
"CMakeLists generator from TOML"
|
||||
)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ cmkr-include = false
|
||||
|
||||
[project]
|
||||
name = "cmkr"
|
||||
version = "0.2.14"
|
||||
version = "0.2.16"
|
||||
description = "CMakeLists generator from TOML"
|
||||
languages = ["CXX"]
|
||||
subdirs = ["third_party", "tests"]
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ include_guard()
|
||||
|
||||
# Change these defaults to point to your infrastructure if desired
|
||||
set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
|
||||
set(CMKR_TAG "v0.2.14" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
set(CMKR_TAG "v0.2.16" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
|
||||
|
||||
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
option(CMKR_GENERATE_DOCUMENTATION "Generate cmkr documentation" ${CMKR_ROOT_PROJECT})
|
||||
set(CMKR_TESTS "" CACHE INTERNAL "List of test directories in the order declared in tests/cmake.toml")
|
||||
|
||||
if(CMKR_GENERATE_DOCUMENTATION)
|
||||
# Hook the add_test function to capture the tests in the order declared in tests/cmake.toml
|
||||
function(add_test)
|
||||
cmake_parse_arguments(TEST "" "WORKING_DIRECTORY" "" ${ARGN})
|
||||
get_filename_component(TEST_WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}" NAME)
|
||||
list(APPEND CMKR_TESTS "${TEST_WORKING_DIRECTORY}")
|
||||
set(CMKR_TESTS "${CMKR_TESTS}" CACHE INTERNAL "")
|
||||
_add_test(${test} ${ARGN})
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
function(generate_documentation)
|
||||
if(CMKR_GENERATE_DOCUMENTATION)
|
||||
message(STATUS "[cmkr] Generating documentation...")
|
||||
|
||||
# Extract the order of the tests
|
||||
set(CMKR_TESTS "")
|
||||
file(READ "${PROJECT_SOURCE_DIR}/tests/cmake.toml" tests_toml NO_HEX_CONVERSION)
|
||||
string(REGEX MATCHALL "working-directory = \"([^\"]+)\"" tests_match "${tests_toml}")
|
||||
foreach(match ${tests_match})
|
||||
if(match MATCHES "working-directory = \"([^\"]+)\"")
|
||||
list(APPEND CMKR_TESTS "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
message(FATAL_ERROR "This should not happen (wrong regex?)")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Delete previously generated examples
|
||||
set(example_folder "${PROJECT_SOURCE_DIR}/docs/examples")
|
||||
|
||||
@@ -27,6 +27,7 @@ name = "myproject"
|
||||
version = "1.0.0"
|
||||
description = "Description of the project"
|
||||
languages = ["C", "CXX"]
|
||||
msvc-runtime = "" # dynamic (implicit default), static
|
||||
cmake-before = """
|
||||
message(STATUS "CMake injected before the project() call")
|
||||
"""
|
||||
@@ -58,6 +59,8 @@ sources = ["src/main.cpp"]
|
||||
windows.sources = ["src/windows_specific.cpp"]
|
||||
```
|
||||
|
||||
### Predefined conditions
|
||||
|
||||
The following conditions are predefined (you can override them if you desire):
|
||||
|
||||
```toml
|
||||
@@ -144,6 +147,7 @@ alias = "mytarget::mytarget"
|
||||
type = "static" # executable, shared (DLL), static, interface, object, library, custom
|
||||
headers = ["src/mytarget.h"]
|
||||
sources = ["src/mytarget.cpp"]
|
||||
msvc-runtime = "" # dynamic (implicit default), static
|
||||
|
||||
# The keys below match the target_xxx CMake commands
|
||||
# Keys prefixed with private- will get PRIVATE visibility
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
# Automatically generated from tests/msvc-runtime/cmake.toml - DO NOT EDIT
|
||||
layout: default
|
||||
title: Static MSVC runtime
|
||||
permalink: /examples/msvc-runtime
|
||||
parent: Examples
|
||||
nav_order: 8
|
||||
---
|
||||
|
||||
# Static MSVC runtime
|
||||
|
||||
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "msvc-runtime"
|
||||
description = "Static MSVC runtime"
|
||||
msvc-runtime = "static"
|
||||
|
||||
# This target will compile with a static runtime
|
||||
[target.static-runtime]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
|
||||
# This target overrides the [project].msvc-runtime
|
||||
[target.dynamic-runtime]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
msvc-runtime = "dynamic"
|
||||
```
|
||||
|
||||
|
||||
|
||||
<sup><sub>This page was automatically generated from [tests/msvc-runtime/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/msvc-runtime/cmake.toml).</sub></sup>
|
||||
@@ -67,7 +67,6 @@ struct Target {
|
||||
TargetType type = target_last;
|
||||
std::string type_name;
|
||||
|
||||
ConditionVector headers;
|
||||
ConditionVector sources;
|
||||
|
||||
// https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands
|
||||
@@ -152,7 +151,17 @@ struct Content {
|
||||
ConditionVector include_after;
|
||||
};
|
||||
|
||||
enum MsvcRuntimeType {
|
||||
msvc_dynamic,
|
||||
msvc_static,
|
||||
msvc_last,
|
||||
};
|
||||
|
||||
extern const char *msvcRuntimeTypeNames[msvc_last];
|
||||
|
||||
struct Project {
|
||||
const Project *parent;
|
||||
|
||||
// This is the CMake version required to use all cmkr versions.
|
||||
std::string cmake_version = "3.15";
|
||||
std::string cmkr_include = "cmkr.cmake";
|
||||
@@ -170,6 +179,7 @@ struct Project {
|
||||
std::string project_version;
|
||||
std::string project_description;
|
||||
std::vector<std::string> project_languages;
|
||||
MsvcRuntimeType project_msvc_runtime = msvc_last;
|
||||
Condition<std::string> cmake_before;
|
||||
Condition<std::string> cmake_after;
|
||||
ConditionVector include_before;
|
||||
@@ -187,6 +197,7 @@ struct Project {
|
||||
std::vector<Subdir> subdirs;
|
||||
|
||||
Project(const Project *parent, const std::string &path, bool build);
|
||||
const Project *root() const;
|
||||
};
|
||||
|
||||
bool is_root_path(const std::string &path);
|
||||
|
||||
@@ -524,6 +524,21 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
if (root_project) {
|
||||
cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl();
|
||||
|
||||
if (project.project_msvc_runtime != parser::msvc_last) {
|
||||
comment("Enable support for MSVC_RUNTIME_LIBRARY");
|
||||
cmd("cmake_policy")("SET", "CMP0091", "NEW").endl();
|
||||
|
||||
switch (project.project_msvc_runtime) {
|
||||
case parser::msvc_dynamic:
|
||||
cmd("set")("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL");
|
||||
break;
|
||||
case parser::msvc_static:
|
||||
cmd("set")("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded$<$<CONFIG:Debug>:Debug>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
if (!project.allow_in_tree) {
|
||||
// clang-format off
|
||||
cmd("if")("CMAKE_SOURCE_DIR", "STREQUAL", "CMAKE_BINARY_DIR");
|
||||
@@ -806,6 +821,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
}
|
||||
|
||||
if (!project.targets.empty()) {
|
||||
auto root_project = project.root();
|
||||
for (size_t i = 0; i < project.targets.size(); i++) {
|
||||
if (i > 0) {
|
||||
endl();
|
||||
@@ -1014,6 +1030,13 @@ 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) {
|
||||
for (const auto &propItr : properties) {
|
||||
if (propItr.first == "MSVC_RUNTIME_LIBRARY") {
|
||||
if (root_project->project_msvc_runtime == parser::msvc_last) {
|
||||
throw std::runtime_error("You cannot set [target].msvc-runtime without setting the root [project].msvc-runtime");
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd("set_target_properties")(target.name, "PROPERTIES", properties);
|
||||
});
|
||||
}
|
||||
|
||||
+70
-6
@@ -21,6 +21,17 @@ static TargetType parse_targetType(const std::string &name) {
|
||||
return target_last;
|
||||
}
|
||||
|
||||
const char *msvcRuntimeTypeNames[msvc_last] = {"dynamic", "static"};
|
||||
|
||||
static MsvcRuntimeType parse_msvcRuntimeType(const std::string &name) {
|
||||
for (int i = 0; i < msvc_last; i++) {
|
||||
if (name == msvcRuntimeTypeNames[i]) {
|
||||
return static_cast<MsvcRuntimeType>(i);
|
||||
}
|
||||
}
|
||||
return msvc_last;
|
||||
}
|
||||
|
||||
using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
|
||||
|
||||
static std::string format_key_error(const std::string &error, const toml::key &ky, const TomlBasicValue &value) {
|
||||
@@ -192,7 +203,7 @@ class TomlCheckerRoot {
|
||||
}
|
||||
};
|
||||
|
||||
Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
Project::Project(const Project *parent, const std::string &path, bool build) : parent(parent) {
|
||||
const auto toml_path = fs::path(path) / "cmake.toml";
|
||||
if (!fs::exists(toml_path)) {
|
||||
throw std::runtime_error("File not found '" + toml_path.string() + "'");
|
||||
@@ -276,6 +287,21 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
project.optional("include-before", include_before);
|
||||
project.optional("include-after", include_after);
|
||||
project.optional("subdirs", project_subdirs);
|
||||
|
||||
std::string msvc_runtime;
|
||||
project.optional("msvc-runtime", msvc_runtime);
|
||||
if (!msvc_runtime.empty()) {
|
||||
project_msvc_runtime = parse_msvcRuntimeType(msvc_runtime);
|
||||
if (project_msvc_runtime == msvc_last) {
|
||||
std::string error = "Unknown runtime '" + msvc_runtime + "'\n";
|
||||
error += "Available types:\n";
|
||||
for (std::string type_name : msvcRuntimeTypeNames) {
|
||||
error += " - " + type_name + "\n";
|
||||
}
|
||||
error.pop_back(); // Remove last newline
|
||||
throw std::runtime_error(format_key_error(error, msvc_runtime, project.find("msvc-runtime")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checker.contains("subdir")) {
|
||||
@@ -487,9 +513,18 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
throw std::runtime_error(format_key_error(error, target.type_name, t.find("type")));
|
||||
}
|
||||
|
||||
t.optional("headers", target.headers);
|
||||
t.optional("sources", target.sources);
|
||||
|
||||
// Merge the headers into the sources
|
||||
ConditionVector headers;
|
||||
t.optional("headers", headers);
|
||||
for (const auto &itr : headers) {
|
||||
auto &dest = target.sources[itr.first];
|
||||
for (const auto &jtr : itr.second) {
|
||||
dest.push_back(jtr);
|
||||
}
|
||||
}
|
||||
|
||||
t.optional("compile-definitions", target.compile_definitions);
|
||||
t.optional("private-compile-definitions", target.private_compile_definitions);
|
||||
|
||||
@@ -514,10 +549,32 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
t.optional("precompile-headers", target.precompile_headers);
|
||||
t.optional("private-precompile-headers", target.private_precompile_headers);
|
||||
|
||||
if (!target.headers.empty()) {
|
||||
auto &sources = target.sources.nth(0).value();
|
||||
const auto &headers = target.headers.nth(0)->second;
|
||||
sources.insert(sources.end(), headers.begin(), headers.end());
|
||||
Condition<std::string> msvc_runtime;
|
||||
t.optional("msvc-runtime", msvc_runtime);
|
||||
for (const auto &condItr : msvc_runtime) {
|
||||
switch (parse_msvcRuntimeType(condItr.second)) {
|
||||
case msvc_dynamic:
|
||||
target.properties[condItr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL";
|
||||
break;
|
||||
case msvc_static:
|
||||
target.properties[condItr.first]["MSVC_RUNTIME_LIBRARY"] = "MultiThreaded$<$<CONFIG:Debug>:Debug>";
|
||||
break;
|
||||
default: {
|
||||
std::string error = "Unknown runtime '" + condItr.second + "'\n";
|
||||
error += "Available types:\n";
|
||||
for (std::string type_name : msvcRuntimeTypeNames) {
|
||||
error += " - " + type_name + "\n";
|
||||
}
|
||||
error.pop_back(); // Remove last newline
|
||||
const TomlBasicValue *report;
|
||||
if (condItr.first.empty()) {
|
||||
report = &t.find("msvc-runtime");
|
||||
} else {
|
||||
report = &t.find(condItr.first).as_table().find("msvc-runtime").value();
|
||||
}
|
||||
throw std::runtime_error(format_key_error(error, condItr.second, *report));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.optional("condition", target.condition);
|
||||
@@ -661,6 +718,13 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
checker.check(conditions, true);
|
||||
}
|
||||
|
||||
const Project *Project::root() const {
|
||||
auto root = this;
|
||||
while (root->parent != nullptr)
|
||||
root = root->parent;
|
||||
return root;
|
||||
}
|
||||
|
||||
bool is_root_path(const std::string &path) {
|
||||
const auto toml_path = fs::path(path) / "cmake.toml";
|
||||
if (!fs::exists(toml_path)) {
|
||||
|
||||
Generated
+12
@@ -88,3 +88,15 @@ add_test(
|
||||
build
|
||||
)
|
||||
|
||||
if(MSVC) # msvc
|
||||
add_test(
|
||||
NAME
|
||||
msvc-runtime
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/msvc-runtime"
|
||||
COMMAND
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -45,3 +45,10 @@ name = "templates"
|
||||
working-directory = "templates"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
arguments = ["build"]
|
||||
|
||||
[[test]]
|
||||
condition = "msvc"
|
||||
name = "msvc-runtime"
|
||||
working-directory = "msvc-runtime"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
arguments = ["build"]
|
||||
@@ -0,0 +1,15 @@
|
||||
[project]
|
||||
name = "msvc-runtime"
|
||||
description = "Static MSVC runtime"
|
||||
msvc-runtime = "static"
|
||||
|
||||
# This target will compile with a static runtime
|
||||
[target.static-runtime]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
|
||||
# This target overrides the [project].msvc-runtime
|
||||
[target.dynamic-runtime]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
msvc-runtime = "dynamic"
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <cstdio>
|
||||
|
||||
int main() {
|
||||
puts("Hello from cmkr(msvc-static)!");
|
||||
}
|
||||
Reference in New Issue
Block a user