aboutsummaryrefslogtreecommitdiffstats
path: root/share
diff options
context:
space:
mode:
authorIvan Komissarov <abbapoh@gmail.com>2021-05-14 00:55:15 +0200
committerIvan Komissarov <ABBAPOH@gmail.com>2021-10-14 10:03:50 +0000
commit3187199a17e013882b0d0ea7aff9c7b9411e4cd1 (patch)
tree5e82271f0702e037898c723bcdaf6ab426eba342 /share
parente7cc3a2cf13db0f786727ce2469f7c66324f35a2 (diff)
Implement eager pkg-config provider
This implements provider that generates modules based on all .pc files present in system. This allows to get rid of the multi-shot providers such as fallback provider. Fixes: QBS-1614 Change-Id: Icf87ac609bc34bd26e8ed94ae547a7e649835a3a Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'share')
-rw-r--r--share/qbs/module-providers/qbspkgconfig.qbs216
-rw-r--r--share/share.qbs2
2 files changed, 217 insertions, 1 deletions
diff --git a/share/qbs/module-providers/qbspkgconfig.qbs b/share/qbs/module-providers/qbspkgconfig.qbs
new file mode 100644
index 000000000..ad6d64027
--- /dev/null
+++ b/share/qbs/module-providers/qbspkgconfig.qbs
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import qbs.Environment
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.PkgConfig
+import qbs.Process
+import qbs.TextFile
+
+ModuleProvider {
+ property string executableFilePath
+ property stringList libDirs
+ property bool staticMode: false
+ property path sysroot: {
+ if (qbs.targetOS.contains("macos"))
+ return "";
+ return qbs.sysroot;
+ }
+
+ relativeSearchPaths: {
+
+ // we need Probes in Providers...
+ function getPkgConfigExecutable(qbs) {
+ function splitNonEmpty(s, c) { return s.split(c).filter(function(e) { return e; }) }
+ function exeSuffix(qbs) { return qbs.hostOS.contains("windows") ? ".exe" : ""; }
+
+ var pathValue = Environment.getEnv("PATH");
+ if (!pathValue)
+ return undefined;
+ var dirs = splitNonEmpty(pathValue, qbs.pathListSeparator);
+ var suffix = exeSuffix(qbs);
+ var filePaths = [];
+ for (var i = 0; i < dirs.length; ++i) {
+ var candidate = FileInfo.joinPaths(dirs[i], "pkg-config" + suffix);
+ var canonicalCandidate = FileInfo.canonicalPath(candidate);
+ if (!canonicalCandidate || !File.exists(canonicalCandidate))
+ continue;
+ return canonicalCandidate;
+ }
+ return undefined;
+ }
+
+ function getModuleInfo(pkg, staticMode) {
+ var result = {};
+
+ var mapper = function(flag) { return flag.value; }
+ var typeFilter = function(type) {
+ return function(flag) { return flag.type === type; }
+ }
+
+ function getLibsInfo(libs) {
+ var result = {};
+ result.dynamicLibraries = libs.filter(typeFilter(PkgConfig.LibraryName)).map(mapper);
+ result.staticLibraries =
+ libs.filter(typeFilter(PkgConfig.StaticLibraryName)).map(mapper);
+ result.libraryPaths = libs.filter(typeFilter(PkgConfig.LibraryPath)).map(mapper);
+ result.frameworks = libs.filter(typeFilter(PkgConfig.Framework)).map(mapper);
+ result.frameworkPaths =
+ libs.filter(typeFilter(PkgConfig.FrameworkPath)).map(mapper);
+ result.driverLinkerFlags =
+ libs.filter(typeFilter(PkgConfig.LinkerFlag)).map(mapper);
+ return result;
+ }
+
+ result.version = pkg.version;
+ result.includePaths = pkg.cflags.filter(typeFilter(PkgConfig.IncludePath)).map(mapper);
+ result.systemIncludePaths =
+ pkg.cflags.filter(typeFilter(PkgConfig.SystemIncludePath)).map(mapper);
+ result.defines = pkg.cflags.filter(typeFilter(PkgConfig.Define)).map(mapper);
+ result.commonCompilerFlags =
+ pkg.cflags.filter(typeFilter(PkgConfig.CompilerFlag)).map(mapper);
+
+ var libsInfo = !staticMode ? getLibsInfo(pkg.libs) : getLibsInfo(pkg.libsPrivate);
+ for (var key in libsInfo) {
+ result[key] = libsInfo[key];
+ }
+
+ return result;
+ }
+
+ function getModuleName(packageName) { return packageName.replace('.', '-'); }
+
+ function getModuleDependencies(pkg, staticMode) {
+ var mapper = function(p) {
+ var result = {};
+ for (var key in p)
+ result[key] = p[key];
+ result.name = getModuleName(result.name);
+ return result;
+ }
+ var result = pkg.requires.map(mapper);
+ if (staticMode)
+ result = result.concat(pkg.requiresPrivate.map(mapper));
+ return result;
+ }
+
+ console.debug("Running pkgconfig provider.")
+
+ var outputDir = FileInfo.joinPaths(outputBaseDir, "modules");
+ File.makePath(outputDir);
+
+ var options = {};
+ options.searchPaths = libDirs;
+ options.sysroot = sysroot;
+ if (options.sysroot && !options.searchPaths) {
+ options.searchPaths = [
+ sysroot + "/usr/lib/pkgconfig",
+ sysroot + "/usr/share/pkgconfig"
+ ];
+ }
+ if (!options.searchPaths) {
+ // if we have pkg-config installed, let's ask it for its search paths (since
+ // built-in search paths can differ between platforms)
+ var executable = executableFilePath ? executableFilePath : getPkgConfigExecutable(qbs);
+ if (executable) {
+ var p = new Process()
+ if (p.exec(executable, ['pkg-config', '--variable=pc_path']) === 0) {
+ var stdout = p.readStdOut().trim();
+ // TODO: qbs.pathListSeparator? depends on what pkg-config prints on Windows
+ options.searchPaths = stdout ? stdout.split(':'): [];
+ }
+ }
+ }
+
+ var pkgConfig = new PkgConfig(options);
+ var brokenPackages = pkgConfig.brokenPackages();
+ if (brokenPackages.length !== 0) {
+ console.warn("Failed to load some pkg-config packages:");
+ for (var i = 0; i < brokenPackages.length; ++i) {
+ console.warn(" " + brokenPackages[i].filePath
+ + ": " + brokenPackages[i].errorText);
+ }
+ }
+ var packages = pkgConfig.packages();
+ for (var packageName in packages) {
+ var moduleName = getModuleName(packageName);
+ var moduleInfo = getModuleInfo(packages[packageName], staticMode);
+ var deps = getModuleDependencies(packages[packageName], staticMode);
+
+ var moduleDir = FileInfo.joinPaths(outputDir, moduleName);
+ File.makePath(moduleDir);
+ var module =
+ new TextFile(FileInfo.joinPaths(moduleDir, "module.qbs"), TextFile.WriteOnly);
+ module.writeLine("Module {");
+ module.writeLine(" version: " + ModUtils.toJSLiteral(moduleInfo.version));
+ module.writeLine(" Depends { name: 'cpp' }");
+ deps.forEach(function(dep) {
+ module.write(" Depends { name: '" + dep.name + "'");
+ for (var k in dep) {
+ if (k === "name")
+ continue;
+ module.write("; " + k + ": " + ModUtils.toJSLiteral(dep[k]));
+ }
+ module.writeLine(" }");
+ })
+ function writeProperty(propertyName) {
+ var value = moduleInfo[propertyName];
+ if (value.length !== 0) { // skip empty props for simplicity of the module file
+ module.writeLine(
+ " cpp." + propertyName + ":" + ModUtils.toJSLiteral(value));
+ }
+ }
+ writeProperty("includePaths");
+ writeProperty("systemIncludePaths");
+ writeProperty("defines");
+ writeProperty("commonCompilerFlags");
+ writeProperty("dynamicLibraries");
+ writeProperty("staticLibraries");
+ writeProperty("libraryPaths");
+ writeProperty("frameworks");
+ writeProperty("frameworkPaths");
+ writeProperty("driverLinkerFlags");
+ module.writeLine("}");
+ module.close();
+ }
+ return "";
+ }
+}
diff --git a/share/share.qbs b/share/share.qbs
index b02e971f6..c5cf6893e 100644
--- a/share/share.qbs
+++ b/share/share.qbs
@@ -56,7 +56,7 @@ Product {
Group {
name: "Module providers"
- files: ["qbs/module-providers/**/*"]
+ files: ["qbs/module-providers/*", "qbs/module-providers/**/*"]
fileTags: ["qbs resources"]
qbs.install: true
qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share"