@@ -879,17 +879,21 @@ void apply(mcpp::manifest::Manifest& m, const Directives& d) {
879879 // A named executable's subsystem and entry. `target_directive_error` has
880880 // refused every value that names no executable, so the conditions below
881881 // only keep this function total.
882- for (auto [slot, member] : {
883- std::pair{Slot::WindowsSubsystem, &mcpp::manifest::Target::windowsSubsystem},
884- std::pair{Slot::WindowsEntry, &mcpp::manifest::Target::windowsEntry}}) {
885- for (auto const & entry : d.at (slot)) {
886- auto sep = entry.rfind (' :' );
887- if (sep == std::string::npos) continue ;
888- const auto name = entry.substr (0 , sep);
889- for (auto & t : m.targets )
890- if (t.name == name && t.kind == mcpp::manifest::Target::Binary)
891- t.*member = entry.substr (sep + 1 );
892- }
882+ for (auto const & entry : d.at (Slot::WindowsSubsystem)) {
883+ const auto sep = entry.rfind (' :' );
884+ if (sep == std::string::npos) continue ;
885+ const auto name = entry.substr (0 , sep);
886+ for (auto & t : m.targets )
887+ if (t.name == name && t.kind == mcpp::manifest::Target::Binary)
888+ t.windowsSubsystem = entry.substr (sep + 1 );
889+ }
890+ for (auto const & entry : d.at (Slot::WindowsEntry)) {
891+ const auto sep = entry.rfind (' :' );
892+ if (sep == std::string::npos) continue ;
893+ const auto name = entry.substr (0 , sep);
894+ for (auto & t : m.targets )
895+ if (t.name == name && t.kind == mcpp::manifest::Target::Binary)
896+ t.windowsEntry = entry.substr (sep + 1 );
893897 }
894898
895899 // Build-graph nodes. Decoded here rather than at parse time so the cache
@@ -931,72 +935,71 @@ std::optional<mcpp::manifest::BuildAction> decode_action(std::string_view payloa
931935 }
932936}
933937
934- std::string target_directive_error (const mcpp::manifest::Manifest& m, const Directives& d) {
935- struct Field {
936- Slot slot;
937- std::string_view wire;
938- std::string_view key;
939- std::span<const std::string_view> accepted;
940- std::string mcpp::manifest::Target::* member;
941- };
942- const Field fields[] = {
943- {Slot::WindowsSubsystem, " windows-subsystem" , " windows_subsystem" ,
944- mcpp::manifest::kWindowsSubsystems , &mcpp::manifest::Target::windowsSubsystem},
945- {Slot::WindowsEntry, " windows-entry" , " windows_entry" ,
946- mcpp::manifest::kWindowsEntries , &mcpp::manifest::Target::windowsEntry},
947- };
948- for (auto const & f : fields) {
949- std::map<std::string, std::string> stated; // target name -> value
950- for (auto const & entry : d.at (f.slot )) {
951- auto sep = entry.rfind (' :' );
952- if (sep == std::string::npos || sep == 0 || sep + 1 == entry.size ())
953- return std::format (
954- " build.mcpp emitted `mcpp:{}={}`, which is not `<target>:<value>`." ,
955- f.wire , entry);
956- const std::string name = entry.substr (0 , sep);
957- const std::string value = entry.substr (sep + 1 );
958- if (std::ranges::find (f.accepted , std::string_view (value)) == f.accepted .end ()) {
959- std::string list;
960- for (auto a : f.accepted )
961- list += (list.empty () ? " " : " , " ) + std::format (" \" {}\" " , a);
962- return std::format (
963- " build.mcpp emitted `mcpp:{}={}`, and \" {}\" is not one of {}." ,
964- f.wire , entry, value, list);
965- }
966- const mcpp::manifest::Target* target = nullptr ;
938+ // One of the two named-target directives; `subsystem` selects the field.
939+ static std::string named_target_error (const mcpp::manifest::Manifest& m,
940+ const std::vector<std::string>& entries,
941+ std::string_view wire, std::string_view key,
942+ bool subsystem) {
943+ std::map<std::string, std::string> stated; // target name -> value
944+ for (auto const & entry : entries) {
945+ const auto sep = entry.rfind (' :' );
946+ if (sep == std::string::npos || sep == 0 || sep + 1 == entry.size ())
947+ return std::format (
948+ " build.mcpp emitted `mcpp:{}={}`, which is not `<target>:<value>`." ,
949+ wire, entry);
950+ const std::string name = entry.substr (0 , sep);
951+ const std::string value = entry.substr (sep + 1 );
952+ if (auto list = mcpp::manifest::windows_choice_problem (subsystem, value);
953+ !list.empty ())
954+ return std::format (
955+ " build.mcpp emitted `mcpp:{}={}`, and \" {}\" is not one of {}." ,
956+ wire, entry, value, list);
957+ const mcpp::manifest::Target* target = nullptr ;
958+ for (auto const & t : m.targets )
959+ if (t.name == name) { target = &t; break ; }
960+ if (target == nullptr ) {
961+ std::string names;
967962 for (auto const & t : m.targets )
968- if (t.name == name) { target = &t; break ; }
969- if (!target) {
970- std::string names;
971- for (auto const & t : m.targets )
972- names += (names.empty () ? " " : " , " ) + t.name ;
973- return std::format (
974- " build.mcpp emitted `mcpp:{}={}`, and package `{}` declares no "
975- " target named `{}` (its targets: {})." ,
976- f.wire , entry, m.package .name , name, names.empty () ? " none" : names);
977- }
978- if (target->kind != mcpp::manifest::Target::Binary)
979- return std::format (
980- " build.mcpp emitted `mcpp:{}={}`, and `{}` applies to an executable "
981- " (`kind = \" bin\" `); target `{}` is not one." ,
982- f.wire , entry, f.key , name);
983- if (const std::string& declared = target->*f.member ;
984- !declared.empty () && declared != value)
985- return std::format (
986- " build.mcpp emitted `mcpp:{}={}`, and mcpp.toml declares "
987- " `[targets.{}] {} = \" {}\" `. One of the two has to change." ,
988- f.wire , entry, name, f.key , declared);
989- if (auto [it, fresh] = stated.try_emplace (name, value);
990- !fresh && it->second != value)
991- return std::format (
992- " build.mcpp emitted `mcpp:{}` twice for target `{}`, as \" {}\" and "
993- " as \" {}\" ." ,
994- f.wire , name, it->second , value);
963+ names += (names.empty () ? " " : " , " ) + t.name ;
964+ return std::format (
965+ " build.mcpp emitted `mcpp:{}={}`, and package `{}` declares no "
966+ " target named `{}` (its targets: {})." ,
967+ wire, entry, m.package .name , name,
968+ names.empty () ? std::string (" none" ) : names);
995969 }
970+ if (target->kind != mcpp::manifest::Target::Binary)
971+ return std::format (
972+ " build.mcpp emitted `mcpp:{}={}`, and `{}` applies to an executable "
973+ " (`kind = \" bin\" `); target `{}` is not one." ,
974+ wire, entry, key, name);
975+ const std::string& declared =
976+ subsystem ? target->windowsSubsystem : target->windowsEntry ;
977+ if (!declared.empty () && declared != value)
978+ return std::format (
979+ " build.mcpp emitted `mcpp:{}={}`, and mcpp.toml declares "
980+ " `[targets.{}] {} = \" {}\" `. One of the two has to change." ,
981+ wire, entry, name, key, declared);
982+ auto found = stated.find (name);
983+ if (found == stated.end ())
984+ stated.emplace (name, value);
985+ else if (found->second != value)
986+ return std::format (
987+ " build.mcpp emitted `mcpp:{}` twice for target `{}`, as \" {}\" and "
988+ " as \" {}\" ." ,
989+ wire, name, found->second , value);
996990 }
997991 return {};
998992}
999993
994+ std::string target_directive_error (const mcpp::manifest::Manifest& m, const Directives& d) {
995+ if (auto e = named_target_error (m, d.at (Slot::WindowsSubsystem),
996+ " windows-subsystem" , " windows_subsystem" , true );
997+ !e.empty ())
998+ return e;
999+ return named_target_error (m, d.at (Slot::WindowsEntry),
1000+ " windows-entry" , " windows_entry" , false );
1001+ }
1002+
10001003std::string action_error (const Directives& d) {
10011004 for (auto const & payload : d.at (Slot::Actions)) {
10021005 // The typed API sets this when an argv did not fit its fixed buffer.
0 commit comments