mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
PkgC: Correctly handle various pkg-config edge cases
Fixes many bugs in PkgC by incorporating the 0.0.7 changes from llpkgc. These include: * Variable substitution fixes * Better whitespace handling * Correct handling of single and double quotes * Dedicated parsers for fragment and dependency lists Also adds support for pcfiledir, which was blocked on incorrect whitespace handling in the old parser. Fixes: #27652, #27683
This commit is contained in:
@@ -451,27 +451,64 @@ struct ImportEnv
|
|||||||
bool required;
|
bool required;
|
||||||
bool quiet;
|
bool quiet;
|
||||||
bool exact;
|
bool exact;
|
||||||
bool err;
|
|
||||||
CommonArguments::StrictnessType strictness;
|
CommonArguments::StrictnessType strictness;
|
||||||
cmExecutionStatus& status;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void warn_or_error(std::string const& err, ImportEnv& imEnv)
|
struct ImportState
|
||||||
|
{
|
||||||
|
cmExecutionStatus& status;
|
||||||
|
bool err;
|
||||||
|
};
|
||||||
|
|
||||||
|
void warn_or_error(std::string const& err, ImportEnv imEnv, ImportState& state)
|
||||||
{
|
{
|
||||||
if (imEnv.required) {
|
if (imEnv.required) {
|
||||||
imEnv.status.SetError(err);
|
state.status.SetError(err);
|
||||||
cmSystemTools::SetFatalErrorOccurred();
|
cmSystemTools::SetFatalErrorOccurred();
|
||||||
} else if (!imEnv.quiet) {
|
} else if (!imEnv.quiet) {
|
||||||
imEnv.status.GetMakefile().IssueMessage(MessageType::WARNING, err);
|
state.status.GetMakefile().IssueMessage(MessageType::WARNING, err);
|
||||||
}
|
}
|
||||||
imEnv.err = true;
|
state.err = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cm::optional<cmPkgConfigResult> ReadPackage(std::string const& package,
|
cm::optional<cmPkgConfigDependencySpec> MakeVersionRequirement(
|
||||||
ImportEnv& imEnv,
|
std::string const& version)
|
||||||
cmPkgConfigEnv& pcEnv)
|
|
||||||
{
|
{
|
||||||
cm::optional<cmPkgConfigResult> result;
|
std::string requirement = cmTrimWhitespace(version);
|
||||||
|
std::string expression = "cmake_pkg_config_version";
|
||||||
|
expression += ' ';
|
||||||
|
|
||||||
|
if (requirement.empty()) {
|
||||||
|
expression += '=';
|
||||||
|
} else {
|
||||||
|
char const first = requirement.front();
|
||||||
|
if (first != '<' && first != '>' && first != '=' && first != '!') {
|
||||||
|
expression += "= ";
|
||||||
|
}
|
||||||
|
expression += requirement;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigDependencyParser parser;
|
||||||
|
auto err = parser.Parse(expression.data(), expression.size());
|
||||||
|
if (err != PDEP_OK || parser.Finish() != PDEP_OK) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& dependencies = parser.Dependencies();
|
||||||
|
if (dependencies.size() != 1 ||
|
||||||
|
dependencies.front().Name != "cmake_pkg_config_version") {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
cm::optional<cmPkgConfigResolver> ReadPackage(std::string const& package,
|
||||||
|
ImportEnv imEnv,
|
||||||
|
cmPkgConfigEnv const& pcEnv,
|
||||||
|
ImportState& state)
|
||||||
|
{
|
||||||
|
cm::optional<cmPkgConfigResolver> result;
|
||||||
cm::filesystem::path path{ package };
|
cm::filesystem::path path{ package };
|
||||||
|
|
||||||
if (path.extension() == ".pc") {
|
if (path.extension() == ".pc") {
|
||||||
@@ -510,7 +547,7 @@ cm::optional<cmPkgConfigResult> ReadPackage(std::string const& package,
|
|||||||
|
|
||||||
if (!ifs) {
|
if (!ifs) {
|
||||||
warn_or_error(cmStrCat("Could not open file '", path.string(), '\''),
|
warn_or_error(cmStrCat("Could not open file '", path.string(), '\''),
|
||||||
imEnv);
|
imEnv, state);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,7 +557,7 @@ cm::optional<cmPkgConfigResult> ReadPackage(std::string const& package,
|
|||||||
// Shouldn't have hit eof on previous read, should hit eof now
|
// Shouldn't have hit eof on previous read, should hit eof now
|
||||||
if (ifs.fail() || ifs.eof() || ifs.get() != EOF) {
|
if (ifs.fail() || ifs.eof() || ifs.get() != EOF) {
|
||||||
warn_or_error(cmStrCat("Error while reading file '", path.string(), '\''),
|
warn_or_error(cmStrCat("Error while reading file '", path.string(), '\''),
|
||||||
imEnv);
|
imEnv, state);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,38 +567,45 @@ cm::optional<cmPkgConfigResult> ReadPackage(std::string const& package,
|
|||||||
auto err = parser.Finish(buf.get(), len);
|
auto err = parser.Finish(buf.get(), len);
|
||||||
|
|
||||||
if (imEnv.strictness != StrictnessType::STRICTNESS_BEST_EFFORT &&
|
if (imEnv.strictness != StrictnessType::STRICTNESS_BEST_EFFORT &&
|
||||||
err != PCE_OK) {
|
err != PFCE_OK) {
|
||||||
warn_or_error(cmStrCat("Parsing failed for file '", path.string(), '\''),
|
warn_or_error(cmStrCat("Parsing failed for file '", path.string(), '\''),
|
||||||
imEnv);
|
imEnv, state);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string const pcFileDir = cmSystemTools::GetFilenamePath(
|
||||||
|
cmSystemTools::CollapseFullPath(path.string()));
|
||||||
|
|
||||||
if (imEnv.strictness == StrictnessType::STRICTNESS_STRICT) {
|
if (imEnv.strictness == StrictnessType::STRICTNESS_STRICT) {
|
||||||
result = cmPkgConfigResolver::ResolveStrict(parser.Data(), pcEnv);
|
result =
|
||||||
|
cmPkgConfigResolver::ResolveStrict(std::move(parser), pcEnv, pcFileDir);
|
||||||
} else if (imEnv.strictness == StrictnessType::STRICTNESS_PERMISSIVE) {
|
} else if (imEnv.strictness == StrictnessType::STRICTNESS_PERMISSIVE) {
|
||||||
result = cmPkgConfigResolver::ResolvePermissive(parser.Data(), pcEnv);
|
result = cmPkgConfigResolver::ResolvePermissive(std::move(parser), pcEnv,
|
||||||
|
pcFileDir);
|
||||||
} else {
|
} else {
|
||||||
result = cmPkgConfigResolver::ResolveBestEffort(parser.Data(), pcEnv);
|
result = cmPkgConfigResolver::ResolveBestEffort(std::move(parser), pcEnv,
|
||||||
|
pcFileDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
warn_or_error(
|
warn_or_error(
|
||||||
cmStrCat("Resolution failed for file '", path.string(), '\''), imEnv);
|
cmStrCat("Resolution failed for file '", path.string(), '\''), imEnv,
|
||||||
|
state);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
cm::optional<cmPkgConfigResult> ImportPackage(
|
cm::optional<cmPkgConfigResolver> ImportPackage(
|
||||||
std::string const& package, cm::optional<std::string> version,
|
std::string const& package, cm::optional<std::string> version,
|
||||||
ImportEnv& imEnv, cmPkgConfigEnv& pcEnv)
|
ImportEnv imEnv, cmPkgConfigEnv const& pcEnv, ImportState& state)
|
||||||
{
|
{
|
||||||
auto result = ReadPackage(package, imEnv, pcEnv);
|
auto result = ReadPackage(package, imEnv, pcEnv, state);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (!imEnv.err) {
|
if (!state.err) {
|
||||||
warn_or_error(cmStrCat("Could not find pkg-config: '", package, '\''),
|
warn_or_error(cmStrCat("Could not find pkg-config: '", package, '\''),
|
||||||
imEnv);
|
imEnv, state);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -570,53 +614,64 @@ cm::optional<cmPkgConfigResult> ImportPackage(
|
|||||||
std::string ver;
|
std::string ver;
|
||||||
|
|
||||||
if (version) {
|
if (version) {
|
||||||
ver = cmPkgConfigResolver::ParseVersion(*version).Version;
|
auto req = MakeVersionRequirement(*version);
|
||||||
|
if (!req) {
|
||||||
|
warn_or_error(
|
||||||
|
cmStrCat("Invalid version requirement '", *version, '\''), imEnv,
|
||||||
|
state);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
ver = req->Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ver != result->Version()) {
|
if (ver != result->Version()) {
|
||||||
warn_or_error(
|
warn_or_error(
|
||||||
cmStrCat("Package '", package, "' version '", result->Version(),
|
cmStrCat("Package '", package, "' version '", result->Version(),
|
||||||
"' does not meet exact version requirement '", ver, '\''),
|
"' does not meet exact version requirement '", ver, '\''),
|
||||||
imEnv);
|
imEnv, state);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (version) {
|
} else if (version) {
|
||||||
auto rv = cmPkgConfigResolver::ParseVersion(*version);
|
auto req = MakeVersionRequirement(*version);
|
||||||
if (!cmPkgConfigResolver::CheckVersion(rv, result->Version())) {
|
if (!req) {
|
||||||
|
warn_or_error(cmStrCat("Invalid version requirement '", *version, '\''),
|
||||||
|
imEnv, state);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!cmPkgConfigResolver::CheckVersion(*req, result->Version())) {
|
||||||
warn_or_error(
|
warn_or_error(
|
||||||
cmStrCat("Package '", package, "' version '", result->Version(),
|
cmStrCat("Package '", package, "' version '", result->Version(),
|
||||||
"' does not meet version requirement '", *version, '\''),
|
"' does not meet version requirement '", *version, '\''),
|
||||||
imEnv);
|
imEnv, state);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result->env = &pcEnv;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pkgStackEntry
|
struct pkgStackEntry
|
||||||
{
|
{
|
||||||
cmPkgConfigVersionReq ver;
|
cmPkgConfigDependencySpec Dependency;
|
||||||
std::string parent;
|
std::string parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
cm::optional<cmPkgConfigResult> ImportPackage(
|
cm::optional<cmPkgConfigResolver> ImportPackage(
|
||||||
std::string const& package, std::vector<pkgStackEntry> const& reqs,
|
std::string const& package, std::vector<pkgStackEntry> const& reqs,
|
||||||
ImportEnv& imEnv, cmPkgConfigEnv& pcEnv)
|
ImportEnv imEnv, cmPkgConfigEnv const& pcEnv, ImportState& state)
|
||||||
{
|
{
|
||||||
auto result = ReadPackage(package, imEnv, pcEnv);
|
auto result = ReadPackage(package, imEnv, pcEnv, state);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (!imEnv.err) {
|
if (!state.err) {
|
||||||
std::string req_str = cmStrCat('\'', reqs.begin()->parent, '\'');
|
std::string req_str = cmStrCat('\'', reqs.begin()->parent, '\'');
|
||||||
for (auto it = reqs.begin() + 1; it != reqs.end(); ++it) {
|
for (auto it = reqs.begin() + 1; it != reqs.end(); ++it) {
|
||||||
req_str = cmStrCat(req_str, ", '", it->parent, '\'');
|
req_str = cmStrCat(req_str, ", '", it->parent, '\'');
|
||||||
}
|
}
|
||||||
warn_or_error(cmStrCat("Could not find pkg-config: '", package,
|
warn_or_error(cmStrCat("Could not find pkg-config: '", package,
|
||||||
"' required by: ", req_str),
|
"' required by: ", req_str),
|
||||||
imEnv);
|
imEnv, state);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -624,16 +679,17 @@ cm::optional<cmPkgConfigResult> ImportPackage(
|
|||||||
auto ver = result->Version();
|
auto ver = result->Version();
|
||||||
for (auto const& req : reqs) {
|
for (auto const& req : reqs) {
|
||||||
|
|
||||||
if (!cmPkgConfigResolver::CheckVersion(req.ver, ver)) {
|
if (!cmPkgConfigResolver::CheckVersion(req.Dependency, ver)) {
|
||||||
warn_or_error(cmStrCat("Package '", package, "' version '", ver,
|
warn_or_error(
|
||||||
"' does not meet version requirement '",
|
cmStrCat("Package '", package, "' version '", ver,
|
||||||
req.ver.string(), "' of '", req.parent, '\''),
|
"' does not meet version requirement '",
|
||||||
imEnv);
|
cmPkgConfigResolver::VersionReqString(req.Dependency),
|
||||||
|
"' of '", req.parent, '\''),
|
||||||
|
imEnv, state);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result->env = &pcEnv;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,8 +735,7 @@ cm::optional<std::pair<cmPkgConfigEnv, ImportEnv>> HandleCommon(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return std::pair<cmPkgConfigEnv, ImportEnv>{
|
return std::pair<cmPkgConfigEnv, ImportEnv>{
|
||||||
pcEnv,
|
pcEnv, { args.Required, args.Quiet, args.Exact, args.Strictness }
|
||||||
{ args.Required, args.Quiet, args.Exact, false, args.Strictness, status }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,10 +769,11 @@ bool HandleExtractCommand(std::vector<std::string> const& args,
|
|||||||
return !parsedArgs.Required;
|
return !parsedArgs.Required;
|
||||||
}
|
}
|
||||||
auto& pcEnv = maybeEnv->first;
|
auto& pcEnv = maybeEnv->first;
|
||||||
auto& imEnv = maybeEnv->second;
|
auto const& imEnv = maybeEnv->second;
|
||||||
|
ImportState state{ status, false };
|
||||||
|
|
||||||
auto maybePackage =
|
auto maybePackage = ImportPackage(*parsedArgs.Package, parsedArgs.Version,
|
||||||
ImportPackage(*parsedArgs.Package, parsedArgs.Version, imEnv, pcEnv);
|
imEnv, pcEnv, state);
|
||||||
if (!maybePackage) {
|
if (!maybePackage) {
|
||||||
return !parsedArgs.Required;
|
return !parsedArgs.Required;
|
||||||
}
|
}
|
||||||
@@ -745,7 +801,7 @@ bool HandleExtractCommand(std::vector<std::string> const& args,
|
|||||||
mf.AddDefinition("CMAKE_PKG_CONFIG_VERSION", package.Version());
|
mf.AddDefinition("CMAKE_PKG_CONFIG_VERSION", package.Version());
|
||||||
|
|
||||||
auto make_list = [&](char const* def,
|
auto make_list = [&](char const* def,
|
||||||
std::vector<cmPkgConfigDependency> const& deps) {
|
std::vector<cmPkgConfigDependencySpec> const& deps) {
|
||||||
std::vector<cm::string_view> vec;
|
std::vector<cm::string_view> vec;
|
||||||
vec.reserve(deps.size());
|
vec.reserve(deps.size());
|
||||||
|
|
||||||
@@ -800,8 +856,8 @@ using pkgStack = std::unordered_map<std::string, std::vector<pkgStackEntry>>;
|
|||||||
using pkgProviders = std::unordered_map<std::string, std::string>;
|
using pkgProviders = std::unordered_map<std::string, std::string>;
|
||||||
|
|
||||||
cmTarget* CreateCMakeTarget(std::string const& name, std::string const& prefix,
|
cmTarget* CreateCMakeTarget(std::string const& name, std::string const& prefix,
|
||||||
cmPkgConfigResult& pkg, pkgProviders& providers,
|
cmPkgConfigResolver const& pkg,
|
||||||
cmMakefile& mf)
|
pkgProviders const& providers, cmMakefile& mf)
|
||||||
{
|
{
|
||||||
auto* tgt = mf.AddForeignTarget("pkgcfg", cmStrCat(prefix, name));
|
auto* tgt = mf.AddForeignTarget("pkgcfg", cmStrCat(prefix, name));
|
||||||
|
|
||||||
@@ -824,7 +880,7 @@ cmTarget* CreateCMakeTarget(std::string const& name, std::string const& prefix,
|
|||||||
tgt->AppendProperty("INTERFACE_COMPILE_OPTIONS",
|
tgt->AppendProperty("INTERFACE_COMPILE_OPTIONS",
|
||||||
cmList::to_string(cflags.CompileOptions));
|
cmList::to_string(cflags.CompileOptions));
|
||||||
|
|
||||||
for (auto& dep : pkg.Requires()) {
|
for (auto const& dep : pkg.Requires()) {
|
||||||
auto it = providers.find(dep.Name);
|
auto it = providers.find(dep.Name);
|
||||||
if (it != providers.end()) {
|
if (it != providers.end()) {
|
||||||
tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", it->second);
|
tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", it->second);
|
||||||
@@ -838,27 +894,28 @@ cmTarget* CreateCMakeTarget(std::string const& name, std::string const& prefix,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CheckPackageDependencies(
|
bool CheckPackageDependencies(
|
||||||
std::string const& name, std::string const& prefix, cmPkgConfigResult& pkg,
|
std::string const& name, std::string const& prefix,
|
||||||
pkgStack& inStack,
|
cmPkgConfigResolver const& pkg, pkgStack& inStack,
|
||||||
std::unordered_map<std::string, cmPkgConfigResult>& outStack,
|
std::unordered_map<std::string, cmPkgConfigResolver> const& outStack,
|
||||||
pkgProviders& providers, ImportEnv& imEnv)
|
pkgProviders const& providers, ImportEnv imEnv, ImportState& state)
|
||||||
{
|
{
|
||||||
for (auto& dep : pkg.Requires()) {
|
for (auto const& dep : pkg.Requires()) {
|
||||||
auto prov_it = providers.find(dep.Name);
|
auto prov_it = providers.find(dep.Name);
|
||||||
if (prov_it != providers.end()) {
|
if (prov_it != providers.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* tgt = imEnv.status.GetMakefile().FindTargetToUse(
|
auto* tgt = state.status.GetMakefile().FindTargetToUse(
|
||||||
cmStrCat("@foreign_pkgcfg::", prefix, dep.Name),
|
cmStrCat("@foreign_pkgcfg::", prefix, dep.Name),
|
||||||
cm::TargetDomain::FOREIGN);
|
cm::TargetDomain::FOREIGN);
|
||||||
if (tgt) {
|
if (tgt) {
|
||||||
auto ver = tgt->GetProperty("VERSION");
|
auto ver = tgt->GetProperty("VERSION");
|
||||||
if (!cmPkgConfigResolver::CheckVersion(dep.VerReq, *ver)) {
|
if (!cmPkgConfigResolver::CheckVersion(dep, *ver)) {
|
||||||
warn_or_error(cmStrCat("Package '", dep.Name, "' version '", *ver,
|
warn_or_error(cmStrCat("Package '", dep.Name, "' version '", *ver,
|
||||||
"' does not meet version requirement '",
|
"' does not meet version requirement '",
|
||||||
dep.VerReq.string(), "' of '", name, '\''),
|
cmPkgConfigResolver::VersionReqString(dep),
|
||||||
imEnv);
|
"' of '", name, '\''),
|
||||||
|
imEnv, state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -867,18 +924,18 @@ bool CheckPackageDependencies(
|
|||||||
auto it = outStack.find(dep.Name);
|
auto it = outStack.find(dep.Name);
|
||||||
if (it != outStack.end()) {
|
if (it != outStack.end()) {
|
||||||
auto ver = it->second.Version();
|
auto ver = it->second.Version();
|
||||||
if (!cmPkgConfigResolver::CheckVersion(dep.VerReq, ver)) {
|
if (!cmPkgConfigResolver::CheckVersion(dep, ver)) {
|
||||||
warn_or_error(cmStrCat("Package '", dep.Name, "' version '", ver,
|
warn_or_error(cmStrCat("Package '", dep.Name, "' version '", ver,
|
||||||
"' does not meet version requirement '",
|
"' does not meet version requirement '",
|
||||||
dep.VerReq.string(), "' of '", name, '\''),
|
cmPkgConfigResolver::VersionReqString(dep),
|
||||||
imEnv);
|
"' of '", name, '\''),
|
||||||
|
imEnv, state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
inStack[dep.Name].emplace_back(
|
inStack[dep.Name].emplace_back(pkgStackEntry{ dep, name });
|
||||||
pkgStackEntry{ std::move(dep.VerReq), name });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -910,11 +967,13 @@ std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
|
|||||||
return { !args.Required, false };
|
return { !args.Required, false };
|
||||||
}
|
}
|
||||||
auto& pcEnv = maybeEnv->first;
|
auto& pcEnv = maybeEnv->first;
|
||||||
auto& imEnv = maybeEnv->second;
|
|
||||||
|
|
||||||
pcEnv.AllowSysCflags = true;
|
pcEnv.AllowSysCflags = true;
|
||||||
pcEnv.AllowSysLibs = true;
|
pcEnv.AllowSysLibs = true;
|
||||||
|
|
||||||
|
auto const& imEnv = maybeEnv->second;
|
||||||
|
ImportState state{ status, false };
|
||||||
|
|
||||||
pkgProviders providers;
|
pkgProviders providers;
|
||||||
if (args.Providers) {
|
if (args.Providers) {
|
||||||
for (auto const& provider_str : *args.Providers) {
|
for (auto const& provider_str : *args.Providers) {
|
||||||
@@ -923,7 +982,7 @@ std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
|
|||||||
providers.emplace(provider_str.substr(0, assignment),
|
providers.emplace(provider_str.substr(0, assignment),
|
||||||
provider_str.substr(assignment + 1));
|
provider_str.substr(assignment + 1));
|
||||||
} else {
|
} else {
|
||||||
imEnv.status.SetError(cmStrCat(
|
state.status.SetError(cmStrCat(
|
||||||
"No '=' found in BIND_PC_REQUIRES argument '", provider_str, '\''));
|
"No '=' found in BIND_PC_REQUIRES argument '", provider_str, '\''));
|
||||||
cmSystemTools::SetFatalErrorOccurred();
|
cmSystemTools::SetFatalErrorOccurred();
|
||||||
return { false, false };
|
return { false, false };
|
||||||
@@ -932,33 +991,35 @@ std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pkgStack inStack;
|
pkgStack inStack;
|
||||||
std::unordered_map<std::string, cmPkgConfigResult> outStack;
|
std::unordered_map<std::string, cmPkgConfigResolver> outStack;
|
||||||
|
|
||||||
auto maybePackage = ImportPackage(*args.Package, args.Version, imEnv, pcEnv);
|
auto maybePackage =
|
||||||
|
ImportPackage(*args.Package, args.Version, imEnv, pcEnv, state);
|
||||||
if (!maybePackage) {
|
if (!maybePackage) {
|
||||||
return { !args.Required, false };
|
return { !args.Required, false };
|
||||||
}
|
}
|
||||||
imEnv.exact = false;
|
ImportEnv depEnv = imEnv;
|
||||||
|
depEnv.exact = false;
|
||||||
|
|
||||||
if (!CheckPackageDependencies(*args.Package, prefix, *maybePackage, inStack,
|
if (!CheckPackageDependencies(*args.Package, prefix, *maybePackage, inStack,
|
||||||
outStack, providers, imEnv)) {
|
outStack, providers, depEnv, state)) {
|
||||||
return { !args.Required, false };
|
return { !args.Required, false };
|
||||||
}
|
}
|
||||||
outStack[*args.Package] = std::move(*maybePackage);
|
outStack.emplace(*args.Package, std::move(*maybePackage));
|
||||||
|
|
||||||
while (!inStack.empty()) {
|
while (!inStack.empty()) {
|
||||||
auto name = inStack.begin()->first;
|
auto name = inStack.begin()->first;
|
||||||
auto reqs = inStack.begin()->second;
|
auto reqs = inStack.begin()->second;
|
||||||
maybePackage = ImportPackage(name, reqs, imEnv, pcEnv);
|
maybePackage = ImportPackage(name, reqs, depEnv, pcEnv, state);
|
||||||
if (!maybePackage) {
|
if (!maybePackage) {
|
||||||
return { !args.Required, false };
|
return { !args.Required, false };
|
||||||
}
|
}
|
||||||
if (!CheckPackageDependencies(name, prefix, *maybePackage, inStack,
|
if (!CheckPackageDependencies(name, prefix, *maybePackage, inStack,
|
||||||
outStack, providers, imEnv)) {
|
outStack, providers, depEnv, state)) {
|
||||||
return { !args.Required, false };
|
return { !args.Required, false };
|
||||||
}
|
}
|
||||||
inStack.erase(name);
|
inStack.erase(name);
|
||||||
outStack[std::move(name)] = std::move(*maybePackage);
|
outStack.emplace(std::move(name), std::move(*maybePackage));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& entry : outStack) {
|
for (auto& entry : outStack) {
|
||||||
|
|||||||
+567
-59
@@ -3,98 +3,248 @@
|
|||||||
|
|
||||||
#include "cmPkgConfigParser.h"
|
#include "cmPkgConfigParser.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cm/string_view>
|
#include <cm/string_view>
|
||||||
|
|
||||||
#include <cmllpkgc/llpkgc.h>
|
#include <cmllpkgc/llpkgc.h>
|
||||||
|
|
||||||
cmPkgConfigValueElement::cmPkgConfigValueElement(bool isVariable,
|
namespace {
|
||||||
cm::string_view data)
|
|
||||||
: IsVariable{ isVariable }
|
cmPkgConfigDependencyOperation LookupDependencyOperation(cm::string_view op)
|
||||||
, Data{ data }
|
{
|
||||||
|
if (op == "<") {
|
||||||
|
return cmPkgConfigDependencyOperation::LessThan;
|
||||||
|
}
|
||||||
|
if (op == "<=") {
|
||||||
|
return cmPkgConfigDependencyOperation::LessThanEqual;
|
||||||
|
}
|
||||||
|
if (op == "=") {
|
||||||
|
return cmPkgConfigDependencyOperation::Equal;
|
||||||
|
}
|
||||||
|
if (op == "!=") {
|
||||||
|
return cmPkgConfigDependencyOperation::NotEqual;
|
||||||
|
}
|
||||||
|
if (op == ">") {
|
||||||
|
return cmPkgConfigDependencyOperation::GreaterThan;
|
||||||
|
}
|
||||||
|
if (op == ">=") {
|
||||||
|
return cmPkgConfigDependencyOperation::GreaterThanEqual;
|
||||||
|
}
|
||||||
|
return cmPkgConfigDependencyOperation::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
cmPkgConfigValueItem::cmPkgConfigValueItem(std::string text,
|
||||||
|
bool isSubstitution)
|
||||||
|
: Text{ std::move(text) }
|
||||||
|
, IsSubstitution{ isSubstitution }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPkgConfigEntry::cmPkgConfigEntry(bool isVariable, cm::string_view key)
|
cmPkgConfigEntry::cmPkgConfigEntry(std::vector<cmPkgConfigValueItem> value,
|
||||||
: IsVariable{ isVariable }
|
std::string ident,
|
||||||
, Key{ key }
|
cmPkgConfigEntryKind kind)
|
||||||
|
: Value{ std::move(value) }
|
||||||
|
, Ident{ std::move(ident) }
|
||||||
|
, Kind{ kind }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPkgConfigParser::cmPkgConfigParser()
|
cmPkgConfigFileParser::cmPkgConfigFileParser()
|
||||||
{
|
{
|
||||||
llpkgc_init(static_cast<llpkgc_t*>(this), &Settings_);
|
llpkgc_file_init(static_cast<llpkgc_file_t*>(this), &Settings_);
|
||||||
}
|
}
|
||||||
|
|
||||||
llpkgc_errno_t cmPkgConfigParser::Parse(char* buf, std::size_t len)
|
cmPkgConfigFileParser::cmPkgConfigFileParser(
|
||||||
|
cmPkgConfigFileParser const& other)
|
||||||
|
: cmPkgConfigFileParser()
|
||||||
{
|
{
|
||||||
return llpkgc_execute(static_cast<llpkgc_t*>(this), buf, len);
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
llpkgc_errno_t cmPkgConfigParser::Finish()
|
cmPkgConfigFileParser::cmPkgConfigFileParser(
|
||||||
|
cmPkgConfigFileParser&& other) noexcept
|
||||||
|
: cmPkgConfigFileParser()
|
||||||
{
|
{
|
||||||
return llpkgc_finish(static_cast<llpkgc_t*>(this));
|
*this = std::move(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
llpkgc_errno_t cmPkgConfigParser::Finish(char* buf, std::size_t len)
|
cmPkgConfigFileParser& cmPkgConfigFileParser::operator=(
|
||||||
|
cmPkgConfigFileParser const& other)
|
||||||
{
|
{
|
||||||
Parse(buf, len);
|
if (this != &other) {
|
||||||
return llpkgc_finish(static_cast<llpkgc_t*>(this));
|
this->ResetCallbacks();
|
||||||
|
llpkgc_file_init(static_cast<llpkgc_file_t*>(this), &Settings_);
|
||||||
|
Ptr_ = nullptr;
|
||||||
|
Len_ = 0;
|
||||||
|
Ident_ = other.Ident_;
|
||||||
|
Data_ = other.Data_;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnSpanNext(char const*, std::size_t len)
|
cmPkgConfigFileParser& cmPkgConfigFileParser::operator=(
|
||||||
|
cmPkgConfigFileParser&& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
this->ResetCallbacks();
|
||||||
|
llpkgc_file_init(static_cast<llpkgc_file_t*>(this), &Settings_);
|
||||||
|
Ptr_ = nullptr;
|
||||||
|
Len_ = 0;
|
||||||
|
Ident_ = std::move(other.Ident_);
|
||||||
|
Data_ = std::move(other.Data_);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmPkgConfigFileParser::ResetCallbacks()
|
||||||
|
{
|
||||||
|
Settings_.on_ident = OnIdentTr;
|
||||||
|
Settings_.on_value_literal = OnValueLiteralTr;
|
||||||
|
Settings_.on_value_substitution = OnValueSubstitutionTr;
|
||||||
|
Settings_.on_line_begin = nullptr;
|
||||||
|
Settings_.on_property_complete = OnPropertyCompleteTr;
|
||||||
|
Settings_.on_variable_complete = OnVariableCompleteTr;
|
||||||
|
Settings_.on_barewords_complete = OnBarewordsCompleteTr;
|
||||||
|
Settings_.on_value_literal_complete = OnValueLiteralCompleteTr;
|
||||||
|
Settings_.on_value_substitution_complete = OnValueSubstitutionCompleteTr;
|
||||||
|
Settings_.on_value_complete = OnValueCompleteTr;
|
||||||
|
Settings_.on_pkgc_complete = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_file_errno_t cmPkgConfigFileParser::Parse(char const* input,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return llpkgc_file_execute(static_cast<llpkgc_file_t*>(this), input, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_file_errno_t cmPkgConfigFileParser::Finish()
|
||||||
|
{
|
||||||
|
return llpkgc_file_finish(static_cast<llpkgc_file_t*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmPkgConfigFileParser::Resume()
|
||||||
|
{
|
||||||
|
llpkgc_file_resume(static_cast<llpkgc_file_t*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_file_errno_t cmPkgConfigFileParser::GetErrno() const
|
||||||
|
{
|
||||||
|
return llpkgc_file_get_errno(static_cast<llpkgc_file_t const*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* cmPkgConfigFileParser::ErrorReason() const
|
||||||
|
{
|
||||||
|
return llpkgc_file_get_error_reason(static_cast<llpkgc_file_t const*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ptrdiff_t cmPkgConfigFileParser::ErrorOffset(char const* base) const
|
||||||
|
{
|
||||||
|
char const* pos =
|
||||||
|
llpkgc_file_get_error_pos(static_cast<llpkgc_file_t const*>(this));
|
||||||
|
if (pos == nullptr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pos - base;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFileParser::OnIdentNext(char const* at, std::size_t len)
|
||||||
|
{
|
||||||
|
Ident_.append(at, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFileParser::OnIdentNextTr(llpkgc_file_t* parser, char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnIdentNext(at, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmPkgConfigFileParser::AppendValue(std::string text, bool isSubstitution)
|
||||||
|
{
|
||||||
|
if (!isSubstitution && !Data_.empty() && !Data_.back().Value.empty() &&
|
||||||
|
!Data_.back().Value.back().IsSubstitution) {
|
||||||
|
Data_.back().Value.back().Text += text;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_.back().Value.emplace_back(std::move(text), isSubstitution);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFileParser::OnSpanNext(char const*, std::size_t len)
|
||||||
{
|
{
|
||||||
Len_ += len;
|
Len_ += len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnSpanNextTr(llpkgc_t* parser, char const* at,
|
int cmPkgConfigFileParser::OnSpanNextTr(llpkgc_file_t* parser, char const* at,
|
||||||
std::size_t len)
|
std::size_t len)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnSpanNext(at, len);
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnSpanNext(at, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnKey(char const* at, std::size_t len)
|
int cmPkgConfigFileParser::OnIdent(char const* at, std::size_t len)
|
||||||
{
|
{
|
||||||
Ptr_ = at;
|
Ident_.assign(at, len);
|
||||||
Len_ = len;
|
Settings_.on_ident = OnIdentNextTr;
|
||||||
Settings_.on_key = OnSpanNextTr;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnKeyTr(llpkgc_t* parser, char const* at,
|
int cmPkgConfigFileParser::OnIdentTr(llpkgc_file_t* parser, char const* at,
|
||||||
std::size_t len)
|
std::size_t len)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnKey(at, len);
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnIdent(at, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnKeywordComplete()
|
int cmPkgConfigFileParser::OnPropertyComplete()
|
||||||
{
|
{
|
||||||
Data_.emplace_back(false, cm::string_view{ Ptr_, Len_ });
|
Data_.emplace_back(std::vector<cmPkgConfigValueItem>{}, Ident_,
|
||||||
Settings_.on_key = OnKeyTr;
|
cmPkgConfigEntryKind::Property);
|
||||||
|
Settings_.on_ident = OnIdentTr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnKeywordCompleteTr(llpkgc_t* parser)
|
int cmPkgConfigFileParser::OnPropertyCompleteTr(llpkgc_file_t* parser)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnKeywordComplete();
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnPropertyComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnVariableComplete()
|
int cmPkgConfigFileParser::OnVariableComplete()
|
||||||
{
|
{
|
||||||
Data_.emplace_back(true, cm::string_view{ Ptr_, Len_ });
|
Data_.emplace_back(std::vector<cmPkgConfigValueItem>{}, Ident_,
|
||||||
Settings_.on_key = OnKeyTr;
|
cmPkgConfigEntryKind::Variable);
|
||||||
|
Settings_.on_ident = OnIdentTr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnVariableCompleteTr(llpkgc_t* parser)
|
int cmPkgConfigFileParser::OnVariableCompleteTr(llpkgc_file_t* parser)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnVariableComplete();
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnVariableComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueLiteral(char const* at, std::size_t len)
|
int cmPkgConfigFileParser::OnBarewordsComplete()
|
||||||
|
{
|
||||||
|
Data_.emplace_back(std::vector<cmPkgConfigValueItem>{}, Ident_,
|
||||||
|
cmPkgConfigEntryKind::Barewords);
|
||||||
|
Settings_.on_ident = OnIdentTr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFileParser::OnBarewordsCompleteTr(llpkgc_file_t* parser)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnBarewordsComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFileParser::OnValueLiteral(char const* at, std::size_t len)
|
||||||
{
|
{
|
||||||
Ptr_ = at;
|
Ptr_ = at;
|
||||||
Len_ = len;
|
Len_ = len;
|
||||||
@@ -102,50 +252,408 @@ int cmPkgConfigParser::OnValueLiteral(char const* at, std::size_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueLiteralTr(llpkgc_t* parser, char const* at,
|
int cmPkgConfigFileParser::OnValueLiteralTr(llpkgc_file_t* parser,
|
||||||
std::size_t len)
|
char const* at, std::size_t len)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueLiteral(at, len);
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnValueLiteral(at, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueLiteralComplete()
|
int cmPkgConfigFileParser::OnValueLiteralComplete()
|
||||||
{
|
{
|
||||||
Settings_.on_value_literal = OnValueLiteralTr;
|
Settings_.on_value_literal = OnValueLiteralTr;
|
||||||
|
AppendValue(std::string{ Ptr_, Len_ }, false);
|
||||||
if (Len_) {
|
|
||||||
Data_.back().Val.emplace_back(false, cm::string_view{ Ptr_, Len_ });
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueLiteralCompleteTr(llpkgc_t* parser)
|
int cmPkgConfigFileParser::OnValueLiteralCompleteTr(llpkgc_file_t* parser)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueLiteralComplete();
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnValueLiteralComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueVariable(char const* at, std::size_t len)
|
int cmPkgConfigFileParser::OnValueSubstitution(char const* at, std::size_t len)
|
||||||
{
|
{
|
||||||
Ptr_ = at;
|
Ptr_ = at;
|
||||||
Len_ = len;
|
Len_ = len;
|
||||||
Settings_.on_value_variable = OnSpanNextTr;
|
Settings_.on_value_substitution = OnSpanNextTr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueVariableTr(llpkgc_t* parser, char const* at,
|
int cmPkgConfigFileParser::OnValueSubstitutionTr(llpkgc_file_t* parser,
|
||||||
std::size_t len)
|
char const* at,
|
||||||
|
std::size_t len)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueVariable(at, len);
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnValueSubstitution(at,
|
||||||
|
len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueVariableComplete()
|
int cmPkgConfigFileParser::OnValueSubstitutionComplete()
|
||||||
{
|
{
|
||||||
Settings_.on_value_variable = OnValueVariableTr;
|
Settings_.on_value_substitution = OnValueSubstitutionTr;
|
||||||
Data_.back().Val.emplace_back(true, cm::string_view{ Ptr_, Len_ });
|
AppendValue(std::string{ Ptr_, Len_ }, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmPkgConfigParser::OnValueVariableCompleteTr(llpkgc_t* parser)
|
int cmPkgConfigFileParser::OnValueSubstitutionCompleteTr(llpkgc_file_t* parser)
|
||||||
{
|
{
|
||||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueVariableComplete();
|
return static_cast<cmPkgConfigFileParser*>(parser)
|
||||||
|
->OnValueSubstitutionComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFileParser::OnValueComplete()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFileParser::OnValueCompleteTr(llpkgc_file_t* parser)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigFileParser*>(parser)->OnValueComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigFragmentParser::cmPkgConfigFragmentParser()
|
||||||
|
{
|
||||||
|
llpkgc_frag_init(static_cast<llpkgc_frag_t*>(this), &Settings_);
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_frag_errno_t cmPkgConfigFragmentParser::Parse(char const* input,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return llpkgc_frag_execute(static_cast<llpkgc_frag_t*>(this), input, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_frag_errno_t cmPkgConfigFragmentParser::Finish()
|
||||||
|
{
|
||||||
|
return llpkgc_frag_finish(static_cast<llpkgc_frag_t*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_frag_errno_t cmPkgConfigFragmentParser::GetErrno() const
|
||||||
|
{
|
||||||
|
return llpkgc_frag_get_errno(static_cast<llpkgc_frag_t const*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* cmPkgConfigFragmentParser::ErrorReason() const
|
||||||
|
{
|
||||||
|
return llpkgc_frag_get_error_reason(static_cast<llpkgc_frag_t const*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFragmentParser::OnFragmentText(char const* at, std::size_t len)
|
||||||
|
{
|
||||||
|
CurrentFragment_.append(at, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFragmentParser::OnFragmentTextTr(llpkgc_frag_t* parser,
|
||||||
|
char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigFragmentParser*>(parser)->OnFragmentText(at,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFragmentParser::OnFragmentComplete()
|
||||||
|
{
|
||||||
|
Fragments_.push_back(std::move(CurrentFragment_));
|
||||||
|
CurrentFragment_.clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigFragmentParser::OnFragmentCompleteTr(llpkgc_frag_t* parser)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigFragmentParser*>(parser)->OnFragmentComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigDependencyParser::cmPkgConfigDependencyParser()
|
||||||
|
{
|
||||||
|
llpkgc_dep_init(static_cast<llpkgc_dep_t*>(this), &Settings_);
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_dep_errno_t cmPkgConfigDependencyParser::Parse(char const* input,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return llpkgc_dep_execute(static_cast<llpkgc_dep_t*>(this), input, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_dep_errno_t cmPkgConfigDependencyParser::Finish()
|
||||||
|
{
|
||||||
|
return llpkgc_dep_finish(static_cast<llpkgc_dep_t*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_dep_errno_t cmPkgConfigDependencyParser::GetErrno() const
|
||||||
|
{
|
||||||
|
return llpkgc_dep_get_errno(static_cast<llpkgc_dep_t const*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* cmPkgConfigDependencyParser::ErrorReason() const
|
||||||
|
{
|
||||||
|
return llpkgc_dep_get_error_reason(static_cast<llpkgc_dep_t const*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyName(char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
Current_.Name.assign(at, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyNameTr(llpkgc_dep_t* parser,
|
||||||
|
char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigDependencyParser*>(parser)->OnDependencyName(
|
||||||
|
at, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyOperator(char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
Current_.Operation = LookupDependencyOperation(cm::string_view{ at, len });
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyOperatorTr(llpkgc_dep_t* parser,
|
||||||
|
char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigDependencyParser*>(parser)
|
||||||
|
->OnDependencyOperator(at, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyVersion(char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
Current_.Version.assign(at, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyVersionTr(llpkgc_dep_t* parser,
|
||||||
|
char const* at,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigDependencyParser*>(parser)
|
||||||
|
->OnDependencyVersion(at, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyComplete()
|
||||||
|
{
|
||||||
|
Dependencies_.push_back(std::move(Current_));
|
||||||
|
Current_ = cmPkgConfigDependencySpec{};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmPkgConfigDependencyParser::OnDependencyCompleteTr(llpkgc_dep_t* parser)
|
||||||
|
{
|
||||||
|
return static_cast<cmPkgConfigDependencyParser*>(parser)
|
||||||
|
->OnDependencyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_file_errno_t cmPkgConfigParser::Parse(char const* input,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
return File_.Parse(input, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_file_errno_t cmPkgConfigParser::Finish()
|
||||||
|
{
|
||||||
|
return File_.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_file_errno_t cmPkgConfigParser::Finish(char const* input,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
auto err = Parse(input, len);
|
||||||
|
if (err != PFCE_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
llpkgc_file_errno_t cmPkgConfigParser::GetErrno() const
|
||||||
|
{
|
||||||
|
return File_.GetErrno();
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* cmPkgConfigParser::ErrorReason() const
|
||||||
|
{
|
||||||
|
return File_.ErrorReason();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ptrdiff_t cmPkgConfigParser::ErrorOffset(char const* base) const
|
||||||
|
{
|
||||||
|
return File_.ErrorOffset(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmPkgConfigParser::SetVariable(std::string name, std::string value)
|
||||||
|
{
|
||||||
|
ValueItems variable;
|
||||||
|
variable.emplace_back(std::move(value), false);
|
||||||
|
StoredVariables_[std::move(name)] = std::move(variable);
|
||||||
|
Cache_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigParser::GetVariable(std::string const& name)
|
||||||
|
{
|
||||||
|
return ResolveValue(StoredVariables_[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmPkgConfigParser::HasProperty(std::string const& name) const
|
||||||
|
{
|
||||||
|
return std::any_of(StoredProperties_.begin(), StoredProperties_.end(),
|
||||||
|
[&name](cmPkgConfigEntry const& entry) -> bool {
|
||||||
|
return entry.Ident == name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> cmPkgConfigParser::GetFragments(
|
||||||
|
std::string const& name)
|
||||||
|
{
|
||||||
|
auto it = Cache_.find(name);
|
||||||
|
if (it != Cache_.end()) {
|
||||||
|
return it->second.Fragments;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigResolvedValue cache;
|
||||||
|
if (!ResolveAndParse(name, cache)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return cache.Fragments;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cmPkgConfigDependencySpec> cmPkgConfigParser::GetDependencies(
|
||||||
|
std::string const& name)
|
||||||
|
{
|
||||||
|
auto it = Cache_.find(name);
|
||||||
|
if (it != Cache_.end()) {
|
||||||
|
return it->second.Dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigResolvedValue cache;
|
||||||
|
if (!ResolveAndParse(name, cache)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return cache.Dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigParser::GetLiteral(std::string const& name)
|
||||||
|
{
|
||||||
|
auto it = Cache_.find(name);
|
||||||
|
if (it != Cache_.end()) {
|
||||||
|
return it->second.Literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigResolvedValue cache;
|
||||||
|
if (!ResolveAndParse(name, cache)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return cache.Literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmPkgConfigParser::ParseComplete()
|
||||||
|
{
|
||||||
|
StoredVariables_.clear();
|
||||||
|
StoredProperties_.clear();
|
||||||
|
Cache_.clear();
|
||||||
|
|
||||||
|
for (auto const& entry : File_.Data_) {
|
||||||
|
switch (entry.Kind) {
|
||||||
|
case cmPkgConfigEntryKind::Variable:
|
||||||
|
StoredVariables_[entry.Ident] = entry.Value;
|
||||||
|
break;
|
||||||
|
case cmPkgConfigEntryKind::Property:
|
||||||
|
StoredProperties_.push_back(entry);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigParser::ResolveValue(ValueItems const& items)
|
||||||
|
{
|
||||||
|
return ResolveValueImpl(items, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigParser::ResolveValueImpl(
|
||||||
|
ValueItems const& items, std::set<std::string> resolving)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
if (items.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& item : items) {
|
||||||
|
if (item.IsSubstitution) {
|
||||||
|
if (resolving.count(item.Text)) {
|
||||||
|
result += "${";
|
||||||
|
result += item.Text;
|
||||||
|
result += "}";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto it = StoredVariables_.find(item.Text);
|
||||||
|
if (it != StoredVariables_.end()) {
|
||||||
|
resolving.insert(item.Text);
|
||||||
|
result += ResolveValueImpl(it->second, resolving);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += item.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmPkgConfigParser::ResolveAndParse(std::string const& name,
|
||||||
|
cmPkgConfigResolvedValue& cache)
|
||||||
|
{
|
||||||
|
cmPkgConfigEntry const* entry = nullptr;
|
||||||
|
for (auto const& candidate : StoredProperties_) {
|
||||||
|
if (candidate.Ident == name) {
|
||||||
|
entry = &candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string resolved = ResolveValue(entry->Value);
|
||||||
|
auto start = resolved.find_first_not_of(" \t");
|
||||||
|
if (start != std::string::npos) {
|
||||||
|
resolved.erase(0, start);
|
||||||
|
}
|
||||||
|
cache.Literal = resolved;
|
||||||
|
|
||||||
|
std::string lower = name;
|
||||||
|
for (auto& c : lower) {
|
||||||
|
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsFragmentProperty(lower)) {
|
||||||
|
cmPkgConfigFragmentParser fragmentParser;
|
||||||
|
auto err = fragmentParser.Parse(resolved.data(), resolved.size());
|
||||||
|
if (err == PFFE_OK && fragmentParser.Finish() == PFFE_OK) {
|
||||||
|
cache.Fragments = fragmentParser.Fragments();
|
||||||
|
}
|
||||||
|
} else if (IsDependencyProperty(lower)) {
|
||||||
|
cmPkgConfigDependencyParser dependencyParser;
|
||||||
|
auto err = dependencyParser.Parse(resolved.data(), resolved.size());
|
||||||
|
if (err == PDEP_OK && dependencyParser.Finish() == PDEP_OK) {
|
||||||
|
cache.Dependencies = dependencyParser.Dependencies();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache_[name] = cache;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmPkgConfigParser::IsFragmentProperty(std::string const& lower)
|
||||||
|
{
|
||||||
|
return lower == "cflags" || lower == "cflags.private" ||
|
||||||
|
lower == "cflags.shared" || lower == "libs" || lower == "libs.private" ||
|
||||||
|
lower == "libs.shared";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmPkgConfigParser::IsDependencyProperty(std::string const& lower)
|
||||||
|
{
|
||||||
|
return lower == "conflicts" || lower == "provides" || lower == "requires" ||
|
||||||
|
lower == "requires.private" || lower == "requires.internal" ||
|
||||||
|
lower == "requires.shared";
|
||||||
}
|
}
|
||||||
|
|||||||
+213
-42
@@ -6,88 +6,259 @@
|
|||||||
#include "cmConfigure.h" // IWYU pragma: keep
|
#include "cmConfigure.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cm/string_view>
|
|
||||||
|
|
||||||
#include <cmllpkgc/llpkgc.h>
|
#include <cmllpkgc/llpkgc.h>
|
||||||
|
|
||||||
struct cmPkgConfigValueElement
|
struct cmPkgConfigValueItem
|
||||||
{
|
{
|
||||||
|
cmPkgConfigValueItem() = default;
|
||||||
|
cmPkgConfigValueItem(std::string text, bool isSubstitution);
|
||||||
|
|
||||||
cmPkgConfigValueElement() = default;
|
std::string Text;
|
||||||
|
bool IsSubstitution = false;
|
||||||
|
};
|
||||||
|
|
||||||
cmPkgConfigValueElement(bool isVariable, cm::string_view data);
|
enum class cmPkgConfigEntryKind
|
||||||
|
{
|
||||||
bool IsVariable;
|
Property,
|
||||||
cm::string_view Data;
|
Variable,
|
||||||
|
Barewords,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmPkgConfigEntry
|
struct cmPkgConfigEntry
|
||||||
{
|
{
|
||||||
|
|
||||||
cmPkgConfigEntry() = default;
|
cmPkgConfigEntry() = default;
|
||||||
|
cmPkgConfigEntry(std::vector<cmPkgConfigValueItem> value, std::string ident,
|
||||||
|
cmPkgConfigEntryKind kind);
|
||||||
|
|
||||||
cmPkgConfigEntry(bool isVariable, cm::string_view key);
|
std::vector<cmPkgConfigValueItem> Value;
|
||||||
|
std::string Ident;
|
||||||
bool IsVariable;
|
cmPkgConfigEntryKind Kind = cmPkgConfigEntryKind::Barewords;
|
||||||
cm::string_view Key;
|
|
||||||
std::vector<cmPkgConfigValueElement> Val;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class cmPkgConfigParser : llpkgc_t
|
class cmPkgConfigFileParser : private llpkgc_file_t
|
||||||
{
|
{
|
||||||
|
friend class cmPkgConfigParser;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cmPkgConfigParser();
|
cmPkgConfigFileParser();
|
||||||
|
cmPkgConfigFileParser(cmPkgConfigFileParser const& other);
|
||||||
|
cmPkgConfigFileParser(cmPkgConfigFileParser&& other) noexcept;
|
||||||
|
cmPkgConfigFileParser& operator=(cmPkgConfigFileParser const& other);
|
||||||
|
cmPkgConfigFileParser& operator=(cmPkgConfigFileParser&& other) noexcept;
|
||||||
|
|
||||||
llpkgc_errno_t Parse(char* buf, std::size_t len);
|
llpkgc_file_errno_t Parse(char const* input, std::size_t len);
|
||||||
|
llpkgc_file_errno_t Finish();
|
||||||
|
void Resume();
|
||||||
|
|
||||||
llpkgc_errno_t Finish();
|
llpkgc_file_errno_t GetErrno() const;
|
||||||
llpkgc_errno_t Finish(char* buf, std::size_t len);
|
char const* ErrorReason() const;
|
||||||
|
std::ptrdiff_t ErrorOffset(char const* base) const;
|
||||||
std::vector<cmPkgConfigEntry>& Data() { return Data_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ResetCallbacks();
|
||||||
|
|
||||||
|
int OnIdentNext(char const* at, std::size_t len);
|
||||||
|
static int OnIdentNextTr(llpkgc_file_t* parser, char const* at,
|
||||||
|
std::size_t len);
|
||||||
|
|
||||||
|
void AppendValue(std::string text, bool isSubstitution);
|
||||||
|
|
||||||
int OnSpanNext(char const*, std::size_t len);
|
int OnSpanNext(char const*, std::size_t len);
|
||||||
static int OnSpanNextTr(llpkgc_t* parser, char const* at, std::size_t len);
|
static int OnSpanNextTr(llpkgc_file_t* parser, char const* at,
|
||||||
|
std::size_t len);
|
||||||
|
|
||||||
int OnKey(char const* at, std::size_t len);
|
int OnIdent(char const* at, std::size_t len);
|
||||||
static int OnKeyTr(llpkgc_t* parser, char const* at, std::size_t len);
|
static int OnIdentTr(llpkgc_file_t* parser, char const* at, std::size_t len);
|
||||||
|
|
||||||
int OnKeywordComplete();
|
int OnPropertyComplete();
|
||||||
static int OnKeywordCompleteTr(llpkgc_t* parser);
|
static int OnPropertyCompleteTr(llpkgc_file_t* parser);
|
||||||
|
|
||||||
int OnVariableComplete();
|
int OnVariableComplete();
|
||||||
static int OnVariableCompleteTr(llpkgc_t* parser);
|
static int OnVariableCompleteTr(llpkgc_file_t* parser);
|
||||||
|
|
||||||
|
int OnBarewordsComplete();
|
||||||
|
static int OnBarewordsCompleteTr(llpkgc_file_t* parser);
|
||||||
|
|
||||||
int OnValueLiteral(char const* at, std::size_t len);
|
int OnValueLiteral(char const* at, std::size_t len);
|
||||||
static int OnValueLiteralTr(llpkgc_t* parser, char const* at,
|
static int OnValueLiteralTr(llpkgc_file_t* parser, char const* at,
|
||||||
std::size_t len);
|
std::size_t len);
|
||||||
|
|
||||||
int OnValueLiteralComplete();
|
int OnValueLiteralComplete();
|
||||||
static int OnValueLiteralCompleteTr(llpkgc_t* parser);
|
static int OnValueLiteralCompleteTr(llpkgc_file_t* parser);
|
||||||
|
|
||||||
int OnValueVariable(char const* at, std::size_t len);
|
int OnValueSubstitution(char const* at, std::size_t len);
|
||||||
static int OnValueVariableTr(llpkgc_t* parser, char const* at,
|
static int OnValueSubstitutionTr(llpkgc_file_t* parser, char const* at,
|
||||||
std::size_t len);
|
std::size_t len);
|
||||||
|
|
||||||
int OnValueVariableComplete();
|
int OnValueSubstitutionComplete();
|
||||||
static int OnValueVariableCompleteTr(llpkgc_t* parser);
|
static int OnValueSubstitutionCompleteTr(llpkgc_file_t* parser);
|
||||||
|
|
||||||
llpkgc_settings_t Settings_{
|
int OnValueComplete();
|
||||||
OnKeyTr,
|
static int OnValueCompleteTr(llpkgc_file_t* parser);
|
||||||
|
|
||||||
|
llpkgc_file_settings_t Settings_{
|
||||||
|
OnIdentTr,
|
||||||
OnValueLiteralTr,
|
OnValueLiteralTr,
|
||||||
OnValueVariableTr,
|
OnValueSubstitutionTr,
|
||||||
nullptr, // on_line_begin
|
nullptr, // on_line_begin
|
||||||
OnKeywordCompleteTr,
|
OnPropertyCompleteTr,
|
||||||
OnVariableCompleteTr,
|
OnVariableCompleteTr,
|
||||||
|
OnBarewordsCompleteTr,
|
||||||
OnValueLiteralCompleteTr,
|
OnValueLiteralCompleteTr,
|
||||||
OnValueVariableCompleteTr,
|
OnValueSubstitutionCompleteTr,
|
||||||
nullptr, // on_value_complete
|
OnValueCompleteTr,
|
||||||
nullptr, // on_pkgc_complete
|
nullptr, // on_pkgc_complete
|
||||||
};
|
};
|
||||||
|
|
||||||
char const* Ptr_;
|
char const* Ptr_ = nullptr;
|
||||||
std::size_t Len_;
|
std::size_t Len_ = 0;
|
||||||
|
std::string Ident_;
|
||||||
std::vector<cmPkgConfigEntry> Data_;
|
std::vector<cmPkgConfigEntry> Data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class cmPkgConfigFragmentParser : private llpkgc_frag_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmPkgConfigFragmentParser();
|
||||||
|
|
||||||
|
llpkgc_frag_errno_t Parse(char const* input, std::size_t len);
|
||||||
|
llpkgc_frag_errno_t Finish();
|
||||||
|
|
||||||
|
llpkgc_frag_errno_t GetErrno() const;
|
||||||
|
char const* ErrorReason() const;
|
||||||
|
|
||||||
|
std::vector<std::string> const& Fragments() const { return Fragments_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int OnFragmentText(char const* at, std::size_t len);
|
||||||
|
static int OnFragmentTextTr(llpkgc_frag_t* parser, char const* at,
|
||||||
|
std::size_t len);
|
||||||
|
|
||||||
|
int OnFragmentComplete();
|
||||||
|
static int OnFragmentCompleteTr(llpkgc_frag_t* parser);
|
||||||
|
|
||||||
|
llpkgc_frag_settings_t Settings_{
|
||||||
|
OnFragmentTextTr, OnFragmentCompleteTr,
|
||||||
|
nullptr, // on_fraglist_complete
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string CurrentFragment_;
|
||||||
|
std::vector<std::string> Fragments_;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class cmPkgConfigDependencyOperation
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
LessThan,
|
||||||
|
LessThanEqual,
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
GreaterThan,
|
||||||
|
GreaterThanEqual,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmPkgConfigDependencySpec
|
||||||
|
{
|
||||||
|
std::string Name;
|
||||||
|
cmPkgConfigDependencyOperation Operation =
|
||||||
|
cmPkgConfigDependencyOperation::None;
|
||||||
|
std::string Version;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cmPkgConfigDependencyParser : private llpkgc_dep_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmPkgConfigDependencyParser();
|
||||||
|
|
||||||
|
llpkgc_dep_errno_t Parse(char const* input, std::size_t len);
|
||||||
|
llpkgc_dep_errno_t Finish();
|
||||||
|
|
||||||
|
llpkgc_dep_errno_t GetErrno() const;
|
||||||
|
char const* ErrorReason() const;
|
||||||
|
|
||||||
|
std::vector<cmPkgConfigDependencySpec> const& Dependencies() const
|
||||||
|
{
|
||||||
|
return Dependencies_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int OnDependencyName(char const* at, std::size_t len);
|
||||||
|
static int OnDependencyNameTr(llpkgc_dep_t* parser, char const* at,
|
||||||
|
std::size_t len);
|
||||||
|
|
||||||
|
int OnDependencyOperator(char const* at, std::size_t len);
|
||||||
|
static int OnDependencyOperatorTr(llpkgc_dep_t* parser, char const* at,
|
||||||
|
std::size_t len);
|
||||||
|
|
||||||
|
int OnDependencyVersion(char const* at, std::size_t len);
|
||||||
|
static int OnDependencyVersionTr(llpkgc_dep_t* parser, char const* at,
|
||||||
|
std::size_t len);
|
||||||
|
|
||||||
|
int OnDependencyComplete();
|
||||||
|
static int OnDependencyCompleteTr(llpkgc_dep_t* parser);
|
||||||
|
|
||||||
|
llpkgc_dep_settings_t Settings_{
|
||||||
|
OnDependencyNameTr,
|
||||||
|
OnDependencyOperatorTr,
|
||||||
|
OnDependencyVersionTr,
|
||||||
|
OnDependencyCompleteTr,
|
||||||
|
nullptr, // on_dep_list_complete
|
||||||
|
};
|
||||||
|
|
||||||
|
cmPkgConfigDependencySpec Current_;
|
||||||
|
std::vector<cmPkgConfigDependencySpec> Dependencies_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmPkgConfigResolvedValue
|
||||||
|
{
|
||||||
|
std::vector<std::string> Fragments;
|
||||||
|
std::vector<cmPkgConfigDependencySpec> Dependencies;
|
||||||
|
std::string Literal;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cmPkgConfigParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmPkgConfigParser() = default;
|
||||||
|
|
||||||
|
llpkgc_file_errno_t Parse(char const* input, std::size_t len);
|
||||||
|
llpkgc_file_errno_t Finish();
|
||||||
|
llpkgc_file_errno_t Finish(char const* data, std::size_t len);
|
||||||
|
|
||||||
|
llpkgc_file_errno_t GetErrno() const;
|
||||||
|
char const* ErrorReason() const;
|
||||||
|
std::ptrdiff_t ErrorOffset(char const* base) const;
|
||||||
|
|
||||||
|
void SetVariable(std::string name, std::string value);
|
||||||
|
std::string GetVariable(std::string const& name);
|
||||||
|
bool HasProperty(std::string const& name) const;
|
||||||
|
std::vector<std::string> GetFragments(std::string const& name);
|
||||||
|
std::vector<cmPkgConfigDependencySpec> GetDependencies(
|
||||||
|
std::string const& name);
|
||||||
|
std::string GetLiteral(std::string const& name);
|
||||||
|
|
||||||
|
void ParseComplete();
|
||||||
|
|
||||||
|
private:
|
||||||
|
using ValueItems = std::vector<cmPkgConfigValueItem>;
|
||||||
|
|
||||||
|
std::string ResolveValue(ValueItems const& items);
|
||||||
|
std::string ResolveValueImpl(ValueItems const& items,
|
||||||
|
std::set<std::string> resolving);
|
||||||
|
|
||||||
|
bool ResolveAndParse(std::string const& name,
|
||||||
|
cmPkgConfigResolvedValue& cache);
|
||||||
|
|
||||||
|
static bool IsFragmentProperty(std::string const& lower);
|
||||||
|
static bool IsDependencyProperty(std::string const& lower);
|
||||||
|
|
||||||
|
cmPkgConfigFileParser File_;
|
||||||
|
std::unordered_map<std::string, ValueItems> StoredVariables_;
|
||||||
|
std::vector<cmPkgConfigEntry> StoredProperties_;
|
||||||
|
std::unordered_map<std::string, cmPkgConfigResolvedValue> Cache_;
|
||||||
|
};
|
||||||
|
|||||||
+253
-691
@@ -7,214 +7,307 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cm/optional>
|
#include <cm/optional>
|
||||||
#include <cm/string_view>
|
|
||||||
|
|
||||||
#include "cmsys/String.h"
|
#include "cmsys/String.h"
|
||||||
|
|
||||||
|
#include "cmOutputConverter.h"
|
||||||
#include "cmPkgConfigParser.h"
|
#include "cmPkgConfigParser.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void TrimBack(std::string& str)
|
bool HasPrefix(std::string const& value, char const* prefix)
|
||||||
{
|
{
|
||||||
if (!str.empty()) {
|
std::size_t const len = std::strlen(prefix);
|
||||||
auto it = str.end() - 1;
|
return value.size() >= len && value.compare(0, len, prefix) == 0;
|
||||||
for (; cmsysString_isspace(*it); --it) {
|
|
||||||
if (it == str.begin()) {
|
|
||||||
str.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
str.erase(++it, str.end());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AppendAndTrim(std::string& str, cm::string_view sv)
|
void AppendFlag(std::string& flagline, std::string const& flag)
|
||||||
{
|
{
|
||||||
auto size = str.length();
|
if (!flagline.empty()) {
|
||||||
str += sv;
|
flagline += ' ';
|
||||||
if (str.empty()) {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
flagline += flag;
|
||||||
auto begin = str.begin() + size;
|
|
||||||
auto cur = str.end() - 1;
|
|
||||||
|
|
||||||
while (cur != begin && cmsysString_isspace(*cur)) {
|
|
||||||
--cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmsysString_isspace(*cur)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return { &*begin, static_cast<std::size_t>(cur - begin) + 1 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cm::string_view TrimFlag(cm::string_view flag)
|
bool IsSystemPath(std::string const& path,
|
||||||
|
std::vector<std::string> const& systemPaths)
|
||||||
{
|
{
|
||||||
std::size_t trim_size = 2;
|
return std::find(systemPaths.begin(), systemPaths.end(), path) !=
|
||||||
for (auto c = flag.rbegin(); c != flag.rend() && cmsysString_isspace(*c);
|
systemPaths.end();
|
||||||
++c) {
|
}
|
||||||
++trim_size;
|
|
||||||
|
std::vector<std::string> DefaultSystemIncludePaths()
|
||||||
|
{
|
||||||
|
return std::vector<std::string>{ "/usr/include" };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> DefaultSystemLibraryPaths()
|
||||||
|
{
|
||||||
|
return std::vector<std::string>{ "/usr/lib" };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> const& SystemCflags(cmPkgConfigEnv const& env,
|
||||||
|
std::vector<std::string>& def)
|
||||||
|
{
|
||||||
|
if (env.SysCflags) {
|
||||||
|
return *env.SysCflags;
|
||||||
}
|
}
|
||||||
return { flag.data() + 2, flag.size() - trim_size };
|
def = DefaultSystemIncludePaths();
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> const& SystemLibs(cmPkgConfigEnv const& env,
|
||||||
|
std::vector<std::string>& def)
|
||||||
|
{
|
||||||
|
if (env.SysLibs) {
|
||||||
|
return *env.SysLibs;
|
||||||
|
}
|
||||||
|
def = DefaultSystemLibraryPaths();
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::string cmPkgConfigVersionReq::string() const
|
std::string cmPkgConfigResolver::VersionReqString(
|
||||||
|
cmPkgConfigDependencySpec const& spec)
|
||||||
{
|
{
|
||||||
switch (Operation) {
|
switch (spec.Operation) {
|
||||||
case ANY:
|
case cmPkgConfigDependencyOperation::None:
|
||||||
return "";
|
return "";
|
||||||
case LT:
|
case cmPkgConfigDependencyOperation::LessThan:
|
||||||
return cmStrCat('<', Version);
|
return cmStrCat('<', spec.Version);
|
||||||
case LT_EQ:
|
case cmPkgConfigDependencyOperation::LessThanEqual:
|
||||||
return cmStrCat("<=", Version);
|
return cmStrCat("<=", spec.Version);
|
||||||
case EQ:
|
case cmPkgConfigDependencyOperation::Equal:
|
||||||
return cmStrCat('=', Version);
|
return cmStrCat('=', spec.Version);
|
||||||
case NEQ:
|
case cmPkgConfigDependencyOperation::NotEqual:
|
||||||
return cmStrCat("!=", Version);
|
return cmStrCat("!=", spec.Version);
|
||||||
case GT_EQ:
|
case cmPkgConfigDependencyOperation::GreaterThanEqual:
|
||||||
return cmStrCat(">=", Version);
|
return cmStrCat(">=", spec.Version);
|
||||||
case GT:
|
case cmPkgConfigDependencyOperation::GreaterThan:
|
||||||
return cmStrCat('>', Version);
|
return cmStrCat('>', spec.Version);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cmPkgConfigResult::StrOrDefault(std::string const& key,
|
cmPkgConfigResolver::cmPkgConfigResolver(cmPkgConfigParser parser,
|
||||||
cm::string_view def)
|
cmPkgConfigEnv const& env,
|
||||||
|
std::string const& pcFileDir)
|
||||||
|
: Parser{ std::move(parser) }
|
||||||
|
, Env{ &env }
|
||||||
{
|
{
|
||||||
auto it = Keywords.find(key);
|
this->Parser.ParseComplete();
|
||||||
return it == Keywords.end() ? std::string{ def } : it->second;
|
this->ConfigureParser(pcFileDir);
|
||||||
};
|
|
||||||
|
|
||||||
std::string cmPkgConfigResult::Name()
|
|
||||||
{
|
|
||||||
return StrOrDefault("Name");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cmPkgConfigResult::Description()
|
cm::optional<cmPkgConfigResolver> cmPkgConfigResolver::Resolve(
|
||||||
|
cmPkgConfigParser parser, cmPkgConfigEnv const& env, Strictness strictness,
|
||||||
|
std::string const& pcFileDir)
|
||||||
{
|
{
|
||||||
return StrOrDefault("Description");
|
cmPkgConfigResolver resolver{ std::move(parser), env, pcFileDir };
|
||||||
}
|
if (strictness != Strictness::BestEffort && !resolver.HasRequiredFields()) {
|
||||||
|
|
||||||
std::string cmPkgConfigResult::Version()
|
|
||||||
{
|
|
||||||
return StrOrDefault("Version");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Conflicts()
|
|
||||||
{
|
|
||||||
auto it = Keywords.find("Conflicts");
|
|
||||||
if (it == Keywords.end()) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
if (strictness == Strictness::Strict && resolver.HasStrictConflicts()) {
|
||||||
return cmPkgConfigResolver::ParseDependencies(it->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Provides()
|
|
||||||
{
|
|
||||||
auto it = Keywords.find("Provides");
|
|
||||||
if (it == Keywords.end()) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
return resolver;
|
||||||
return cmPkgConfigResolver::ParseDependencies(it->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Requires(bool priv)
|
cm::optional<cmPkgConfigResolver> cmPkgConfigResolver::ResolveStrict(
|
||||||
|
cmPkgConfigParser parser, cmPkgConfigEnv const& env,
|
||||||
|
std::string const& pcFileDir)
|
||||||
{
|
{
|
||||||
auto it = Keywords.find(priv ? "Requires.private" : "Requires");
|
return Resolve(std::move(parser), env, Strictness::Strict, pcFileDir);
|
||||||
if (it == Keywords.end()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmPkgConfigResolver::ParseDependencies(it->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPkgConfigCflagsResult cmPkgConfigResult::Cflags(bool priv)
|
cm::optional<cmPkgConfigResolver> cmPkgConfigResolver::ResolvePermissive(
|
||||||
|
cmPkgConfigParser parser, cmPkgConfigEnv const& env,
|
||||||
|
std::string const& pcFileDir)
|
||||||
{
|
{
|
||||||
std::string cflags;
|
return Resolve(std::move(parser), env, Strictness::Permissive, pcFileDir);
|
||||||
auto it = Keywords.find(priv ? "Cflags.private" : "Cflags");
|
|
||||||
if (it != Keywords.end()) {
|
|
||||||
cflags += it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
it = Keywords.find(priv ? "CFlags.private" : "CFlags");
|
|
||||||
if (it != Keywords.end()) {
|
|
||||||
if (!cflags.empty()) {
|
|
||||||
cflags += " ";
|
|
||||||
}
|
|
||||||
cflags += it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tokens = cmPkgConfigResolver::TokenizeFlags(cflags);
|
|
||||||
|
|
||||||
if (env->AllowSysCflags) {
|
|
||||||
if (env->SysrootDir) {
|
|
||||||
return cmPkgConfigResolver::MangleCflags(tokens, *env->SysrootDir);
|
|
||||||
}
|
|
||||||
return cmPkgConfigResolver::MangleCflags(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env->SysCflags) {
|
|
||||||
if (env->SysrootDir) {
|
|
||||||
return cmPkgConfigResolver::MangleCflags(tokens, *env->SysrootDir,
|
|
||||||
*env->SysCflags);
|
|
||||||
}
|
|
||||||
return cmPkgConfigResolver::MangleCflags(tokens, *env->SysCflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env->SysrootDir) {
|
|
||||||
return cmPkgConfigResolver::MangleCflags(
|
|
||||||
tokens, *env->SysrootDir, std::vector<std::string>{ "/usr/include" });
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmPkgConfigResolver::MangleCflags(
|
|
||||||
tokens, std::vector<std::string>{ "/usr/include" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPkgConfigLibsResult cmPkgConfigResult::Libs(bool priv)
|
cmPkgConfigResolver cmPkgConfigResolver::ResolveBestEffort(
|
||||||
|
cmPkgConfigParser parser, cmPkgConfigEnv const& env,
|
||||||
|
std::string const& pcFileDir)
|
||||||
{
|
{
|
||||||
auto it = Keywords.find(priv ? "Libs.private" : "Libs");
|
return cmPkgConfigResolver{ std::move(parser), env, pcFileDir };
|
||||||
if (it == Keywords.end()) {
|
}
|
||||||
return cmPkgConfigLibsResult();
|
|
||||||
|
void cmPkgConfigResolver::ConfigureParser(std::string const& pcFileDir)
|
||||||
|
{
|
||||||
|
if (this->Env->SysrootDir) {
|
||||||
|
this->Parser.SetVariable(
|
||||||
|
"pc_sysrootdir",
|
||||||
|
cmOutputConverter::EscapeForShell(*this->Env->SysrootDir,
|
||||||
|
cmOutputConverter::Shell_Flag_IsUnix));
|
||||||
|
} else {
|
||||||
|
this->Parser.SetVariable("pc_sysrootdir", "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tokens = cmPkgConfigResolver::TokenizeFlags(it->second);
|
if (this->Env->TopBuildDir) {
|
||||||
|
this->Parser.SetVariable(
|
||||||
|
"pc_top_builddir",
|
||||||
|
cmOutputConverter::EscapeForShell(*this->Env->TopBuildDir,
|
||||||
|
cmOutputConverter::Shell_Flag_IsUnix));
|
||||||
|
}
|
||||||
|
|
||||||
if (env->AllowSysLibs) {
|
this->Parser.SetVariable("pcfiledir",
|
||||||
if (env->SysrootDir) {
|
cmOutputConverter::EscapeForShell(
|
||||||
return cmPkgConfigResolver::MangleLibs(tokens, *env->SysrootDir);
|
pcFileDir, cmOutputConverter::Shell_Flag_IsUnix));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmPkgConfigResolver::HasRequiredFields() const
|
||||||
|
{
|
||||||
|
return this->Parser.HasProperty("Name") &&
|
||||||
|
this->Parser.HasProperty("Description") &&
|
||||||
|
this->Parser.HasProperty("Version");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmPkgConfigResolver::HasStrictConflicts() const
|
||||||
|
{
|
||||||
|
return (this->Parser.HasProperty("Cflags") &&
|
||||||
|
this->Parser.HasProperty("CFlags")) ||
|
||||||
|
(this->Parser.HasProperty("Cflags.private") &&
|
||||||
|
this->Parser.HasProperty("CFlags.private"));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigResolver::Literal(std::string const& key) const
|
||||||
|
{
|
||||||
|
return this->Parser.GetLiteral(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigResolver::Name() const
|
||||||
|
{
|
||||||
|
return this->Literal("Name");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigResolver::Description() const
|
||||||
|
{
|
||||||
|
return this->Literal("Description");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigResolver::Version() const
|
||||||
|
{
|
||||||
|
return this->Literal("Version");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> cmPkgConfigResolver::Fragments(
|
||||||
|
std::string const& key) const
|
||||||
|
{
|
||||||
|
return this->Parser.GetFragments(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cmPkgConfigDependencySpec> cmPkgConfigResolver::Dependencies(
|
||||||
|
std::string const& key) const
|
||||||
|
{
|
||||||
|
return this->Parser.GetDependencies(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cmPkgConfigDependencySpec> cmPkgConfigResolver::Conflicts() const
|
||||||
|
{
|
||||||
|
return this->Dependencies("Conflicts");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cmPkgConfigDependencySpec> cmPkgConfigResolver::Provides() const
|
||||||
|
{
|
||||||
|
return this->Dependencies("Provides");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cmPkgConfigDependencySpec> cmPkgConfigResolver::Requires(
|
||||||
|
bool priv) const
|
||||||
|
{
|
||||||
|
return this->Dependencies(priv ? "Requires.private" : "Requires");
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigCflagsResult cmPkgConfigResolver::Cflags(bool priv) const
|
||||||
|
{
|
||||||
|
auto flags = this->Fragments(priv ? "Cflags.private" : "Cflags");
|
||||||
|
auto alt = this->Fragments(priv ? "CFlags.private" : "CFlags");
|
||||||
|
flags.insert(flags.end(), alt.begin(), alt.end());
|
||||||
|
return MangleCflags(flags, *this->Env);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigLibsResult cmPkgConfigResolver::Libs(bool priv) const
|
||||||
|
{
|
||||||
|
return MangleLibs(this->Fragments(priv ? "Libs.private" : "Libs"),
|
||||||
|
*this->Env);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
||||||
|
std::vector<std::string> const& flags, cmPkgConfigEnv const& env)
|
||||||
|
{
|
||||||
|
cmPkgConfigCflagsResult result;
|
||||||
|
std::vector<std::string> defaultSystemPaths;
|
||||||
|
auto const& systemPaths = SystemCflags(env, defaultSystemPaths);
|
||||||
|
|
||||||
|
for (auto const& flag : flags) {
|
||||||
|
std::string mangled = flag;
|
||||||
|
if (HasPrefix(flag, "-I") && env.SysrootDir) {
|
||||||
|
mangled = Reroot(flag, "-I", *env.SysrootDir);
|
||||||
}
|
}
|
||||||
return cmPkgConfigResolver::MangleLibs(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env->SysLibs) {
|
if (HasPrefix(mangled, "-I")) {
|
||||||
if (env->SysrootDir) {
|
if (!env.AllowSysCflags &&
|
||||||
return cmPkgConfigResolver::MangleLibs(tokens, *env->SysrootDir,
|
IsSystemPath(mangled.substr(2), systemPaths)) {
|
||||||
*env->SysLibs);
|
continue;
|
||||||
|
}
|
||||||
|
AppendFlag(result.Flagline, mangled);
|
||||||
|
result.Includes.push_back(mangled);
|
||||||
|
} else {
|
||||||
|
AppendFlag(result.Flagline, mangled);
|
||||||
|
result.CompileOptions.push_back(mangled);
|
||||||
}
|
}
|
||||||
return cmPkgConfigResolver::MangleLibs(tokens, *env->SysLibs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env->SysrootDir) {
|
return result;
|
||||||
return cmPkgConfigResolver::MangleLibs(
|
}
|
||||||
tokens, *env->SysrootDir, std::vector<std::string>{ "/usr/lib" });
|
|
||||||
|
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
||||||
|
std::vector<std::string> const& flags, cmPkgConfigEnv const& env)
|
||||||
|
{
|
||||||
|
cmPkgConfigLibsResult result;
|
||||||
|
std::vector<std::string> defaultSystemPaths;
|
||||||
|
auto const& systemPaths = SystemLibs(env, defaultSystemPaths);
|
||||||
|
|
||||||
|
for (auto const& flag : flags) {
|
||||||
|
std::string mangled = flag;
|
||||||
|
if (HasPrefix(flag, "-L") && env.SysrootDir) {
|
||||||
|
mangled = Reroot(flag, "-L", *env.SysrootDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasPrefix(mangled, "-L")) {
|
||||||
|
if (!env.AllowSysLibs && IsSystemPath(mangled.substr(2), systemPaths)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AppendFlag(result.Flagline, mangled);
|
||||||
|
result.LibDirs.push_back(mangled);
|
||||||
|
} else if (HasPrefix(mangled, "-l")) {
|
||||||
|
AppendFlag(result.Flagline, mangled);
|
||||||
|
result.LibNames.push_back(mangled);
|
||||||
|
} else {
|
||||||
|
AppendFlag(result.Flagline, mangled);
|
||||||
|
result.LinkOptions.push_back(mangled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmPkgConfigResolver::MangleLibs(
|
return result;
|
||||||
tokens, std::vector<std::string>{ "/usr/lib" });
|
}
|
||||||
|
|
||||||
|
std::string cmPkgConfigResolver::Reroot(std::string const& flag,
|
||||||
|
char const* prefix,
|
||||||
|
std::string const& sysroot)
|
||||||
|
{
|
||||||
|
std::string result = prefix;
|
||||||
|
result += sysroot;
|
||||||
|
result += flag.substr(std::strlen(prefix));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmPkgConfigResolver::ReplaceSep(std::string& list)
|
void cmPkgConfigResolver::ReplaceSep(std::string& list)
|
||||||
@@ -222,538 +315,30 @@ void cmPkgConfigResolver::ReplaceSep(std::string& list)
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
std::replace(list.begin(), list.end(), ':', ';');
|
std::replace(list.begin(), list.end(), ':', ';');
|
||||||
#else
|
#else
|
||||||
static_cast<void>(list); // Unused parameter
|
static_cast<void>(list);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
cm::optional<cmPkgConfigResult> cmPkgConfigResolver::ResolveStrict(
|
bool cmPkgConfigResolver::CheckVersion(
|
||||||
std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv& env)
|
cmPkgConfigDependencySpec const& desired, std::string const& provided)
|
||||||
{
|
{
|
||||||
cm::optional<cmPkgConfigResult> result;
|
if (desired.Operation == cmPkgConfigDependencyOperation::None) {
|
||||||
cmPkgConfigResult config;
|
|
||||||
auto& keys = config.Keywords;
|
|
||||||
|
|
||||||
if (env.SysrootDir) {
|
|
||||||
config.Variables["pc_sysrootdir"] = *env.SysrootDir;
|
|
||||||
} else {
|
|
||||||
config.Variables["pc_sysrootdir"] = "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.TopBuildDir) {
|
|
||||||
config.Variables["pc_top_builddir"] = *env.TopBuildDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.env = &env;
|
|
||||||
|
|
||||||
for (auto const& entry : entries) {
|
|
||||||
std::string key(entry.Key);
|
|
||||||
if (entry.IsVariable) {
|
|
||||||
if (config.Variables.find(key) != config.Variables.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
auto var = HandleVariableStrict(entry, config.Variables);
|
|
||||||
if (!var) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
config.Variables[key] = *var;
|
|
||||||
} else {
|
|
||||||
if (key == "Cflags" && keys.find("CFlags") != keys.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (key == "CFlags" && keys.find("Cflags") != keys.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (key == "Cflags.private" &&
|
|
||||||
keys.find("CFlags.private") != keys.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (key == "CFlags.private" &&
|
|
||||||
keys.find("Cflags.private") != keys.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (keys.find(key) != keys.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
keys[key] = HandleKeyword(entry, config.Variables);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keys.find("Name") == keys.end() ||
|
|
||||||
keys.find("Description") == keys.end() ||
|
|
||||||
keys.find("Version") == keys.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = std::move(config);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cm::optional<cmPkgConfigResult> cmPkgConfigResolver::ResolvePermissive(
|
|
||||||
std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv& env)
|
|
||||||
{
|
|
||||||
cm::optional<cmPkgConfigResult> result;
|
|
||||||
|
|
||||||
cmPkgConfigResult config = ResolveBestEffort(entries, env);
|
|
||||||
auto const& keys = config.Keywords;
|
|
||||||
|
|
||||||
if (keys.find("Name") == keys.end() ||
|
|
||||||
keys.find("Description") == keys.end() ||
|
|
||||||
keys.find("Version") == keys.end()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = std::move(config);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigResult cmPkgConfigResolver::ResolveBestEffort(
|
|
||||||
std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv& env)
|
|
||||||
{
|
|
||||||
cmPkgConfigResult result;
|
|
||||||
|
|
||||||
if (env.SysrootDir) {
|
|
||||||
result.Variables["pc_sysrootdir"] = *env.SysrootDir;
|
|
||||||
} else {
|
|
||||||
result.Variables["pc_sysrootdir"] = "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.TopBuildDir) {
|
|
||||||
result.Variables["pc_top_builddir"] = *env.TopBuildDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.env = &env;
|
|
||||||
|
|
||||||
for (auto const& entry : entries) {
|
|
||||||
std::string key(entry.Key);
|
|
||||||
if (entry.IsVariable) {
|
|
||||||
result.Variables[key] =
|
|
||||||
HandleVariablePermissive(entry, result.Variables);
|
|
||||||
} else {
|
|
||||||
result.Keywords[key] += HandleKeyword(entry, result.Variables);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string cmPkgConfigResolver::HandleVariablePermissive(
|
|
||||||
cmPkgConfigEntry const& entry,
|
|
||||||
std::unordered_map<std::string, std::string> const& variables)
|
|
||||||
{
|
|
||||||
std::string result;
|
|
||||||
for (auto const& segment : entry.Val) {
|
|
||||||
if (!segment.IsVariable) {
|
|
||||||
result += segment.Data;
|
|
||||||
} else if (entry.Key != segment.Data) {
|
|
||||||
auto it = variables.find(std::string{ segment.Data });
|
|
||||||
if (it != variables.end()) {
|
|
||||||
result += it->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TrimBack(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cm::optional<std::string> cmPkgConfigResolver::HandleVariableStrict(
|
|
||||||
cmPkgConfigEntry const& entry,
|
|
||||||
std::unordered_map<std::string, std::string> const& variables)
|
|
||||||
{
|
|
||||||
cm::optional<std::string> result;
|
|
||||||
|
|
||||||
std::string value;
|
|
||||||
for (auto const& segment : entry.Val) {
|
|
||||||
if (!segment.IsVariable) {
|
|
||||||
value += segment.Data;
|
|
||||||
} else if (entry.Key == segment.Data) {
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
auto it = variables.find(std::string{ segment.Data });
|
|
||||||
if (it != variables.end()) {
|
|
||||||
value += it->second;
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TrimBack(value);
|
|
||||||
result = std::move(value);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string cmPkgConfigResolver::HandleKeyword(
|
|
||||||
cmPkgConfigEntry const& entry,
|
|
||||||
std::unordered_map<std::string, std::string> const& variables)
|
|
||||||
{
|
|
||||||
std::string result;
|
|
||||||
for (auto const& segment : entry.Val) {
|
|
||||||
if (!segment.IsVariable) {
|
|
||||||
result += segment.Data;
|
|
||||||
} else {
|
|
||||||
auto it = variables.find(std::string{ segment.Data });
|
|
||||||
if (it != variables.end()) {
|
|
||||||
result += it->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TrimBack(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<cm::string_view> cmPkgConfigResolver::TokenizeFlags(
|
|
||||||
std::string const& flagline)
|
|
||||||
{
|
|
||||||
std::vector<cm::string_view> result;
|
|
||||||
|
|
||||||
auto it = flagline.begin();
|
|
||||||
while (it != flagline.end() && cmsysString_isspace(*it)) {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (it != flagline.end()) {
|
|
||||||
char const* start = &(*it);
|
|
||||||
std::size_t len = 0;
|
|
||||||
|
|
||||||
for (; it != flagline.end() && !cmsysString_isspace(*it); ++it) {
|
|
||||||
++len;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; it != flagline.end() && cmsysString_isspace(*it); ++it) {
|
|
||||||
++len;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.emplace_back(start, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
|
||||||
std::vector<cm::string_view> const& flags)
|
|
||||||
{
|
|
||||||
cmPkgConfigCflagsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-I", 0) == 0) {
|
|
||||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
} else {
|
|
||||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot)
|
|
||||||
{
|
|
||||||
cmPkgConfigCflagsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-I", 0) == 0) {
|
|
||||||
std::string reroot = Reroot(flag, "-I", sysroot);
|
|
||||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
|
||||||
} else {
|
|
||||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
|
||||||
std::vector<cm::string_view> const& flags,
|
|
||||||
std::vector<std::string> const& syspaths)
|
|
||||||
{
|
|
||||||
cmPkgConfigCflagsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-I", 0) == 0) {
|
|
||||||
cm::string_view trimmed = TrimFlag(flag);
|
|
||||||
if (std::all_of(
|
|
||||||
syspaths.begin(), syspaths.end(),
|
|
||||||
[&](std::string const& path) { return path != trimmed; })) {
|
|
||||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot,
|
|
||||||
std::vector<std::string> const& syspaths)
|
|
||||||
{
|
|
||||||
cmPkgConfigCflagsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-I", 0) == 0) {
|
|
||||||
std::string reroot = Reroot(flag, "-I", sysroot);
|
|
||||||
cm::string_view trimmed = TrimFlag(reroot);
|
|
||||||
if (std::all_of(
|
|
||||||
syspaths.begin(), syspaths.end(),
|
|
||||||
[&](std::string const& path) { return path != trimmed; })) {
|
|
||||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
|
||||||
std::vector<cm::string_view> const& flags)
|
|
||||||
{
|
|
||||||
cmPkgConfigLibsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-L", 0) == 0) {
|
|
||||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
} else if (flag.rfind("-l", 0) == 0) {
|
|
||||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
} else {
|
|
||||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot)
|
|
||||||
{
|
|
||||||
cmPkgConfigLibsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-L", 0) == 0) {
|
|
||||||
std::string reroot = Reroot(flag, "-L", sysroot);
|
|
||||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
|
||||||
} else if (flag.rfind("-l", 0) == 0) {
|
|
||||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
} else {
|
|
||||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
|
||||||
std::vector<cm::string_view> const& flags,
|
|
||||||
std::vector<std::string> const& syspaths)
|
|
||||||
{
|
|
||||||
cmPkgConfigLibsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-L", 0) == 0) {
|
|
||||||
cm::string_view trimmed = TrimFlag(flag);
|
|
||||||
if (std::all_of(
|
|
||||||
syspaths.begin(), syspaths.end(),
|
|
||||||
[&](std::string const& path) { return path != trimmed; })) {
|
|
||||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (flag.rfind("-l", 0) == 0) {
|
|
||||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
} else {
|
|
||||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot,
|
|
||||||
std::vector<std::string> const& syspaths)
|
|
||||||
{
|
|
||||||
cmPkgConfigLibsResult result;
|
|
||||||
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (flag.rfind("-L", 0) == 0) {
|
|
||||||
std::string reroot = Reroot(flag, "-L", sysroot);
|
|
||||||
cm::string_view trimmed = TrimFlag(reroot);
|
|
||||||
if (std::all_of(
|
|
||||||
syspaths.begin(), syspaths.end(),
|
|
||||||
[&](std::string const& path) { return path != trimmed; })) {
|
|
||||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (flag.rfind("-l", 0) == 0) {
|
|
||||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
} else {
|
|
||||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string cmPkgConfigResolver::Reroot(cm::string_view flag,
|
|
||||||
cm::string_view prefix,
|
|
||||||
std::string const& sysroot)
|
|
||||||
{
|
|
||||||
std::string result = std::string{ prefix };
|
|
||||||
result += sysroot;
|
|
||||||
result += cm::string_view{ flag.data() + prefix.length(),
|
|
||||||
flag.size() - prefix.length() };
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmPkgConfigVersionReq cmPkgConfigResolver::ParseVersion(
|
|
||||||
std::string::const_iterator& cur, std::string::const_iterator end)
|
|
||||||
{
|
|
||||||
cmPkgConfigVersionReq result;
|
|
||||||
if (*cur == '=') {
|
|
||||||
result.Operation = result.EQ;
|
|
||||||
++cur;
|
|
||||||
} else if (*cur == '>') {
|
|
||||||
++cur;
|
|
||||||
|
|
||||||
if (cur == end) {
|
|
||||||
result.Operation = result.GT;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*cur == '=') {
|
|
||||||
result.Operation = result.GT_EQ;
|
|
||||||
++cur;
|
|
||||||
} else {
|
|
||||||
result.Operation = result.GT;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (*cur == '<') {
|
|
||||||
++cur;
|
|
||||||
|
|
||||||
if (cur == end) {
|
|
||||||
result.Operation = result.LT;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*cur == '=') {
|
|
||||||
result.Operation = result.LT_EQ;
|
|
||||||
++cur;
|
|
||||||
} else {
|
|
||||||
result.Operation = result.LT;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (*cur == '!') {
|
|
||||||
++cur;
|
|
||||||
|
|
||||||
if (cur == end) {
|
|
||||||
result.Operation = result.ANY;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*cur == '=') {
|
|
||||||
result.Operation = result.NEQ;
|
|
||||||
++cur;
|
|
||||||
} else {
|
|
||||||
result.Operation = result.ANY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;; ++cur) {
|
|
||||||
if (cur == end) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cmsysString_isspace(*cur)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; cur != end && !cmsysString_isspace(*cur) && *cur != ','; ++cur) {
|
|
||||||
result.Version += *cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<cmPkgConfigDependency> cmPkgConfigResolver::ParseDependencies(
|
|
||||||
std::string const& deps)
|
|
||||||
{
|
|
||||||
|
|
||||||
std::vector<cmPkgConfigDependency> result;
|
|
||||||
|
|
||||||
auto cur = deps.begin();
|
|
||||||
auto end = deps.end();
|
|
||||||
|
|
||||||
while (cur != end) {
|
|
||||||
while ((cmsysString_isspace(*cur) || *cur == ',')) {
|
|
||||||
if (++cur == end) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.emplace_back();
|
|
||||||
auto& dep = result.back();
|
|
||||||
|
|
||||||
while (!cmsysString_isspace(*cur) && *cur != ',') {
|
|
||||||
dep.Name += *cur;
|
|
||||||
if (++cur == end) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto in_operator = [&]() -> bool {
|
|
||||||
for (;; ++cur) {
|
|
||||||
if (cur == end) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*cur == '>' || *cur == '=' || *cur == '<' || *cur == '!') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cmsysString_isspace(*cur)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!in_operator()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
dep.VerReq = ParseVersion(cur, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cmPkgConfigResolver::CheckVersion(cmPkgConfigVersionReq const& desired,
|
|
||||||
std::string const& provided)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (desired.Operation == cmPkgConfigVersionReq::ANY) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://blog.jasonantman.com/2014/07/how-yum-and-rpm-compare-versions/
|
|
||||||
|
|
||||||
auto check_with_op = [&](int comp) -> bool {
|
auto check_with_op = [&](int comp) -> bool {
|
||||||
switch (desired.Operation) {
|
switch (desired.Operation) {
|
||||||
case cmPkgConfigVersionReq::EQ:
|
case cmPkgConfigDependencyOperation::Equal:
|
||||||
return comp == 0;
|
return comp == 0;
|
||||||
case cmPkgConfigVersionReq::NEQ:
|
case cmPkgConfigDependencyOperation::NotEqual:
|
||||||
return comp != 0;
|
return comp != 0;
|
||||||
case cmPkgConfigVersionReq::GT:
|
case cmPkgConfigDependencyOperation::GreaterThan:
|
||||||
return comp < 0;
|
return comp < 0;
|
||||||
case cmPkgConfigVersionReq::GT_EQ:
|
case cmPkgConfigDependencyOperation::GreaterThanEqual:
|
||||||
return comp <= 0;
|
return comp <= 0;
|
||||||
case cmPkgConfigVersionReq::LT:
|
case cmPkgConfigDependencyOperation::LessThan:
|
||||||
return comp > 0;
|
return comp > 0;
|
||||||
case cmPkgConfigVersionReq::LT_EQ:
|
case cmPkgConfigDependencyOperation::LessThanEqual:
|
||||||
return comp >= 0;
|
return comp >= 0;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
@@ -870,26 +455,3 @@ bool cmPkgConfigResolver::CheckVersion(cmPkgConfigVersionReq const& desired,
|
|||||||
|
|
||||||
return check_with_op(1);
|
return check_with_op(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPkgConfigVersionReq cmPkgConfigResolver::ParseVersion(
|
|
||||||
std::string const& version)
|
|
||||||
{
|
|
||||||
cmPkgConfigVersionReq result;
|
|
||||||
|
|
||||||
auto cur = version.begin();
|
|
||||||
auto end = version.end();
|
|
||||||
|
|
||||||
if (cur == end) {
|
|
||||||
result.Operation = cmPkgConfigVersionReq::EQ;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = ParseVersion(cur, end);
|
|
||||||
cur = version.begin();
|
|
||||||
|
|
||||||
if (*cur != '=' && *cur != '!' && *cur != '<' && *cur != '>') {
|
|
||||||
result.Operation = cmPkgConfigVersionReq::EQ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
+50
-103
@@ -6,14 +6,11 @@
|
|||||||
#include "cmConfigure.h" // IWYU pragma: keep
|
#include "cmConfigure.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cm/optional>
|
#include <cm/optional>
|
||||||
#include <cm/string_view>
|
|
||||||
|
|
||||||
// From cmPkgConfigParser.h, IWYU doesn't like including the header
|
#include "cmPkgConfigParser.h"
|
||||||
struct cmPkgConfigEntry;
|
|
||||||
|
|
||||||
struct cmPkgConfigCflagsResult
|
struct cmPkgConfigCflagsResult
|
||||||
{
|
{
|
||||||
@@ -30,29 +27,6 @@ struct cmPkgConfigLibsResult
|
|||||||
std::vector<std::string> LinkOptions;
|
std::vector<std::string> LinkOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmPkgConfigVersionReq
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ANY = 0,
|
|
||||||
LT,
|
|
||||||
LT_EQ,
|
|
||||||
EQ,
|
|
||||||
NEQ,
|
|
||||||
GT_EQ,
|
|
||||||
GT,
|
|
||||||
} Operation = ANY;
|
|
||||||
std::string Version;
|
|
||||||
|
|
||||||
std::string string() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cmPkgConfigDependency
|
|
||||||
{
|
|
||||||
std::string Name;
|
|
||||||
cmPkgConfigVersionReq VerReq;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cmPkgConfigEnv
|
struct cmPkgConfigEnv
|
||||||
{
|
{
|
||||||
cm::optional<std::vector<std::string>> Path;
|
cm::optional<std::vector<std::string>> Path;
|
||||||
@@ -70,46 +44,51 @@ struct cmPkgConfigEnv
|
|||||||
bool AllowSysLibs = true;
|
bool AllowSysLibs = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class cmPkgConfigResult
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::unordered_map<std::string, std::string> Keywords;
|
|
||||||
std::unordered_map<std::string, std::string> Variables;
|
|
||||||
|
|
||||||
std::string Name();
|
|
||||||
std::string Description();
|
|
||||||
std::string Version();
|
|
||||||
|
|
||||||
std::vector<cmPkgConfigDependency> Conflicts();
|
|
||||||
std::vector<cmPkgConfigDependency> Provides();
|
|
||||||
std::vector<cmPkgConfigDependency> Requires(bool priv = false);
|
|
||||||
|
|
||||||
cmPkgConfigCflagsResult Cflags(bool priv = false);
|
|
||||||
cmPkgConfigLibsResult Libs(bool priv = false);
|
|
||||||
|
|
||||||
cmPkgConfigEnv* env;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string StrOrDefault(std::string const& key, cm::string_view def = "");
|
|
||||||
};
|
|
||||||
|
|
||||||
class cmPkgConfigResolver
|
class cmPkgConfigResolver
|
||||||
{
|
{
|
||||||
friend class cmPkgConfigResult;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static cm::optional<cmPkgConfigResult> ResolveStrict(
|
enum class Strictness
|
||||||
std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv& env);
|
{
|
||||||
|
Strict,
|
||||||
|
Permissive,
|
||||||
|
BestEffort,
|
||||||
|
};
|
||||||
|
|
||||||
static cm::optional<cmPkgConfigResult> ResolvePermissive(
|
cmPkgConfigResolver(cmPkgConfigParser parser, cmPkgConfigEnv const& env,
|
||||||
std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv& env);
|
std::string const& pcFileDir);
|
||||||
|
|
||||||
static cmPkgConfigResult ResolveBestEffort(
|
static cm::optional<cmPkgConfigResolver> Resolve(
|
||||||
std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv& env);
|
cmPkgConfigParser parser, cmPkgConfigEnv const& env, Strictness strictness,
|
||||||
|
std::string const& pcFileDir);
|
||||||
|
|
||||||
static cmPkgConfigVersionReq ParseVersion(std::string const& version);
|
static cm::optional<cmPkgConfigResolver> ResolveStrict(
|
||||||
|
cmPkgConfigParser parser, cmPkgConfigEnv const& env,
|
||||||
|
std::string const& pcFileDir);
|
||||||
|
|
||||||
static bool CheckVersion(cmPkgConfigVersionReq const& desired,
|
static cm::optional<cmPkgConfigResolver> ResolvePermissive(
|
||||||
|
cmPkgConfigParser parser, cmPkgConfigEnv const& env,
|
||||||
|
std::string const& pcFileDir);
|
||||||
|
|
||||||
|
static cmPkgConfigResolver ResolveBestEffort(cmPkgConfigParser parser,
|
||||||
|
cmPkgConfigEnv const& env,
|
||||||
|
std::string const& pcFileDir);
|
||||||
|
|
||||||
|
std::string Literal(std::string const& key) const;
|
||||||
|
|
||||||
|
std::string Name() const;
|
||||||
|
std::string Description() const;
|
||||||
|
std::string Version() const;
|
||||||
|
|
||||||
|
std::vector<cmPkgConfigDependencySpec> Conflicts() const;
|
||||||
|
std::vector<cmPkgConfigDependencySpec> Provides() const;
|
||||||
|
std::vector<cmPkgConfigDependencySpec> Requires(bool priv = false) const;
|
||||||
|
|
||||||
|
cmPkgConfigCflagsResult Cflags(bool priv = false) const;
|
||||||
|
cmPkgConfigLibsResult Libs(bool priv = false) const;
|
||||||
|
|
||||||
|
static std::string VersionReqString(cmPkgConfigDependencySpec const& spec);
|
||||||
|
|
||||||
|
static bool CheckVersion(cmPkgConfigDependencySpec const& desired,
|
||||||
std::string const& provided);
|
std::string const& provided);
|
||||||
|
|
||||||
static void ReplaceSep(std::string& list);
|
static void ReplaceSep(std::string& list);
|
||||||
@@ -121,55 +100,23 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string HandleVariablePermissive(
|
void ConfigureParser(std::string const& pcFileDir);
|
||||||
cmPkgConfigEntry const& entry,
|
bool HasRequiredFields() const;
|
||||||
std::unordered_map<std::string, std::string> const& variables);
|
bool HasStrictConflicts() const;
|
||||||
|
|
||||||
static cm::optional<std::string> HandleVariableStrict(
|
std::vector<std::string> Fragments(std::string const& key) const;
|
||||||
cmPkgConfigEntry const& entry,
|
std::vector<cmPkgConfigDependencySpec> Dependencies(
|
||||||
std::unordered_map<std::string, std::string> const& variables);
|
std::string const& key) const;
|
||||||
|
|
||||||
static std::string HandleKeyword(
|
|
||||||
cmPkgConfigEntry const& entry,
|
|
||||||
std::unordered_map<std::string, std::string> const& variables);
|
|
||||||
|
|
||||||
static std::vector<cm::string_view> TokenizeFlags(
|
|
||||||
std::string const& flagline);
|
|
||||||
|
|
||||||
static cmPkgConfigCflagsResult MangleCflags(
|
static cmPkgConfigCflagsResult MangleCflags(
|
||||||
std::vector<cm::string_view> const& flags);
|
std::vector<std::string> const& flags, cmPkgConfigEnv const& env);
|
||||||
|
|
||||||
static cmPkgConfigCflagsResult MangleCflags(
|
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot);
|
|
||||||
|
|
||||||
static cmPkgConfigCflagsResult MangleCflags(
|
|
||||||
std::vector<cm::string_view> const& flags,
|
|
||||||
std::vector<std::string> const& syspaths);
|
|
||||||
|
|
||||||
static cmPkgConfigCflagsResult MangleCflags(
|
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot,
|
|
||||||
std::vector<std::string> const& syspaths);
|
|
||||||
|
|
||||||
static cmPkgConfigLibsResult MangleLibs(
|
static cmPkgConfigLibsResult MangleLibs(
|
||||||
std::vector<cm::string_view> const& flags);
|
std::vector<std::string> const& flags, cmPkgConfigEnv const& env);
|
||||||
|
|
||||||
static cmPkgConfigLibsResult MangleLibs(
|
static std::string Reroot(std::string const& flag, char const* prefix,
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot);
|
|
||||||
|
|
||||||
static cmPkgConfigLibsResult MangleLibs(
|
|
||||||
std::vector<cm::string_view> const& flags,
|
|
||||||
std::vector<std::string> const& syspaths);
|
|
||||||
|
|
||||||
static cmPkgConfigLibsResult MangleLibs(
|
|
||||||
std::vector<cm::string_view> const& flags, std::string const& sysroot,
|
|
||||||
std::vector<std::string> const& syspaths);
|
|
||||||
|
|
||||||
static std::string Reroot(cm::string_view flag, cm::string_view prefix,
|
|
||||||
std::string const& sysroot);
|
std::string const& sysroot);
|
||||||
|
|
||||||
static cmPkgConfigVersionReq ParseVersion(std::string::const_iterator& cur,
|
mutable cmPkgConfigParser Parser;
|
||||||
std::string::const_iterator end);
|
cmPkgConfigEnv const* Env;
|
||||||
|
|
||||||
static std::vector<cmPkgConfigDependency> ParseDependencies(
|
|
||||||
std::string const& deps);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,16 +44,21 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
|||||||
result = parser.Finish();
|
result = parser.Finish();
|
||||||
(void)result;
|
(void)result;
|
||||||
|
|
||||||
// Access parsed data to exercise accessors
|
parser.ParseComplete();
|
||||||
auto& entries = parser.Data();
|
|
||||||
for (auto const& entry : entries) {
|
(void)parser.GetLiteral("Name");
|
||||||
(void)entry.IsVariable;
|
(void)parser.GetLiteral("Description");
|
||||||
(void)entry.Key;
|
(void)parser.GetLiteral("Version");
|
||||||
for (auto const& elem : entry.Val) {
|
(void)parser.GetFragments("Cflags");
|
||||||
(void)elem.IsVariable;
|
(void)parser.GetFragments("Cflags.private");
|
||||||
(void)elem.Data;
|
(void)parser.GetFragments("CFlags");
|
||||||
}
|
(void)parser.GetFragments("CFlags.private");
|
||||||
}
|
(void)parser.GetFragments("Libs");
|
||||||
|
(void)parser.GetFragments("Libs.private");
|
||||||
|
(void)parser.GetDependencies("Requires");
|
||||||
|
(void)parser.GetDependencies("Requires.private");
|
||||||
|
(void)parser.GetDependencies("Conflicts");
|
||||||
|
(void)parser.GetDependencies("Provides");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
cmake_pkg_config(
|
||||||
|
EXTRACT builtindirs
|
||||||
|
PC_SYSROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/Sys Root"
|
||||||
|
TOP_BUILD_DIR "${CMAKE_CURRENT_LIST_DIR}/Top Build"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(expected_dir "${CMAKE_CURRENT_LIST_DIR}/PackageRoot")
|
||||||
|
set(expected_sysroot "${CMAKE_CURRENT_LIST_DIR}/Sys Root")
|
||||||
|
set(expected_top_build "${CMAKE_CURRENT_LIST_DIR}/Top Build")
|
||||||
|
set(expected_options
|
||||||
|
"-DROOT=${expected_sysroot}/include"
|
||||||
|
"-DTOP=${expected_top_build}/generated"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT CMAKE_PKG_CONFIG_INCLUDES STREQUAL "-I${expected_sysroot}${expected_dir}/include")
|
||||||
|
message(FATAL_ERROR "Unexpected built-in directory include: ${CMAKE_PKG_CONFIG_INCLUDES}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_PKG_CONFIG_COMPILE_OPTIONS STREQUAL "${expected_options}")
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Unexpected built-in directory options: ${CMAKE_PKG_CONFIG_COMPILE_OPTIONS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_PKG_CONFIG_LIBDIRS STREQUAL "-L${expected_sysroot}${expected_dir}/lib")
|
||||||
|
message(FATAL_ERROR "Unexpected built-in directory libdir: ${CMAKE_PKG_CONFIG_LIBDIRS}")
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Name: BuiltinDirs
|
||||||
|
Description: Uses built-in directory variables
|
||||||
|
Version: 1.0.0
|
||||||
|
|
||||||
|
includedir=${pcfiledir}/include
|
||||||
|
libdir=${pcfiledir}/lib
|
||||||
|
|
||||||
|
Cflags: -I${includedir} -DROOT=${pc_sysrootdir}/include -DTOP=${pc_top_builddir}/generated
|
||||||
|
Libs: -L${libdir} -lbuiltindirs
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
Name: Invalid
|
Name: Invalid
|
||||||
Description: Will cause a parse error
|
Description: Will cause a parse error
|
||||||
Version: 1.0.0
|
Version: 1.0.0
|
||||||
BrokenKey
|
BrokenKey: ${unterminated
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ foreach(strictness IN ITEMS STRICT PERMISSIVE BEST_EFFORT)
|
|||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
run_cmake(ExtractBuiltinDirs)
|
||||||
run_cmake(ExtractEnv)
|
run_cmake(ExtractEnv)
|
||||||
run_cmake(ExtractFields)
|
run_cmake(ExtractFields)
|
||||||
run_cmake(ExtractMangle)
|
run_cmake(ExtractMangle)
|
||||||
|
|||||||
Reference in New Issue
Block a user