@@ -32,14 +32,14 @@ static MsvcRuntimeType parse_msvcRuntimeType(const std::string &name) {
3232
3333using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
3434
35- static std::string format_key_error (const std::string &error , const toml::key &ky, const TomlBasicValue &value) {
35+ static std::string format_key_message (const std::string &message , const toml::key &ky, const TomlBasicValue &value) {
3636 auto loc = value.location ();
3737 auto line_number_str = std::to_string (loc.line ());
3838 auto line_width = line_number_str.length ();
3939 auto line_str = loc.line_str ();
4040
4141 std::ostringstream oss;
42- oss << " [error] " << error << ' \n ' ;
42+ oss << message << " \n " ;
4343 oss << " --> " << loc.file_name () << ' :' << loc.line () << ' \n ' ;
4444
4545 oss << std::string (line_width + 2 , ' ' ) << " |\n " ;
@@ -57,6 +57,14 @@ static std::string format_key_error(const std::string &error, const toml::key &k
5757 return oss.str ();
5858}
5959
60+ static void throw_key_error (const std::string &error, const toml::key &ky, const TomlBasicValue &value) {
61+ throw std::runtime_error (format_key_message (" [error] " + error, ky, value));
62+ }
63+
64+ static void print_key_warning (const std::string &message, const toml::key &ky, const TomlBasicValue &value) {
65+ puts (format_key_message (" [warning] " + message, ky, value).c_str ());
66+ }
67+
6068class TomlChecker {
6169 const TomlBasicValue &m_v;
6270 tsl::ordered_set<toml::key> m_visited;
@@ -133,27 +141,27 @@ class TomlChecker {
133141 const auto &ky = itr.first ;
134142 if (m_conditionVisited.contains (ky)) {
135143 if (!conditions.contains (ky)) {
136- throw std::runtime_error ( format_key_error ( " Unknown condition '" + ky + " '" , ky, itr.second ) );
144+ throw_key_error ( " Unknown condition '" + ky + " '" , ky, itr.second );
137145 }
138146
139147 for (const auto &jtr : itr.second .as_table ()) {
140148 if (!m_visited.contains (jtr.first )) {
141- throw std::runtime_error ( format_key_error ( " Unknown key '" + jtr.first + " '" , jtr.first , jtr.second ) );
149+ throw_key_error ( " Unknown key '" + jtr.first + " '" , jtr.first , jtr.second );
142150 }
143151 }
144152 } else if (!m_visited.contains (ky)) {
145153 if (itr.second .is_table ()) {
146154 for (const auto &jtr : itr.second .as_table ()) {
147155 if (!m_visited.contains (jtr.first )) {
148- throw std::runtime_error ( format_key_error ( " Unknown key '" + jtr.first + " '" , jtr.first , jtr.second ) );
156+ throw_key_error ( " Unknown key '" + jtr.first + " '" , jtr.first , jtr.second );
149157 }
150158 }
151159 }
152- throw std::runtime_error ( format_key_error ( " Unknown key '" + ky + " '" , ky, itr.second ) );
160+ throw_key_error ( " Unknown key '" + ky + " '" , ky, itr.second );
153161 } else if (ky == " condition" ) {
154162 std::string condition = itr.second .as_string ();
155163 if (!conditions.contains (condition)) {
156- throw std::runtime_error ( format_key_error ( " Unknown condition '" + condition + " '" , condition, itr.second ) );
164+ throw_key_error ( " Unknown condition '" + condition + " '" , condition, itr.second );
157165 }
158166 }
159167 }
@@ -191,7 +199,7 @@ class TomlCheckerRoot {
191199 if (check_root) {
192200 for (const auto &itr : m_root.as_table ()) {
193201 if (!m_visisted.contains (itr.first )) {
194- throw std::runtime_error ( format_key_error ( " Unknown key '" + itr.first + " '" , itr.first , itr.second ) );
202+ throw_key_error ( " Unknown key '" + itr.first + " '" , itr.first , itr.second );
195203 }
196204 }
197205 }
@@ -219,7 +227,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
219227 cmake.required (" version" , cmake_version);
220228
221229 if (cmake.contains (" bin-dir" )) {
222- throw std::runtime_error ( format_key_error ( " bin-dir has been renamed to build-dir" , " bin-dir" , cmake.find (" bin-dir" ) ));
230+ throw_key_error ( " bin-dir has been renamed to build-dir" , " bin-dir" , cmake.find (" bin-dir" ));
223231 }
224232
225233 cmake.optional (" build-dir" , build_dir);
@@ -297,7 +305,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
297305 error += " - " + type_name + " \n " ;
298306 }
299307 error.pop_back (); // Remove last newline
300- throw std::runtime_error ( format_key_error ( error, msvc_runtime, project.find (" msvc-runtime" ) ));
308+ throw_key_error ( error, msvc_runtime, project.find (" msvc-runtime" ));
301309 }
302310 }
303311 }
@@ -319,15 +327,21 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
319327 }
320328 }
321329
322- if (checker.contains (" settings" )) {
323- throw std::runtime_error (format_key_error (" [settings] has been renamed to [variables]" , " " , toml.at (" settings" )));
324- }
325-
326330 if (checker.contains (" variables" )) {
327331 using set_map = tsl::ordered_map<std::string, TomlBasicValue>;
328- const auto &sets = toml::find<set_map>(toml, " variables" );
329- for (const auto &itr : sets) {
330- Setting s;
332+ auto vars = toml::find<set_map>(toml, " variables" );
333+ if (checker.contains (" settings" )) {
334+ print_key_warning (" [settings] has been renamed to [variables]" , " settings" , toml.at (" settings" ));
335+ const auto &sets = toml::find<set_map>(toml, " settings" );
336+ for (const auto &itr : sets) {
337+ if (!vars.insert (itr).second ) {
338+ throw_key_error (" Key '" + itr.first + " ' shadows existing variable" , itr.first , itr.second );
339+ }
340+ }
341+ }
342+
343+ for (const auto &itr : vars) {
344+ Variable s;
331345 s.name = itr.first ;
332346 const auto &value = itr.second ;
333347 if (value.is_boolean ()) {
@@ -348,7 +362,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
348362 setting.optional (" cache" , s.cache );
349363 setting.optional (" force" , s.force );
350364 }
351- settings .push_back (s);
365+ variables .push_back (s);
352366 }
353367 }
354368
@@ -458,7 +472,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
458472 } else if (is_cmake_arg (key)) {
459473 // allow passthrough of ExternalProject options
460474 } else if (!c.visisted (key)) {
461- throw std::runtime_error ( format_key_error ( " Unknown key '" + argItr.first + " '" , argItr.first , argItr.second ) );
475+ throw_key_error ( " Unknown key '" + argItr.first + " '" , argItr.first , argItr.second );
462476 }
463477
464478 // Make sure not to emit keys like "condition" in the FetchContent call
@@ -473,7 +487,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
473487 }
474488
475489 if (checker.contains (" bin" )) {
476- throw std::runtime_error ( format_key_error ( " [[bin]] has been renamed to [target.<name>]" , " " , toml.at (" bin" ) ));
490+ throw_key_error ( " [[bin]] has been renamed to [target.<name>]" , " " , toml.at (" bin" ));
477491 }
478492
479493 auto parse_target = [&](const std::string &name, TomlChecker &t, bool isTemplate) {
@@ -512,7 +526,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
512526 }
513527 }
514528 error.pop_back (); // Remove last newline
515- throw std::runtime_error ( format_key_error ( error, target.type_name , t.find (" type" ) ));
529+ throw_key_error ( error, target.type_name , t.find (" type" ));
516530 }
517531
518532 t.optional (" sources" , target.sources );
@@ -574,7 +588,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
574588 } else {
575589 report = &t.find (condItr.first ).as_table ().find (" msvc-runtime" ).value ();
576590 }
577- throw std::runtime_error ( format_key_error ( error, condItr.second , *report) );
591+ throw_key_error ( error, condItr.second , *report);
578592 }
579593 }
580594 }
@@ -630,13 +644,13 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
630644
631645 for (const auto &type_name : targetTypeNames) {
632646 if (name == type_name) {
633- throw std::runtime_error ( format_key_error ( " Reserved template name '" + name + " '" , name, itr.second ) );
647+ throw_key_error ( " Reserved template name '" + name + " '" , name, itr.second );
634648 }
635649 }
636650
637651 for (const auto &tmplate : templates) {
638652 if (name == tmplate.outline .name ) {
639- throw std::runtime_error ( format_key_error ( " Template '" + name + " ' already defined" , name, itr.second ) );
653+ throw_key_error ( " Template '" + name + " ' already defined" , name, itr.second );
640654 }
641655 }
642656
@@ -711,7 +725,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
711725 package.features .emplace_back (feature);
712726 }
713727 } else {
714- throw std::runtime_error ( format_key_error ( " Invalid package name '" + package_str + " '" , " packages" , p) );
728+ throw_key_error ( " Invalid package name '" + package_str + " '" , " packages" , p);
715729 }
716730 vcpkg.packages .emplace_back (std::move (package));
717731 }
0 commit comments