diff options
Diffstat (limited to 'src/lib/pkgconfig/pcparser.cpp')
-rw-r--r-- | src/lib/pkgconfig/pcparser.cpp | 106 |
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); } |