diff --git a/docs/cmake-toml.md b/docs/cmake-toml.md index 96d3fa6..47e5c6f 100644 --- a/docs/cmake-toml.md +++ b/docs/cmake-toml.md @@ -100,9 +100,12 @@ include-after = ["cmake/after-subdir.cmake"] [options] MYPROJECT_BUILD_TESTS = false MYPROJECT_SPECIAL_OPTION = { value = true, help = "Docstring for this option." } +MYPROJECT_BUILD_EXAMPLES = "root" ``` -Options correspond to [CMake cache variables](https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html) that can be used to customize your project at configure-time. You can configure with `cmake -DMYPROJECT_BUILD_TESTS=ON` to enable the option. Every options automatically gets a corresponding [condition](#conditions). +Options correspond to [CMake cache variables](https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html) that can be used to customize your project at configure-time. You can configure with `cmake -DMYPROJECT_BUILD_TESTS=ON` to enable the option. Every option automatically gets a corresponding [condition](#conditions). + +The special value `root` can be used to set the option to `true` if the project is compiled as the root project (it will be `false` if someone is including your project via `[fetch-content]` or `[subdir]`). ## Variables diff --git a/include/project_parser.hpp b/include/project_parser.hpp index 06e6ce3..0fc5e9f 100644 --- a/include/project_parser.hpp +++ b/include/project_parser.hpp @@ -25,7 +25,7 @@ struct Variable { struct Option { std::string name; std::string help; - bool value = false; + mpark::variant value; }; struct Package { diff --git a/src/cmake_generator.cpp b/src/cmake_generator.cpp index 2a00a7b..c4fba8d 100644 --- a/src/cmake_generator.cpp +++ b/src/cmake_generator.cpp @@ -656,7 +656,13 @@ void generate_cmake(const char *path, const parser::Project *parent_project) { if (!project.options.empty()) { comment("Options"); for (const auto &opt : project.options) { - cmd("option")(opt.name, RawArg(Command::quote(opt.help)), opt.value ? "ON" : "OFF"); + std::string default_val; + if (opt.value.index() == 0) { + default_val = mpark::get<0>(opt.value) ? "ON" : "OFF"; + } else { + default_val = mpark::get<1>(opt.value); + } + cmd("option")(opt.name, RawArg(Command::quote(opt.help)), default_val); } endl(); } diff --git a/src/project_parser.cpp b/src/project_parser.cpp index 91c38cb..3e722cb 100644 --- a/src/project_parser.cpp +++ b/src/project_parser.cpp @@ -377,10 +377,33 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p const auto &value = itr.second; if (value.is_boolean()) { o.value = value.as_boolean(); - } else { + } else if (value.is_string()) { + auto str = std::string(value.as_string()); + if (str == "root") { + o.value = std::string("${CMKR_ROOT_PROJECT}"); + } else { + throw_key_error("Unsupported option value '" + str + "'", str, value); + } + } else if (value.is_table()) { auto &option = checker.create(value); option.optional("help", o.help); - option.optional("value", o.value); + if (option.contains("value")) { + const auto &ovalue = option.find("value"); + if (ovalue.is_boolean()) { + o.value = ovalue.as_boolean(); + } else if (ovalue.is_string()) { + auto str = std::string(ovalue.as_string()); + if (str == "root") { + o.value = std::string("${CMKR_ROOT_PROJECT}"); + } else { + throw_key_error("Unsupported option value '" + str + "'", str, value); + } + } else { + throw_key_error(toml::concat_to_string("Unsupported value type: ", ovalue.type()), "value", value); + } + } + } else { + throw_key_error(toml::concat_to_string("Unsupported value type: ", itr.second.type()), itr.first, itr.second); } options.push_back(o); conditions.emplace(o.name, o.name);