Skip to content

Commit d905be1

Browse files
committed
Final touches
1 parent 8d13ccb commit d905be1

File tree

5 files changed

+68
-110
lines changed

5 files changed

+68
-110
lines changed

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

include/enum_helper.hpp

Lines changed: 0 additions & 70 deletions
This file was deleted.

include/project_parser.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,15 @@ enum TargetType {
5757
target_custom,
5858
target_object,
5959
target_template,
60-
target_COUNT,
60+
target_last,
6161
};
6262

63+
extern const char *targetTypeNames[target_last];
64+
6365
struct Target {
6466
std::string name;
65-
TargetType type = {};
66-
std::string type_string;
67+
TargetType type = target_last;
68+
std::string type_name;
6769

6870
ConditionVector headers;
6971
ConditionVector sources;

src/cmake_generator.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
780780
// Check if this target is using a template.
781781
if (target.type == parser::target_template) {
782782
for (const auto &t : project.templates) {
783-
if (target.type_string == t.outline.name) {
783+
if (target.type_name == t.outline.name) {
784784
tmplate = &t;
785785
tmplate_cs = std::unique_ptr<ConditionScope>(new ConditionScope(gen, tmplate->outline.condition));
786786
}
@@ -895,6 +895,8 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
895895
if (tmplate->pass_sources_to_add_function) {
896896
cmd(add_command)(target.name, target_type_string, "${" + sources_var + "}");
897897
} else {
898+
cmd(add_command)(target.name, target_type_string).endl();
899+
898900
// clang-format off
899901
cmd("if")(sources_var);
900902
cmd("target_sources")(target.name, target_type == parser::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}");

src/project_parser.cpp

Lines changed: 60 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,27 @@
11
#include "project_parser.hpp"
22

3-
#include "enum_helper.hpp"
43
#include "fs.hpp"
54
#include <deque>
65
#include <stdexcept>
76
#include <toml.hpp>
87
#include <tsl/ordered_map.h>
98

10-
template <>
11-
std::vector<std::string> enumStrings<cmkr::parser::TargetType>::data{"executable", "library", "shared", "static",
12-
"interface", "custom", "object", "template"};
13-
149
namespace cmkr {
1510
namespace parser {
1611

17-
using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
12+
const char *targetTypeNames[target_last] = {"executable", "library", "shared", "static", "interface", "custom", "object", "template"};
1813

19-
template <typename EnumType>
20-
static EnumType to_enum(const std::string &str, const std::string &help_name) {
21-
EnumType value;
22-
try {
23-
std::stringstream ss(str);
24-
ss >> enumFromString(value);
25-
} catch (std::invalid_argument &) {
26-
std::string supported;
27-
for (const auto &s : enumStrings<EnumType>::data) {
28-
if (!supported.empty()) {
29-
supported += ", ";
30-
}
31-
supported += s;
14+
static TargetType parse_targetType(const std::string &name) {
15+
for (int i = 0; i < target_last; i++) {
16+
if (name == targetTypeNames[i]) {
17+
return static_cast<TargetType>(i);
3218
}
33-
throw std::runtime_error("Unknown " + help_name + "'" + str + "'! Supported types are: " + supported);
3419
}
35-
return value;
20+
return target_last;
3621
}
3722

23+
using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
24+
3825
static std::string format_key_error(const std::string &error, const toml::key &ky, const TomlBasicValue &value) {
3926
auto loc = value.location();
4027
auto line_number_str = std::to_string(loc.line());
@@ -43,7 +30,7 @@ static std::string format_key_error(const std::string &error, const toml::key &k
4330

4431
std::ostringstream oss;
4532
oss << "[error] " << error << '\n';
46-
oss << " --> " << loc.file_name() << '\n';
33+
oss << " --> " << loc.file_name() << ':' << loc.line() << '\n';
4734

4835
oss << std::string(line_width + 2, ' ') << "|\n";
4936
oss << ' ' << line_number_str << " | " << line_str << '\n';
@@ -56,7 +43,6 @@ static std::string format_key_error(const std::string &error, const toml::key &k
5643
if (key_start != std::string::npos) {
5744
oss << std::string(key_start + 1, ' ') << std::string(ky.length(), '~');
5845
}
59-
oss << '\n';
6046

6147
return oss.str();
6248
}
@@ -242,6 +228,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
242228
conditions["x32"] = R"cmake(CMAKE_SIZEOF_VOID_P EQUAL 4)cmake";
243229
} else {
244230
conditions = parent->conditions;
231+
templates = parent->templates;
245232
}
246233

247234
if (toml.contains("conditions")) {
@@ -387,16 +374,43 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
387374
throw std::runtime_error("[[bin]] has been renamed to [[target]]");
388375
}
389376

390-
auto parse_target = [&](const std::string &name, TomlChecker& t) {
377+
auto parse_target = [&](const std::string &name, TomlChecker &t, bool isTemplate) {
391378
Target target;
392379
target.name = name;
393380

394-
t.required("type", target.type_string);
381+
t.required("type", target.type_name);
382+
target.type = parse_targetType(target.type_name);
395383

396-
target.type = to_enum<TargetType>(target.type_string, "target type");
384+
// Users cannot set this target type
385+
if (target.type == target_template) {
386+
target.type = target_last;
387+
}
397388

398-
if (target.type >= target_COUNT) {
399-
target.type = target_template;
389+
if (!isTemplate && target.type == target_last) {
390+
for (const auto &tmplate : templates) {
391+
if (target.type_name == tmplate.outline.name) {
392+
target.type = target_template;
393+
break;
394+
}
395+
}
396+
}
397+
398+
if (target.type == target_last) {
399+
std::string error = "Unknown target type '" + target.type_name + "'\n";
400+
error += "Available types:\n";
401+
for (std::string type_name : targetTypeNames) {
402+
if (type_name != "template") {
403+
error += " - " + type_name + "\n";
404+
}
405+
}
406+
if (!isTemplate && !templates.empty()) {
407+
error += "Available templates:\n";
408+
for (const auto &tmplate : templates) {
409+
error += " - " + tmplate.outline.name + "\n";
410+
}
411+
}
412+
error.pop_back(); // Remove last newline
413+
throw std::runtime_error(format_key_error(error, target.type_name, t.find("type")));
400414
}
401415

402416
t.optional("headers", target.headers);
@@ -477,26 +491,37 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
477491

478492
if (toml.contains("template")) {
479493
const auto &ts = toml::find(toml, "template").as_table();
480-
481494
for (const auto &itr : ts) {
495+
auto &t = checker.create(itr.second);
496+
const auto &name = itr.first;
497+
498+
for (const auto &type_name : targetTypeNames) {
499+
if (name == type_name) {
500+
throw std::runtime_error(format_key_error("Reserved template name '" + name + "'", name, itr.second));
501+
}
502+
}
503+
504+
for (const auto &tmplate : templates) {
505+
if (name == tmplate.outline.name) {
506+
throw std::runtime_error(format_key_error("Template '" + name + "' already defined", name, itr.second));
507+
}
508+
}
509+
482510
Template tmplate;
483-
auto& t = checker.create(itr.second);
484-
tmplate.outline = parse_target(itr.first, t);
511+
tmplate.outline = parse_target(name, t, true);
485512

486513
t.optional("add-function", tmplate.add_function);
487514
t.optional("pass-sources-to-add-function", tmplate.pass_sources_to_add_function);
488515

489516
templates.push_back(tmplate);
490-
enumStrings<TargetType>::data.push_back(tmplate.outline.name);
491517
}
492518
}
493519

494520
if (toml.contains("target")) {
495521
const auto &ts = toml::find(toml, "target").as_table();
496-
497522
for (const auto &itr : ts) {
498-
auto& t = checker.create(itr.second);
499-
targets.push_back(parse_target(itr.first, t));
523+
auto &t = checker.create(itr.second);
524+
targets.push_back(parse_target(itr.first, t, false));
500525
}
501526
}
502527

0 commit comments

Comments
 (0)