Support $<condition> in unnamed conditions

main
Duncan Ogilvie 5 months ago
parent ff7e4b8f23
commit 53820c9f65

@ -88,7 +88,7 @@ sources = ["src/main.cpp"]
ptr64.sources = ["src/ptr64_only.cpp"]
```
Instead of a named condition you can also specify a [CMake expression](https://cmake.org/cmake/help/latest/command/if.html#condition-syntax) directly.
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.
### Predefined conditions

@ -547,12 +547,57 @@ struct Generator {
// NOTE: this should have been caught by the parser already
throw std::runtime_error("Condition '" + condition + "' is not defined");
}
cmd("if", "NOTE: unnamed condition")(RawArg(condition));
cmd("if", "NOTE: unnamed condition")(RawArg(cmake_condition(condition)));
} else {
cmd("if", condition)(RawArg(found->second));
}
return true;
}
private:
std::string cmake_condition(const std::string &condition) {
// HACK: this replaces '$<name>' with the value of the 'name' condition. We can safely
// reuse the generator expression syntax, because it is not valid in CMake conditions.
// TODO: properly handle quoted arguments (using a simple state machine):
// https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#quoted-argument
std::string result = "";
bool in_replacement = false;
std::string temp;
for (size_t i = 0; i < condition.length(); i++) {
if (in_replacement) {
if (condition[i] == '>') {
in_replacement = false;
if (temp.empty()) {
throw std::runtime_error("Empty replacement in condition '" + condition + "'");
}
auto found = project.conditions.find(temp);
if (found == project.conditions.end()) {
throw std::runtime_error("Unknown condition '" + temp + "' in replacement");
}
auto has_space = found->second.find(' ') != std::string::npos;
if (has_space) {
result += '(';
}
result += found->second;
if (has_space) {
result += ')';
}
temp.clear();
} else {
temp += condition[i];
}
} else if (condition[i] == '$' && i + 1 < condition.length() && condition[i + 1] == '<') {
i++;
in_replacement = true;
} else {
result += condition[i];
}
}
if (!temp.empty()) {
throw std::runtime_error("Unterminated replacement in condition '" + condition + "'");
}
return result;
}
};
struct ConditionScope {

@ -3,7 +3,7 @@ name = "conditions"
cmake-after = "set(CUSTOM ON)"
[options]
CONDITIONS_BUILD_TESTS = false
CONDITIONS_BUILD_TESTS = "root"
[conditions]
custom = "CUSTOM"
@ -19,6 +19,7 @@ linux.cmake-after = "message(STATUS linux-after)"
unix.cmake-after = "message(STATUS unix-after)"
custom.cmake-after = "message(STATUS custom-after)"
build-tests.cmake-after = "message(STATUS build-tests)"
"CONDITIONS_BUILD_TESTS AND $<linux>".cmake-after = "message(STATUS linux-tests)"
[target.example.properties]
AUTOMOC = false

Loading…
Cancel
Save