@@ -699,6 +699,16 @@ struct TargetFileAnswer {
699699TargetFileAnswer resolve_target_file (const BuildPlan& plan, std::string_view name,
700700 std::string_view actingMember);
701701
702+ // The references an action's arguments made that the plan cannot answer, as
703+ // the refusal a user reads: names no link unit has (`unresolvedTargets`), names
704+ // several members define for a package that acts for none of them
705+ // (`ambiguousTargets`, from `resolve_target_file`), and `${mcpp.artifact:}`
706+ // references no requested artifact matches (`unresolvedArtifacts`).
707+ std::expected<void , std::string> refuse_unresolved_references (
708+ const BuildPlan& plan, const std::set<std::string>& unresolvedTargets,
709+ const std::map<std::string, std::vector<std::string>>& ambiguousTargets,
710+ const std::set<std::string>& unresolvedArtifacts);
711+
702712// The objects a package contributes to an image that links it whole: its
703713// module units, which link unconditionally, then its implementation units, in
704714// plan order. A shared library that carries a private copy of a graph C++
@@ -3318,6 +3328,48 @@ TargetFileAnswer resolve_target_file(const BuildPlan& plan, std::string_view nam
33183328 return answer;
33193329}
33203330
3331+ std::expected<void , std::string> refuse_unresolved_references (
3332+ const BuildPlan& plan, const std::set<std::string>& unresolvedTargets,
3333+ const std::map<std::string, std::vector<std::string>>& ambiguousTargets,
3334+ const std::set<std::string>& unresolvedArtifacts) {
3335+ if (!unresolvedTargets.empty ()) {
3336+ std::string bad, known;
3337+ for (auto const & n : unresolvedTargets) bad += (bad.empty () ? " " : " , " ) + n;
3338+ for (auto const & lu : plan.linkUnits )
3339+ known += (known.empty () ? " " : " , " ) + lu.targetName ;
3340+ return std::unexpected (std::format (
3341+ " build.mcpp action references unknown target(s) via "
3342+ " ${{mcpp.target_file:...}}: {}\n "
3343+ " targets in this build: [{}]\n "
3344+ " (a target gated by required_features is absent unless those "
3345+ " features are active)" ,
3346+ bad, known.empty () ? std::string (" none" ) : known));
3347+ }
3348+
3349+ for (auto const & [n, in] : ambiguousTargets)
3350+ return std::unexpected (std::format (
3351+ " build.mcpp action references ${{mcpp.target_file:{}}}, a target of "
3352+ " each of the members {}, and its package acts for none of them.\n "
3353+ " use: select one of the members, or give the targets distinct names" ,
3354+ n, std::format (" {}" , in)));
3355+
3356+ if (!unresolvedArtifacts.empty ()) {
3357+ std::string bad, known;
3358+ for (auto const & n : unresolvedArtifacts) bad += (bad.empty () ? " " : " , " ) + n;
3359+ for (auto const & lu : plan.linkUnits )
3360+ if (!lu.artifactOf .empty ())
3361+ known += (known.empty () ? " " : " , " ) + lu.artifactOf + " /" + lu.targetName ;
3362+ return std::unexpected (std::format (
3363+ " build.mcpp action references unknown artifact(s) via "
3364+ " ${{mcpp.artifact:<package>/<target>}}: {}\n "
3365+ " artifacts in this build: [{}]\n "
3366+ " (an artifact exists when a dependency edge requests it with "
3367+ " `artifacts = [\" <target>\" ]`)" ,
3368+ bad, known.empty () ? std::string (" none" ) : known));
3369+ }
3370+ return {};
3371+ }
3372+
33213373std::vector<std::filesystem::path>
33223374package_link_objects (const BuildPlan& plan, std::string_view packageName) {
33233375 std::vector<std::filesystem::path> objects;
0 commit comments