Skip to content

Commit 459ebb1

Browse files
committed
Support conditions everywhere
Closes #36
1 parent 490869b commit 459ebb1

File tree

3 files changed

+67
-38
lines changed

3 files changed

+67
-38
lines changed

include/project_parser.hpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
namespace cmkr {
99
namespace parser {
1010

11+
template <typename T>
12+
using Condition = tsl::ordered_map<std::string, T>;
13+
14+
using ConditionVector = Condition<std::vector<std::string>>;
15+
1116
struct Setting {
1217
std::string name;
1318
std::string comment;
@@ -24,6 +29,7 @@ struct Option {
2429

2530
struct Package {
2631
std::string name;
32+
std::string condition;
2733
std::string version;
2834
bool required = true;
2935
bool config = false;
@@ -52,11 +58,6 @@ enum TargetType {
5258
target_object,
5359
};
5460

55-
template <typename T>
56-
using Condition = tsl::ordered_map<std::string, T>;
57-
58-
using ConditionVector = Condition<std::vector<std::string>>;
59-
6061
struct Target {
6162
std::string name;
6263
TargetType type = {};
@@ -101,13 +102,15 @@ struct Target {
101102

102103
struct Test {
103104
std::string name;
105+
std::string condition;
104106
std::vector<std::string> configurations;
105107
std::string working_directory;
106108
std::string command;
107109
std::vector<std::string> arguments;
108110
};
109111

110112
struct Install {
113+
std::string condition;
111114
std::vector<std::string> targets;
112115
std::vector<std::string> files;
113116
std::vector<std::string> dirs;
@@ -126,6 +129,7 @@ struct Subdir {
126129

127130
struct Content {
128131
std::string name;
132+
std::string condition;
129133
tsl::ordered_map<std::string, std::string> arguments;
130134
};
131135

src/cmake_generator.cpp

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,10 @@ static std::string tolf(const std::string &str) {
316316
};
317317

318318
struct Generator {
319-
Generator(parser::Project &project) : project(project) {}
319+
Generator(const parser::Project &project) : project(project) {}
320320
Generator(const Generator &) = delete;
321321

322-
parser::Project &project;
322+
const parser::Project &project;
323323
std::stringstream ss;
324324
int indent = 0;
325325

@@ -383,11 +383,7 @@ struct Generator {
383383
for (const auto &itr : value) {
384384
const auto &condition = itr.first;
385385
if (!condition.empty()) {
386-
if (project.conditions.count(condition) == 0) {
387-
// TODO: somehow print line number information here?
388-
throw std::runtime_error("Unknown condition '" + condition + "'");
389-
}
390-
cmd("if", condition)(RawArg(project.conditions[condition]));
386+
cmd("if", condition)(RawArg(project.conditions.at(condition)));
391387
}
392388

393389
if (!itr.second.empty()) {
@@ -403,6 +399,27 @@ struct Generator {
403399
}
404400
};
405401

402+
struct ConditionScope {
403+
Generator &gen;
404+
bool endif = false;
405+
406+
ConditionScope(Generator &gen, const std::string &condition) : gen(gen) {
407+
if (!condition.empty()) {
408+
gen.cmd("if", condition)(RawArg(gen.project.conditions.at(condition)));
409+
endif = true;
410+
}
411+
}
412+
413+
ConditionScope(const ConditionScope &) = delete;
414+
ConditionScope(ConditionScope &&) = delete;
415+
416+
~ConditionScope() {
417+
if (endif) {
418+
gen.cmd("endif")();
419+
}
420+
}
421+
};
422+
406423
static bool vcpkg_valid_identifier(const std::string &name) {
407424
// prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default
408425
auto is_reserved = [](const std::string &s) {
@@ -679,7 +696,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
679696
if (!project.contents.empty()) {
680697
cmd("include")("FetchContent").endl();
681698
for (const auto &content : project.contents) {
682-
cmd("message")("STATUS", "Fetching " + content.name + "...");
699+
ConditionScope cs(gen, content.condition);
700+
std::string version_info = "";
701+
if (content.arguments.contains("GIT_TAG")) {
702+
version_info = " (" + content.arguments.at("GIT_TAG") + ")";
703+
} else if (content.arguments.contains("SVN_REVISION")) {
704+
version_info = " (" + content.arguments.at("SVN_REVISION") + ")";
705+
}
706+
cmd("message")("STATUS", "Fetching " + content.name + version_info + "...");
683707
ss << "FetchContent_Declare(\n\t" << content.name << "\n";
684708
for (const auto &arg : content.arguments) {
685709
ss << "\t" << arg.first << "\n\t\t" << arg.second << "\n";
@@ -698,6 +722,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
698722
auto required = dep.required ? "REQUIRED" : "";
699723
auto config = dep.config ? "CONFIG" : "";
700724
auto components = std::make_pair("COMPONENTS", dep.components);
725+
ConditionScope cs(gen, dep.condition);
701726
cmd("find_package")(dep.name, version, required, config, components).endl();
702727
}
703728
}
@@ -727,13 +752,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
727752
endl();
728753
}
729754
for (const auto &subdir : project.subdirs) {
730-
if (!subdir.condition.empty()) {
731-
const auto &condition = subdir.condition;
732-
if (project.conditions.count(condition) == 0) {
733-
throw std::runtime_error("Unknown condition '" + condition + "' for [subdir." + subdir.name + "]");
734-
}
735-
gen.cmd("if", condition)(RawArg(project.conditions[condition]));
736-
}
755+
ConditionScope cs(gen, subdir.condition);
737756

738757
gen.handle_condition(subdir.include_before,
739758
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
@@ -743,23 +762,18 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
743762

744763
gen.handle_condition(subdir.include_after, [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
745764
gen.handle_condition(subdir.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
746-
747-
if (!subdir.condition.empty()) {
748-
cmd("endif")();
749-
}
750765
}
751766

752767
if (!project.targets.empty()) {
753-
for (const auto &target : project.targets) {
768+
for (size_t i = 0; i < project.targets.size(); i++) {
769+
if (i > 0) {
770+
endl();
771+
}
772+
773+
const auto &target = project.targets[i];
754774
comment("Target " + target.name);
755775

756-
if (!target.condition.empty()) {
757-
const auto &condition = target.condition;
758-
if (project.conditions.count(condition) == 0) {
759-
throw std::runtime_error("Unknown condition '" + condition + "' for [target." + target.name + "]");
760-
}
761-
gen.cmd("if", condition)(RawArg(project.conditions[condition]));
762-
}
776+
ConditionScope cs(gen, target.condition);
763777

764778
cmd("set")("CMKR_TARGET", target.name);
765779

@@ -901,13 +915,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
901915

902916
cmd("unset")("CMKR_TARGET");
903917
cmd("unset")("CMKR_SOURCES");
904-
905-
if (!target.condition.empty()) {
906-
cmd("endif")();
907-
}
908-
909-
endl();
910918
}
919+
920+
endl();
911921
}
912922

913923
if (!project.tests.empty()) {
@@ -922,6 +932,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
922932
auto working_directory = std::make_pair("WORKING_DIRECTORY", dir);
923933
auto command = std::make_pair("COMMAND", test.command);
924934
auto arguments = std::make_pair("", test.arguments);
935+
ConditionScope cs(gen, test.condition);
925936
cmd("add_test")(name, configurations, working_directory, command, arguments).endl();
926937
}
927938
}
@@ -941,6 +952,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
941952
auto configs = std::make_pair("CONFIGURATIONS", inst.configs);
942953
auto destination = std::make_pair("DESTINATION", inst.destination);
943954
auto component = std::make_pair("COMPONENT", inst.targets.empty() ? "" : inst.targets.front());
955+
ConditionScope cs(gen, inst.condition);
944956
cmd("install")(targets, dirs, files, configs, destination, component);
945957
}
946958
}

src/project_parser.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ class TomlChecker {
145145
}
146146
}
147147
throw std::runtime_error(format_key_error("Unknown key '" + ky + "'", ky, itr.second));
148+
} else if (ky == "condition") {
149+
std::string condition = itr.second.as_string();
150+
if (!conditions.contains(condition)) {
151+
throw std::runtime_error(format_key_error("Unknown condition '" + condition + "'", condition, itr.second));
152+
}
148153
}
149154
}
150155
}
@@ -330,6 +335,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
330335
p.version = itr.second.as_string();
331336
} else {
332337
auto &pkg = checker.create(value);
338+
pkg.optional("condition", p.condition);
333339
pkg.optional("version", p.version);
334340
pkg.optional("required", p.required);
335341
pkg.optional("config", p.config);
@@ -347,6 +353,11 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
347353
content.name = itr.first;
348354
for (const auto &argItr : itr.second.as_table()) {
349355
auto key = argItr.first;
356+
if (key == "condition") {
357+
content.condition = argItr.second.as_string();
358+
continue;
359+
}
360+
350361
if (key == "git") {
351362
key = "GIT_REPOSITORY";
352363
} else if (key == "tag") {
@@ -469,6 +480,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
469480
auto &t = checker.create(value);
470481
Test test;
471482
t.required("name", test.name);
483+
t.optional("condition", test.condition);
472484
t.optional("configurations", test.configurations);
473485
t.optional("working-directory", test.working_directory);
474486
t.required("command", test.command);
@@ -482,6 +494,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
482494
for (const auto &value : is) {
483495
auto &i = checker.create(value);
484496
Install inst;
497+
i.optional("condition", inst.condition);
485498
i.optional("targets", inst.targets);
486499
i.optional("files", inst.files);
487500
i.optional("dirs", inst.dirs);

0 commit comments

Comments
 (0)