aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pkgconfig/pcparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pkgconfig/pcparser.cpp')
-rw-r--r--src/lib/pkgconfig/pcparser.cpp106
1 files changed, 61 insertions, 45 deletions
diff --git a/src/lib/pkgconfig/pcparser.cpp b/src/lib/pkgconfig/pcparser.cpp
index b314bc1bb..eb07aa5ef 100644
--- a/src/lib/pkgconfig/pcparser.cpp
+++ b/src/lib/pkgconfig/pcparser.cpp
@@ -62,8 +62,22 @@ namespace std {
namespace qbs {
+using Internal::completeBaseName;
+using Internal::parentPath;
+using Internal::startsWith;
+using Internal::endsWith;
+
namespace {
+// workaround for a missing ctor before c++20
+template<typename It>
+std::string_view makeStringView(It begin, It end)
+{
+ if (begin == end)
+ return {};
+ return std::string_view(&*begin, std::distance(begin, end));
+}
+
bool readOneLine(std::ifstream &file, std::string &line)
{
bool quoted = false;
@@ -133,7 +147,7 @@ std::string_view trimmed(std::string_view str)
const auto right = std::find_if_not(str.rbegin(), str.rend(), predicate).base();
if (right <= left)
return {};
- return std::string_view(&*left, std::distance(left, right));
+ return makeStringView(left, right);
}
// based on https://opensource.apple.com/source/distcc/distcc-31.0.81/popt/poptparse.c.auto.html
@@ -186,17 +200,6 @@ std::optional<std::vector<std::string>> splitCommand(std::string_view s)
return result;
}
-bool startsWith(std::string_view haystack, std::string_view needle)
-{
- return haystack.size() >= needle.size() && haystack.compare(0, needle.size(), needle) == 0;
-}
-
-bool endsWith(std::string_view haystack, std::string_view needle)
-{
- return haystack.size() >= needle.size()
- && haystack.compare(haystack.size() - needle.size(), needle.size(), needle) == 0;
-}
-
[[noreturn]] void raizeUnknownComparisonException(const PcPackage &pkg, std::string_view verName, std::string_view comp)
{
std::string message;
@@ -388,17 +391,6 @@ PcPackage::RequiredVersion::ComparisonType comparisonFromString(
raizeUnknownComparisonException(pkg, verName, comp);
}
-std::string baseName(const std::string_view &filePath)
-{
- auto pos = filePath.rfind('/');
- const auto fileName =
- pos == std::string_view::npos ? std::string_view() : filePath.substr(pos + 1);
- pos = fileName.rfind('.');
- return std::string(pos == std::string_view::npos
- ? std::string_view()
- : fileName.substr(0, pos));
-}
-
} // namespace
PcParser::PcParser(const PkgConfig &pkgConfig)
@@ -420,7 +412,7 @@ try
if (!file.is_open())
throw PcException(std::string("Can't open file ") + path);
- package.baseFileName = baseName(path);
+ package.baseFileName = std::string{completeBaseName(path)};
#if HAS_STD_FILESYSTEM
const auto fsPath = std::filesystem::path(path);
package.filePath = fsPath.generic_string();
@@ -436,7 +428,7 @@ try
parseLine(package, line);
return package;
} catch(const PcException &ex) {
- return PcBrokenPackage{path, baseName(path), ex.what()};
+ return PcBrokenPackage{path, std::string{completeBaseName(path)}, ex.what()};
}
std::string PcParser::trimAndSubstitute(const PcPackage &pkg, std::string_view str) const
@@ -466,10 +458,10 @@ std::string PcParser::trimAndSubstitute(const PcPackage &pkg, std::string_view s
const auto varval = m_pkgConfig.packageGetVariable(pkg, varname);
- if (varval.empty())
+ if (!varval)
raizeUndefinedVariableException(pkg, varname);
- result += varval;
+ result += *varval;
} else {
result += str.front();
str.remove_prefix(1);
@@ -479,6 +471,35 @@ std::string PcParser::trimAndSubstitute(const PcPackage &pkg, std::string_view s
return result;
}
+std::string PcParser::evaluateVariable(
+ PcPackage &pkg, std::string_view tag, std::string_view str) const
+{
+ static constexpr std::string_view prefixVariable = "prefix";
+ if (m_pkgConfig.options().definePrefix) {
+ if (tag == prefixVariable) {
+ std::string_view prefix = pkg.filePath;
+ prefix = parentPath(prefix);
+ if (completeBaseName(prefix) == "pkgconfig") {
+ prefix = parentPath(prefix);
+ prefix = parentPath(prefix);
+ }
+ pkg.oldPrefix = std::string(str);
+ if (!prefix.empty())
+ str = prefix;
+ return std::string(str);
+ } else if (pkg.oldPrefix
+ && str.size() > pkg.oldPrefix->size()
+ && str.substr(0, pkg.oldPrefix->size()) == *pkg.oldPrefix
+ && str[pkg.oldPrefix->size()] == '/') {
+ auto result = pkg.variables["prefix"];
+ result += str.substr(pkg.oldPrefix->size());
+ return trimAndSubstitute(pkg, result);
+ }
+ }
+
+ return trimAndSubstitute(pkg, str);
+}
+
void PcParser::parseStringField(
PcPackage &pkg,
std::string &field,
@@ -503,9 +524,11 @@ void PcParser::parseLibs(
raiseDuplicateFieldException(fieldName, pkg.filePath);
const auto trimmed = trimAndSubstitute(pkg, str);
+ if (trimmed.empty())
+ return;
const auto argv = splitCommand(trimmed);
- if (!trimmed.empty() && !argv)
+ if (!argv)
throw PcException("Couldn't parse Libs field into an argument vector");
libs = doParseLibs(*argv);
@@ -572,9 +595,11 @@ void PcParser::parseCFlags(PcPackage &pkg, std::string_view str)
raiseDuplicateFieldException("Cflags", pkg.filePath);
const auto command = trimAndSubstitute(pkg, str);
+ if (command.empty())
+ return;
const auto argv = splitCommand(command);
- if (!command.empty() && !argv)
+ if (!argv)
throw PcException("Couldn't parse Cflags field into an argument vector");
std::vector<PcPackage::Flag> cflags;
@@ -633,10 +658,10 @@ std::vector<PcPackage::RequiredVersion> PcParser::parseModuleList(PcPackage &pkg
auto start = p;
- while (*p && !std::isspace(*p))
+ while (p != end && !std::isspace(*p))
++p;
- const auto name = std::string_view(&*start, std::distance(start, p));
+ const auto name = makeStringView(start, p);
if (name.empty())
raizeEmptyPackageNameException(pkg);
@@ -651,7 +676,7 @@ std::vector<PcPackage::RequiredVersion> PcParser::parseModuleList(PcPackage &pkg
while (p != end && !std::isspace(*p))
++p;
- const auto comp = std::string_view(&*start, std::distance(start, p));
+ const auto comp = makeStringView(start, p);
ver.comparison = comparisonFromString(pkg, ver.name, comp);
while (p != end && std::isspace(*p))
@@ -662,7 +687,7 @@ std::vector<PcPackage::RequiredVersion> PcParser::parseModuleList(PcPackage &pkg
while (p != end && !std::isspace(*p))
++p;
- const auto version = std::string_view(&*start, std::distance(start, p));
+ const auto version = makeStringView(start, p);
while (p != end && std::isspace(*p))
++p;
@@ -701,10 +726,8 @@ void PcParser::parseLine(PcPackage &pkg, std::string_view str)
size_t pos = 0;
for (; pos < s.size(); ++pos) {
auto p = s.data() + pos;
- if (!((*p >= 'A' && *p <= 'Z') ||
- (*p >= 'a' && *p <= 'z') ||
- (*p >= '0' && *p <= '9') ||
- *p == '_' || *p == '.')) {
+ if ((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z') && (*p < '0' || *p > '9')
+ && *p != '_' && *p != '.') {
break;
}
}
@@ -756,14 +779,7 @@ void PcParser::parseLine(PcPackage &pkg, std::string_view str)
str.remove_prefix(1); // cut '='
str = trimmed(str);
- // TODO: support guesstimating of the prefix variable (pkg-config's --define-prefix option)
- // from doc: "try to override the value of prefix for each .pc file found with a
- // guesstimated value based on the location of the .pc file"
- // https://gitlab.freedesktop.org/pkg-config/pkg-config/-/blob/pkg-config-0.29.2/parse.c#L998
- // This option is disabled by default, and Qbs doesn't allow to override it yet, so we can
- // ignore this feature for now
-
- const auto value = trimAndSubstitute(pkg, str);
+ const auto value = evaluateVariable(pkg, tag, str);
if (!pkg.variables.insert({std::string(tag), value}).second)
raizeDuplicateVariableException(pkg, tag);
}