| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmPackageInfoReader.h"
- #include <initializer_list>
- #include <limits>
- #include <unordered_map>
- #include <utility>
- #include <cmext/string_view>
- #include <cm3p/json/reader.h>
- #include <cm3p/json/value.h>
- #include <cm3p/json/version.h>
- #include "cmsys/FStream.hxx"
- #include "cmsys/RegularExpression.hxx"
- #include "cmExecutionStatus.h"
- #include "cmListFileCache.h"
- #include "cmMakefile.h"
- #include "cmMessageType.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- #include "cmTarget.h"
- namespace {
- // Map of CPS language names to CMake language name. Case insensitivity is
- // achieved by converting the CPS value to lower case, so keys in this map must
- // be lower case.
- std::unordered_map<std::string, std::string> Languages = {
- // clang-format off
- { "c", "C" },
- { "c++", "CXX" },
- { "cpp", "CXX" },
- { "cxx", "CXX" },
- { "objc", "OBJC" },
- { "objc++", "OBJCXX" },
- { "objcpp", "OBJCXX" },
- { "objcxx", "OBJCXX" },
- { "swift", "swift" },
- { "hip", "HIP" },
- { "cuda", "CUDA" },
- { "ispc", "ISPC" },
- { "c#", "CSharp" },
- { "csharp", "CSharp" },
- { "fortran", "Fortran" },
- // clang-format on
- };
- enum LanguageGlobOption
- {
- DisallowGlob,
- AllowGlob,
- };
- cm::string_view MapLanguage(cm::string_view lang,
- LanguageGlobOption glob = AllowGlob)
- {
- if (glob == AllowGlob && lang == "*"_s) {
- return "*"_s;
- }
- auto const li = Languages.find(cmSystemTools::LowerCase(lang));
- if (li != Languages.end()) {
- return li->second;
- }
- return {};
- }
- std::string GetRealPath(std::string const& path)
- {
- return cmSystemTools::GetRealPath(path);
- }
- std::string GetRealDir(std::string const& path)
- {
- return cmSystemTools::GetFilenamePath(cmSystemTools::GetRealPath(path));
- }
- Json::Value ReadJson(std::string const& fileName)
- {
- // Open the specified file.
- cmsys::ifstream file(fileName.c_str(), std::ios::in | std::ios::binary);
- if (!file) {
- #if JSONCPP_VERSION_HEXA < 0x01070300
- return Json::Value::null;
- #else
- return Json::Value::nullSingleton();
- #endif
- }
- // Read file content and translate JSON.
- Json::Value data;
- Json::CharReaderBuilder builder;
- builder["collectComments"] = false;
- if (!Json::parseFromStream(builder, file, &data, nullptr)) {
- #if JSONCPP_VERSION_HEXA < 0x01070300
- return Json::Value::null;
- #else
- return Json::Value::nullSingleton();
- #endif
- }
- return data;
- }
- bool CheckSchemaVersion(Json::Value const& data)
- {
- std::string const& version = data["cps_version"].asString();
- // Check that a valid version is specified.
- if (version.empty()) {
- return false;
- }
- // Check that we understand this version.
- return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
- version, "0.13") &&
- cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, version, "1");
- // TODO Eventually this probably needs to return the version tuple, and
- // should share code with cmPackageInfoReader::ParseVersion.
- }
- bool ComparePathSuffix(std::string const& path, std::string const& suffix)
- {
- std::string const& tail = path.substr(path.size() - suffix.size());
- return cmSystemTools::ComparePath(tail, suffix);
- }
- std::string DeterminePrefix(std::string const& filepath,
- Json::Value const& data)
- {
- // First check if an absolute prefix was supplied.
- std::string prefix = data["prefix"].asString();
- if (!prefix.empty()) {
- // Ensure that the specified prefix is valid.
- if (cmsys::SystemTools::FileIsFullPath(prefix) &&
- cmsys::SystemTools::FileIsDirectory(prefix)) {
- cmSystemTools::ConvertToUnixSlashes(prefix);
- return prefix;
- }
- // The specified absolute prefix is not valid.
- return {};
- }
- // Get and validate prefix-relative path.
- std::string relPath = data["cps_path"].asString();
- cmSystemTools::ConvertToUnixSlashes(relPath);
- if (relPath.empty() || !cmHasLiteralPrefix(relPath, "@prefix@/")) {
- // The relative prefix is not valid.
- return {};
- }
- relPath = relPath.substr(8);
- // Get directory portion of the absolute path.
- std::string const& absPath = cmSystemTools::GetFilenamePath(filepath);
- if (ComparePathSuffix(absPath, relPath)) {
- return absPath.substr(0, absPath.size() - relPath.size());
- }
- for (auto* const f : { GetRealPath, GetRealDir }) {
- std::string const& tmpPath = (*f)(absPath);
- if (!cmSystemTools::ComparePath(tmpPath, absPath) &&
- ComparePathSuffix(tmpPath, relPath)) {
- return tmpPath.substr(0, tmpPath.size() - relPath.size());
- }
- }
- return {};
- }
- // Extract key name from value iterator as string_view.
- cm::string_view IterKey(Json::Value::const_iterator const& iter)
- {
- char const* end;
- char const* const start = iter.memberName(&end);
- return { start, static_cast<std::string::size_type>(end - start) };
- }
- // Get list-of-strings value from object.
- std::vector<std::string> ReadList(Json::Value const& arr)
- {
- std::vector<std::string> result;
- if (arr.isArray()) {
- for (Json::Value const& val : arr) {
- if (val.isString()) {
- result.push_back(val.asString());
- }
- }
- }
- return result;
- }
- std::vector<std::string> ReadList(Json::Value const& data, char const* key)
- {
- return ReadList(data[key]);
- }
- std::string NormalizeTargetName(std::string const& name,
- std::string const& context)
- {
- if (cmHasLiteralPrefix(name, ":")) {
- return cmStrCat(context, name);
- }
- std::string::size_type const n = name.find_first_of(':');
- if (n != std::string::npos) {
- cm::string_view v{ name };
- return cmStrCat(v.substr(0, n), ':', v.substr(n));
- }
- return name;
- }
- void AppendProperty(cmMakefile* makefile, cmTarget* target,
- cm::string_view property, cm::string_view configuration,
- std::string const& value)
- {
- std::string fullprop;
- if (configuration.empty()) {
- fullprop = cmStrCat("INTERFACE_"_s, property);
- } else {
- fullprop = cmStrCat("INTERFACE_"_s, property, '_',
- cmSystemTools::UpperCase(configuration));
- }
- target->AppendProperty(fullprop, value, makefile->GetBacktrace());
- }
- template <typename Transform>
- void AppendLanguageProperties(cmMakefile* makefile, cmTarget* target,
- cm::string_view property,
- cm::string_view configuration,
- Json::Value const& data, char const* key,
- Transform transform)
- {
- Json::Value const& value = data[key];
- if (value.isArray()) {
- for (std::string v : ReadList(value)) {
- AppendProperty(makefile, target, property, configuration,
- transform(std::move(v)));
- }
- } else if (value.isObject()) {
- for (auto vi = value.begin(), ve = value.end(); vi != ve; ++vi) {
- cm::string_view const originalLang = IterKey(vi);
- cm::string_view const lang = MapLanguage(originalLang);
- if (lang.empty()) {
- makefile->IssueMessage(MessageType::WARNING,
- cmStrCat(R"(ignoring unknown language ")"_s,
- originalLang, R"(" in )"_s, key,
- " for "_s, target->GetName()));
- continue;
- }
- if (lang == "*"_s) {
- for (std::string v : ReadList(*vi)) {
- AppendProperty(makefile, target, property, configuration,
- transform(std::move(v)));
- }
- } else {
- for (std::string v : ReadList(*vi)) {
- v = cmStrCat("$<$<COMPILE_LANGUAGE:"_s, lang, ">:"_s,
- transform(std::move(v)), '>');
- AppendProperty(makefile, target, property, configuration, v);
- }
- }
- }
- }
- }
- void AddCompileFeature(cmMakefile* makefile, cmTarget* target,
- cm::string_view configuration, std::string const& value)
- {
- auto reLanguageLevel = []() -> cmsys::RegularExpression {
- static cmsys::RegularExpression re{ "^[Cc]([+][+])?([0-9][0-9])$" };
- return re;
- }();
- if (reLanguageLevel.find(value)) {
- std::string::size_type const n = reLanguageLevel.end() - 2;
- cm::string_view const featurePrefix = (n == 3 ? "cxx_std_"_s : "c_std_"_s);
- if (configuration.empty()) {
- AppendProperty(makefile, target, "COMPILE_FEATURES"_s, {},
- cmStrCat(featurePrefix, value.substr(n)));
- } else {
- std::string const& feature =
- cmStrCat("$<$<CONFIG:"_s, configuration, ">:"_s, featurePrefix,
- value.substr(n), '>');
- AppendProperty(makefile, target, "COMPILE_FEATURES"_s, {}, feature);
- }
- } else if (cmStrCaseEq(value, "gnu"_s)) {
- // Not implemented in CMake at this time
- } else if (cmStrCaseEq(value, "threads"_s)) {
- AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration,
- "Threads::Threads");
- }
- }
- void AddLinkFeature(cmMakefile* makefile, cmTarget* target,
- cm::string_view configuration, std::string const& value)
- {
- if (cmStrCaseEq(value, "thread"_s)) {
- AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration,
- "Threads::Threads");
- }
- }
- std::string BuildDefinition(std::string const& name, Json::Value const& value)
- {
- if (!value.isNull() && value.isConvertibleTo(Json::stringValue)) {
- return cmStrCat(name, '=', value.asString());
- }
- return name;
- }
- void AddDefinition(cmMakefile* makefile, cmTarget* target,
- cm::string_view configuration,
- std::string const& definition)
- {
- AppendProperty(makefile, target, "COMPILE_DEFINITIONS"_s, configuration,
- definition);
- }
- using DefinitionLanguageMap = std::map<cm::string_view, Json::Value>;
- using DefinitionsMap = std::map<std::string, DefinitionLanguageMap>;
- void AddDefinitions(cmMakefile* makefile, cmTarget* target,
- cm::string_view configuration,
- DefinitionsMap const& definitions)
- {
- for (auto const& di : definitions) {
- auto const& g = di.second.find("*"_s);
- if (g != di.second.end()) {
- std::string const& def = BuildDefinition(di.first, g->second);
- if (di.second.size() == 1) {
- // Only the non-language-specific definition exists.
- AddDefinition(makefile, target, configuration, def);
- continue;
- }
- // Create a genex to apply this definition to all languages except
- // those that override it.
- std::vector<cm::string_view> excludedLanguages;
- for (auto const& li : di.second) {
- if (li.first != "*"_s) {
- excludedLanguages.emplace_back(li.first);
- }
- }
- AddDefinition(makefile, target, configuration,
- cmStrCat("$<$<NOT:$<COMPILE_LANGUAGE:"_s,
- cmJoin(excludedLanguages, ","_s), ">>:"_s, def,
- '>'));
- }
- // Add language-specific definitions.
- for (auto const& li : di.second) {
- if (li.first != "*"_s) {
- AddDefinition(makefile, target, configuration,
- cmStrCat("$<$<COMPILE_LANGUAGE:"_s, li.first, ">:"_s,
- BuildDefinition(di.first, li.second), '>'));
- }
- }
- }
- }
- } // namespace
- std::unique_ptr<cmPackageInfoReader> cmPackageInfoReader::Read(
- std::string const& path, cmPackageInfoReader const* parent)
- {
- // Read file and perform some basic validation:
- // - the input is valid JSON
- // - the input is a JSON object
- // - the input has a "cps_version" that we (in theory) know how to parse
- Json::Value data = ReadJson(path);
- if (!data.isObject() || (!parent && !CheckSchemaVersion(data))) {
- return nullptr;
- }
- // - the input has a "name" attribute that is a non-empty string
- Json::Value const& name = data["name"];
- if (!name.isString() || name.empty()) {
- return nullptr;
- }
- // - the input has a "components" attribute that is a JSON object
- if (!data["components"].isObject()) {
- return nullptr;
- }
- std::string prefix = (parent ? parent->Prefix : DeterminePrefix(path, data));
- if (prefix.empty()) {
- return nullptr;
- }
- // Seems sane enough to hand back to the caller.
- std::unique_ptr<cmPackageInfoReader> reader{ new cmPackageInfoReader };
- reader->Data = std::move(data);
- reader->Prefix = std::move(prefix);
- reader->Path = path;
- // Determine other information we need to know immediately, or (if this is
- // a supplemental reader) copy from the parent.
- if (parent) {
- reader->ComponentTargets = parent->ComponentTargets;
- reader->DefaultConfigurations = parent->DefaultConfigurations;
- } else {
- reader->DefaultConfigurations = ReadList(reader->Data, "configurations");
- }
- return reader;
- }
- std::string cmPackageInfoReader::GetName() const
- {
- return this->Data["name"].asString();
- }
- cm::optional<std::string> cmPackageInfoReader::GetVersion() const
- {
- Json::Value const& version = this->Data["version"];
- if (version.isString()) {
- return version.asString();
- }
- return cm::nullopt;
- }
- std::vector<unsigned> cmPackageInfoReader::ParseVersion() const
- {
- // Check that we have a version.
- cm::optional<std::string> const& version = this->GetVersion();
- if (!version) {
- return {};
- }
- std::vector<unsigned> result;
- cm::string_view remnant{ *version };
- // Check if we know how to parse the version.
- Json::Value const& schema = this->Data["version_schema"];
- if (schema.isNull() || cmStrCaseEq(schema.asString(), "simple"_s)) {
- // Keep going until we run out of parts.
- while (!remnant.empty()) {
- std::string::size_type n = remnant.find('.');
- cm::string_view part = remnant.substr(0, n);
- if (n == std::string::npos) {
- remnant = {};
- } else {
- remnant = remnant.substr(n + 1);
- }
- unsigned long const value = std::stoul(std::string{ part }, &n);
- if (n == 0 || value > std::numeric_limits<unsigned>::max()) {
- // The part was not a valid number or is too big.
- return {};
- }
- result.push_back(static_cast<unsigned>(value));
- }
- }
- return result;
- }
- std::vector<cmPackageRequirement> cmPackageInfoReader::GetRequirements() const
- {
- std::vector<cmPackageRequirement> requirements;
- auto const& requirementObjects = this->Data["requires"];
- for (auto ri = requirementObjects.begin(), re = requirementObjects.end();
- ri != re; ++ri) {
- cmPackageRequirement r{ ri.name(), (*ri)["version"].asString(),
- ReadList(*ri, "components"),
- ReadList(*ri, "hints") };
- requirements.emplace_back(std::move(r));
- }
- return requirements;
- }
- std::vector<std::string> cmPackageInfoReader::GetComponentNames() const
- {
- std::vector<std::string> componentNames;
- Json::Value const& components = this->Data["components"];
- for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
- componentNames.emplace_back(ci.name());
- }
- return componentNames;
- }
- std::string cmPackageInfoReader::ResolvePath(std::string path) const
- {
- cmSystemTools::ConvertToUnixSlashes(path);
- if (cmHasPrefix(path, "@prefix@"_s)) {
- return cmStrCat(this->Prefix, path.substr(8));
- }
- if (!cmSystemTools::FileIsFullPath(path)) {
- return cmStrCat(cmSystemTools::GetFilenamePath(this->Path), '/', path);
- }
- return path;
- }
- void cmPackageInfoReader::SetOptionalProperty(cmTarget* target,
- cm::string_view property,
- cm::string_view configuration,
- Json::Value const& value) const
- {
- if (!value.isNull()) {
- std::string fullprop;
- if (configuration.empty()) {
- fullprop = cmStrCat("IMPORTED_"_s, property);
- } else {
- fullprop = cmStrCat("IMPORTED_"_s, property, '_',
- cmSystemTools::UpperCase(configuration));
- }
- target->SetProperty(fullprop, this->ResolvePath(value.asString()));
- }
- }
- void cmPackageInfoReader::SetTargetProperties(
- cmMakefile* makefile, cmTarget* target, Json::Value const& data,
- std::string const& package, cm::string_view configuration) const
- {
- // Add configuration (if applicable).
- if (!configuration.empty()) {
- target->AppendProperty("IMPORTED_CONFIGURATIONS",
- cmSystemTools::UpperCase(configuration),
- makefile->GetBacktrace());
- }
- // Add compile and link features.
- for (std::string const& def : ReadList(data, "compile_features")) {
- AddCompileFeature(makefile, target, configuration, def);
- }
- for (std::string const& def : ReadList(data, "link_features")) {
- AddLinkFeature(makefile, target, configuration, def);
- }
- // Add compile definitions.
- Json::Value const& defs = data["definitions"];
- DefinitionsMap definitionsMap;
- for (auto ldi = defs.begin(), lde = defs.end(); ldi != lde; ++ldi) {
- cm::string_view const originalLang = IterKey(ldi);
- cm::string_view const lang = MapLanguage(originalLang);
- if (lang.empty()) {
- makefile->IssueMessage(
- MessageType::WARNING,
- cmStrCat(R"(ignoring unknown language ")"_s, originalLang,
- R"(" in definitions for )"_s, target->GetName()));
- continue;
- }
- for (auto di = ldi->begin(), de = ldi->end(); di != de; ++di) {
- definitionsMap[di.name()].emplace(lang, *di);
- }
- }
- AddDefinitions(makefile, target, configuration, definitionsMap);
- // Add include directories.
- AppendLanguageProperties(makefile, target, "INCLUDE_DIRECTORIES"_s,
- configuration, data, "includes",
- [this](std::string p) -> std::string {
- return this->ResolvePath(std::move(p));
- });
- // Add link name/location(s).
- this->SetOptionalProperty(target, "LOCATION"_s, configuration,
- data["location"]);
- this->SetOptionalProperty(target, "IMPLIB"_s, configuration,
- data["link_location"]);
- this->SetOptionalProperty(target, "SONAME"_s, configuration,
- data["link_name"]);
- // Add link languages.
- for (std::string const& originalLang : ReadList(data, "link_languages")) {
- cm::string_view const lang = MapLanguage(originalLang, DisallowGlob);
- if (!lang.empty()) {
- AppendProperty(makefile, target, "LINK_LANGUAGES"_s, configuration,
- std::string{ lang });
- }
- }
- // Add transitive dependencies.
- for (std::string const& dep : ReadList(data, "requires")) {
- AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration,
- NormalizeTargetName(dep, package));
- }
- for (std::string const& dep : ReadList(data, "link_requires")) {
- std::string const& lib =
- cmStrCat("$<LINK_ONLY:"_s, NormalizeTargetName(dep, package), '>');
- AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration, lib);
- }
- }
- cmTarget* cmPackageInfoReader::AddLibraryComponent(
- cmMakefile* makefile, cmStateEnums::TargetType type, std::string const& name,
- Json::Value const& data, std::string const& package) const
- {
- // Create the imported target.
- cmTarget* const target = makefile->AddImportedTarget(name, type, false);
- // Set target properties.
- this->SetTargetProperties(makefile, target, data, package, {});
- auto const& cfgData = data["configurations"];
- for (auto ci = cfgData.begin(), ce = cfgData.end(); ci != ce; ++ci) {
- this->SetTargetProperties(makefile, target, *ci, package, IterKey(ci));
- }
- // Set default configurations.
- if (!this->DefaultConfigurations.empty()) {
- target->SetProperty("IMPORTED_CONFIGURATIONS",
- cmJoin(this->DefaultConfigurations, ";"_s));
- }
- return target;
- }
- bool cmPackageInfoReader::ImportTargets(cmMakefile* makefile,
- cmExecutionStatus& status)
- {
- std::string const& package = this->GetName();
- // Read components.
- Json::Value const& components = this->Data["components"];
- for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
- cm::string_view const& name = IterKey(ci);
- std::string const& type =
- cmSystemTools::LowerCase((*ci)["type"].asString());
- // Get and validate full target name.
- std::string const& fullName = cmStrCat(package, "::"_s, name);
- {
- std::string msg;
- if (!makefile->EnforceUniqueName(fullName, msg)) {
- status.SetError(msg);
- return false;
- }
- }
- cmTarget* target = nullptr;
- if (type == "symbolic"_s) {
- // TODO
- } else if (type == "dylib"_s) {
- target = this->AddLibraryComponent(
- makefile, cmStateEnums::SHARED_LIBRARY, fullName, *ci, package);
- } else if (type == "module"_s) {
- target = this->AddLibraryComponent(
- makefile, cmStateEnums::MODULE_LIBRARY, fullName, *ci, package);
- } else if (type == "archive"_s) {
- target = this->AddLibraryComponent(
- makefile, cmStateEnums::STATIC_LIBRARY, fullName, *ci, package);
- } else if (type == "interface"_s) {
- target = this->AddLibraryComponent(
- makefile, cmStateEnums::INTERFACE_LIBRARY, fullName, *ci, package);
- } else {
- makefile->IssueMessage(MessageType::WARNING,
- cmStrCat(R"(component ")"_s, fullName,
- R"(" has unknown type ")"_s, type,
- R"(" and was not imported)"_s));
- }
- if (target) {
- this->ComponentTargets.emplace(std::string{ name }, target);
- }
- }
- // Read default components.
- std::vector<std::string> const& defaultComponents =
- ReadList(this->Data, "default_components");
- if (!defaultComponents.empty()) {
- std::string msg;
- if (!makefile->EnforceUniqueName(package, msg)) {
- status.SetError(msg);
- return false;
- }
- cmTarget* const target = makefile->AddImportedTarget(
- package, cmStateEnums::INTERFACE_LIBRARY, false);
- for (std::string const& name : defaultComponents) {
- std::string const& fullName = cmStrCat(package, "::"_s, name);
- AppendProperty(makefile, target, "LINK_LIBRARIES"_s, {}, fullName);
- }
- }
- return true;
- }
- bool cmPackageInfoReader::ImportTargetConfigurations(
- cmMakefile* makefile, cmExecutionStatus& status) const
- {
- std::string const& configuration = this->Data["configuration"].asString();
- if (configuration.empty()) {
- makefile->IssueMessage(MessageType::WARNING,
- cmStrCat("supplemental file "_s, this->Path,
- " does not specify a configuration"_s));
- return true;
- }
- std::string const& package = this->GetName();
- Json::Value const& components = this->Data["components"];
- for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
- // Get component name and look up target.
- cm::string_view const& name = IterKey(ci);
- auto const& ti = this->ComponentTargets.find(std::string{ name });
- if (ti == this->ComponentTargets.end()) {
- status.SetError(cmStrCat("component "_s, name, " was not found"_s));
- return false;
- }
- // Read supplemental data for component.
- this->SetTargetProperties(makefile, ti->second, *ci, package,
- configuration);
- }
- return true;
- }
|