Refactor msvc-static to msvc-runtime

main
Duncan Ogilvie 2 years ago
parent af9a117f50
commit 69d844a152

@ -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>

@ -1,27 +0,0 @@
---
# Automatically generated from tests/msvc-static/cmake.toml - DO NOT EDIT
layout: default
title: msvc static
permalink: /examples/msvc-static
parent: Examples
nav_order: 8
---
# msvc static
A msvc-static `cmake.toml` project:
```toml
[project]
name = "msvc-static"
description = "msvc static"
[target.basic]
type = "executable"
sources = ["src/msvc-static.cpp"]
msvc-static = true
```
<sup><sub>This page was automatically generated from [tests/msvc-static/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/msvc-static/cmake.toml).</sub></sup>

@ -102,8 +102,6 @@ struct Target {
Condition<std::string> cmake_after;
ConditionVector include_before;
ConditionVector include_after;
bool allow_msvc_static = false;
};
struct Template {
@ -153,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";
@ -171,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;
@ -188,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);

@ -523,10 +523,12 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
if (root_project) {
cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl();
// clang-format off
cmd("if")("POLICY", "CMP0091");
cmd("cmake_policy")("SET", "CMP0091", "NEW");
cmd("endif")().endl();
if (project.project_msvc_runtime != parser::msvc_last) {
comment("Enable support for MSVC_RUNTIME_LIBRARY");
cmd("cmake_policy")("SET", "CMP0091", "NEW").endl();
}
// clang-format on
if (!project.allow_in_tree) {
// clang-format off
@ -810,6 +812,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();
@ -1018,6 +1021,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);
});
}
@ -1030,10 +1040,6 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
gen.conditional_cmake(tmplate->outline.cmake_after);
}
if (target.allow_msvc_static && !target.name.empty()) {
cmd("set_property")("TARGET", target.name, "PROPERTY", "MSVC_RUNTIME_LIBRARY", "MultiThreaded$<$<CONFIG:Debug>:Debug>");
}
cmd("unset")("CMKR_TARGET");
cmd("unset")("CMKR_SOURCES");
}

@ -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")) {
@ -523,7 +549,33 @@ 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);
t.optional("msvc-static", target.allow_msvc_static);
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);
t.optional("alias", target.alias);
@ -666,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)) {

20
tests/CMakeLists.txt generated

@ -88,13 +88,15 @@ add_test(
build
)
add_test(
NAME
msvc-static
WORKING_DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/msvc-static"
COMMAND
"$<TARGET_FILE:cmkr>"
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"

@ -1,11 +0,0 @@
# A msvc-static `cmake.toml` project:
[project]
name = "msvc-static"
description = "msvc static"
[target.basic]
type = "executable"
sources = ["src/msvc-static.cpp"]
msvc-static = true
Loading…
Cancel
Save