Skip to content

Commit 53820c9

Browse files
committed
Support $<condition> in unnamed conditions
1 parent ff7e4b8 commit 53820c9

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

docs/cmake-toml.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ sources = ["src/main.cpp"]
8888
ptr64.sources = ["src/ptr64_only.cpp"]
8989
```
9090

91-
Instead of a named condition you can also specify a [CMake expression](https://cmake.org/cmake/help/latest/command/if.html#condition-syntax) directly.
91+
Instead of a named condition you can also specify a [CMake expression](https://cmake.org/cmake/help/latest/command/if.html#condition-syntax) in quotes. Instances of `$<name>` are replaced with the corresponding condition. For example: `"CONDITIONS_BUILD_TESTS AND $<linux>"` becomes `CONDITIONS_BUILD_TESTS AND (CMAKE_SYSTEM_NAME MATCHES "Linux")` in the final `CMakeLists.txt` file.
9292

9393
### Predefined conditions
9494

src/cmake_generator.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,12 +547,57 @@ struct Generator {
547547
// NOTE: this should have been caught by the parser already
548548
throw std::runtime_error("Condition '" + condition + "' is not defined");
549549
}
550-
cmd("if", "NOTE: unnamed condition")(RawArg(condition));
550+
cmd("if", "NOTE: unnamed condition")(RawArg(cmake_condition(condition)));
551551
} else {
552552
cmd("if", condition)(RawArg(found->second));
553553
}
554554
return true;
555555
}
556+
557+
private:
558+
std::string cmake_condition(const std::string &condition) {
559+
// HACK: this replaces '$<name>' with the value of the 'name' condition. We can safely
560+
// reuse the generator expression syntax, because it is not valid in CMake conditions.
561+
// TODO: properly handle quoted arguments (using a simple state machine):
562+
// https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#quoted-argument
563+
std::string result = "";
564+
bool in_replacement = false;
565+
std::string temp;
566+
for (size_t i = 0; i < condition.length(); i++) {
567+
if (in_replacement) {
568+
if (condition[i] == '>') {
569+
in_replacement = false;
570+
if (temp.empty()) {
571+
throw std::runtime_error("Empty replacement in condition '" + condition + "'");
572+
}
573+
auto found = project.conditions.find(temp);
574+
if (found == project.conditions.end()) {
575+
throw std::runtime_error("Unknown condition '" + temp + "' in replacement");
576+
}
577+
auto has_space = found->second.find(' ') != std::string::npos;
578+
if (has_space) {
579+
result += '(';
580+
}
581+
result += found->second;
582+
if (has_space) {
583+
result += ')';
584+
}
585+
temp.clear();
586+
} else {
587+
temp += condition[i];
588+
}
589+
} else if (condition[i] == '$' && i + 1 < condition.length() && condition[i + 1] == '<') {
590+
i++;
591+
in_replacement = true;
592+
} else {
593+
result += condition[i];
594+
}
595+
}
596+
if (!temp.empty()) {
597+
throw std::runtime_error("Unterminated replacement in condition '" + condition + "'");
598+
}
599+
return result;
600+
}
556601
};
557602

558603
struct ConditionScope {

tests/conditions/cmake.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "conditions"
33
cmake-after = "set(CUSTOM ON)"
44

55
[options]
6-
CONDITIONS_BUILD_TESTS = false
6+
CONDITIONS_BUILD_TESTS = "root"
77

88
[conditions]
99
custom = "CUSTOM"
@@ -19,6 +19,7 @@ linux.cmake-after = "message(STATUS linux-after)"
1919
unix.cmake-after = "message(STATUS unix-after)"
2020
custom.cmake-after = "message(STATUS custom-after)"
2121
build-tests.cmake-after = "message(STATUS build-tests)"
22+
"CONDITIONS_BUILD_TESTS AND $<linux>".cmake-after = "message(STATUS linux-tests)"
2223

2324
[target.example.properties]
2425
AUTOMOC = false

0 commit comments

Comments
 (0)