Skip to content

Commit 8537096

Browse files
committed
Improved fetch-content support
Closes #38
1 parent 06a4c04 commit 8537096

File tree

3 files changed

+72
-28
lines changed

3 files changed

+72
-28
lines changed

include/project_parser.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct Install {
133133
struct Subdir {
134134
std::string name;
135135
std::string condition;
136+
136137
Condition<std::string> cmake_before;
137138
Condition<std::string> cmake_after;
138139
ConditionVector include_before;
@@ -143,6 +144,11 @@ struct Content {
143144
std::string name;
144145
std::string condition;
145146
tsl::ordered_map<std::string, std::string> arguments;
147+
148+
Condition<std::string> cmake_before;
149+
Condition<std::string> cmake_after;
150+
ConditionVector include_before;
151+
ConditionVector include_after;
146152
};
147153

148154
struct Project {

src/cmake_generator.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313
namespace cmkr {
1414
namespace gen {
1515

16-
static std::string to_upper(const std::string &str) {
17-
std::string temp;
18-
temp.reserve(str.size());
19-
for (auto c : str) {
20-
temp.push_back(::toupper(c));
21-
}
22-
return temp;
23-
}
24-
2516
static std::string format(const char *format, tsl::ordered_map<std::string, std::string> variables) {
2617
std::string s = format;
2718
for (const auto &itr : variables) {
@@ -710,6 +701,11 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
710701
cmd("include")("FetchContent").endl();
711702
for (const auto &content : project.contents) {
712703
ConditionScope cs(gen, content.condition);
704+
705+
gen.handle_condition(content.include_before,
706+
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
707+
gen.handle_condition(content.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
708+
713709
std::string version_info = "";
714710
if (content.arguments.contains("GIT_TAG")) {
715711
version_info = " (" + content.arguments.at("GIT_TAG") + ")";
@@ -723,6 +719,10 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
723719
}
724720
ss << ")\n";
725721
cmd("FetchContent_MakeAvailable")(content.name).endl();
722+
723+
gen.handle_condition(content.include_after,
724+
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
725+
gen.handle_condition(content.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
726726
}
727727
}
728728

src/project_parser.cpp

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <stdexcept>
66
#include <toml.hpp>
77
#include <tsl/ordered_map.h>
8+
#include <tsl/ordered_set.h>
89

910
namespace cmkr {
1011
namespace parser {
@@ -49,8 +50,8 @@ static std::string format_key_error(const std::string &error, const toml::key &k
4950

5051
class TomlChecker {
5152
const TomlBasicValue &m_v;
52-
tsl::ordered_map<toml::key, bool> m_visited;
53-
tsl::ordered_map<toml::key, bool> m_conditionVisited;
53+
tsl::ordered_set<toml::key> m_visited;
54+
tsl::ordered_set<toml::key> m_conditionVisited;
5455

5556
public:
5657
TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {}
@@ -77,7 +78,7 @@ class TomlChecker {
7778
// Handle visiting logic
7879
for (const auto &itr : destination) {
7980
if (!itr.first.empty()) {
80-
m_conditionVisited.emplace(itr.first, true);
81+
m_conditionVisited.emplace(itr.first);
8182
}
8283
}
8384
visit(ky);
@@ -108,7 +109,9 @@ class TomlChecker {
108109
return toml::find(m_v, ky);
109110
}
110111

111-
void visit(const toml::key &ky) { m_visited.emplace(ky, true); }
112+
void visit(const toml::key &ky) { m_visited.emplace(ky); }
113+
114+
bool visisted(const toml::key &ky) const { return m_visited.contains(ky); }
112115

113116
void check(const tsl::ordered_map<std::string, std::string> &conditions) const {
114117
for (const auto &itr : m_v.as_table()) {
@@ -145,7 +148,7 @@ class TomlChecker {
145148
class TomlCheckerRoot {
146149
const TomlBasicValue &m_root;
147150
std::deque<TomlChecker> m_checkers;
148-
tsl::ordered_map<toml::key, bool> m_visisted;
151+
tsl::ordered_set<toml::key> m_visisted;
149152
bool m_checked = false;
150153

151154
public:
@@ -154,7 +157,7 @@ class TomlCheckerRoot {
154157
TomlCheckerRoot(TomlCheckerRoot &&) = delete;
155158

156159
bool contains(const toml::key &ky) {
157-
m_visisted[ky] = true;
160+
m_visisted.emplace(ky);
158161
return m_root.contains(ky);
159162
}
160163

@@ -353,19 +356,49 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
353356
}
354357
}
355358

356-
// TODO: perform checking here
357359
if (checker.contains("fetch-content")) {
358360
const auto &fc = toml::find(toml, "fetch-content").as_table();
359361
for (const auto &itr : fc) {
360362
Content content;
361363
content.name = itr.first;
364+
365+
auto &c = checker.create(itr.second);
366+
c.optional("condition", content.condition);
367+
c.optional("cmake-before", content.cmake_before);
368+
c.optional("cmake-after", content.cmake_after);
369+
c.optional("include-before", content.include_before);
370+
c.optional("include-after", content.include_after);
371+
362372
for (const auto &argItr : itr.second.as_table()) {
363-
auto key = argItr.first;
364-
if (key == "condition") {
365-
content.condition = argItr.second.as_string();
366-
continue;
373+
std::string value;
374+
if (argItr.second.is_array()) {
375+
for (const auto &list_val : argItr.second.as_array()) {
376+
if (!value.empty()) {
377+
value += ';';
378+
}
379+
value += list_val.as_string();
380+
}
381+
} else if (argItr.second.is_boolean()) {
382+
value = argItr.second.as_boolean() ? "ON" : "OFF";
383+
} else {
384+
value = argItr.second.as_string();
367385
}
368386

387+
auto is_cmake_arg = [](const std::string &s) {
388+
for (auto c : s) {
389+
if (!(std::isdigit(c) || std::isupper(c) || c == '_')) {
390+
return false;
391+
}
392+
}
393+
return true;
394+
};
395+
396+
// https://cmake.org/cmake/help/latest/command/string.html#supported-hash-algorithms
397+
tsl::ordered_set<std::string> hash_algorithms = {
398+
"md5", "sha1", "sha224", "sha256", "sha384", "sha512", "sha3_224", "sha3_256", "sha3_384", "sha3_512",
399+
};
400+
401+
auto key = argItr.first;
369402
if (key == "git") {
370403
key = "GIT_REPOSITORY";
371404
} else if (key == "tag") {
@@ -378,18 +411,23 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
378411
key = "SVN_REVISION";
379412
} else if (key == "url") {
380413
key = "URL";
414+
} else if (hash_algorithms.contains(key)) {
415+
std::string algo;
416+
for (auto c : key) {
417+
algo.push_back(std::toupper(c));
418+
}
419+
key = "URL_HASH";
420+
value = algo + "=" + value;
381421
} else if (key == "hash") {
382422
key = "URL_HASH";
383-
} else {
384-
// don't change arg
423+
} else if (is_cmake_arg(key)) {
424+
// allow passthrough of ExternalProject options
425+
} else if (!c.visisted(key)) {
426+
throw std::runtime_error(format_key_error("Unknown key '" + argItr.first + "'", argItr.first, argItr.second));
385427
}
386428

387-
std::string value;
388-
if (argItr.second.is_boolean()) {
389-
value = argItr.second.as_boolean() ? "ON" : "OFF";
390-
} else {
391-
value = argItr.second.as_string();
392-
}
429+
c.visit(argItr.first);
430+
393431
content.arguments.emplace(key, value);
394432
}
395433
contents.emplace_back(std::move(content));

0 commit comments

Comments
 (0)