diff options
author | Richard Weickelt <richard@weickelt.de> | 2019-07-08 01:49:19 +0200 |
---|---|---|
committer | Richard Weickelt <richard@weickelt.de> | 2019-10-10 08:05:15 +0000 |
commit | 905ee49fabe197bfe4537c1f10df9d7c48f731c2 (patch) | |
tree | 57acb908ac5449be8ddb84e01e00e52d7ce07755 | |
parent | 73ed687cf11cb2d4e7f263ef5754039b96b69aaa (diff) |
Bundle Qt libraries on all platforms
This patch allows us to deploy a self-containing Qbs package on all host
platforms that are supported by the official Qt binary packages.
Although not all (Linux) distributions make use of it, this will
be helpful to
- provide at least some binary convenience packages for the most
important distributions,
- perform building and testing in different environments, for instance
build Qbs in one stage and then run autotests for desktop, iOS,
android in parallel on multiple machines,
- avoid windeployqt which does not work when cross-building
for Windows on a Linux hosts.
Change-Id: I63de4ea2240b37d8bd465cbbf4ddff3d01eeac7e
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r-- | qbs-resources/imports/QbsAutotest.qbs | 6 | ||||
-rw-r--r-- | qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs | 2 | ||||
-rw-r--r-- | src/lib/corelib/corelib.qbs | 1 | ||||
-rw-r--r-- | src/packages/archive/archive.qbs | 115 | ||||
-rw-r--r-- | src/shared/bundledqt/bundledqt.qbs | 181 |
5 files changed, 144 insertions, 161 deletions
diff --git a/qbs-resources/imports/QbsAutotest.qbs b/qbs-resources/imports/QbsAutotest.qbs index 78db72d11..5d4143a41 100644 --- a/qbs-resources/imports/QbsAutotest.qbs +++ b/qbs-resources/imports/QbsAutotest.qbs @@ -7,6 +7,7 @@ QtApplication { consoleApplication: true property string testName name: "tst_" + testName + property string targetInstallDir: qbsbuildconfig.appInstallDir Depends { name: "Qt.testlib" } Depends { name: "qbscore" } Depends { name: "qbsbuildconfig" } @@ -28,13 +29,14 @@ QtApplication { "consolelogger.h" ] } - cpp.rpaths: [FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, qbsbuildconfig.libDirName)] + cpp.rpaths: qbsbuildconfig.libRPaths + qbs.commonRunEnvironment: ({ "QBS_INSTALL_DIR": FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix) }) Group { fileTagsFilter: product.type qbs.install: true - qbs.installDir: qbsbuildconfig.appInstallDir + qbs.installDir: targetInstallDir } } diff --git a/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs index c2db0189f..7fe735ad9 100644 --- a/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs +++ b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs @@ -12,7 +12,7 @@ Module { property bool enableProjectFileUpdates: false property bool enableRPath: true property bool installApiHeaders: true - property bool enableBundledQt: true + property bool enableBundledQt: false property bool useBundledQtScript: false property bool staticBuild: false property string libDirName: "lib" diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index 019d9aa51..bd44ac3ed 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -3,7 +3,6 @@ import qbs.Utilities QbsLibrary { Depends { name: "cpp" } - Depends { name: "bundledqt" } Depends { name: "Qt"; submodules: ["core-private", "network", "xml"] } Depends { name: "Qt.script" diff --git a/src/packages/archive/archive.qbs b/src/packages/archive/archive.qbs index 0e0663090..468606368 100644 --- a/src/packages/archive/archive.qbs +++ b/src/packages/archive/archive.qbs @@ -7,7 +7,7 @@ import qbs.TextFile QbsProduct { Depends { name: "qbs_processlauncher" } Depends { name: "qbscore" } - Depends { name: "bundledqt" } + Depends { name: "bundledqt"; required: false } Depends { name: "qbs documentation"; condition: project.withDocumentation } Depends { name: "qbs resources" } Depends { @@ -18,25 +18,8 @@ QbsProduct { Depends { name: "archiver" } - property stringList windeployqtArgs: [ - "--no-svg", - "--no-system-d3d-compiler", - "--no-angle", - "--no-compiler-runtime", - "--no-opengl-sw", - ] - - // List of path prefixes to be excluded from the generated archive - property stringList excludedPathPrefixes: [ - "bin/icudt", - "bin/icuin", - "bin/icuuc", - "bin/iconengines/", - "bin/imageformats/", - ] property bool includeTopLevelDir: false - condition: qbs.targetOS.containsAny(["windows", "macos"]) builtByDefault: false name: "qbs archive" type: ["archiver.archive"] @@ -64,65 +47,8 @@ QbsProduct { } Rule { - condition: qbs.targetOS.contains("windows") multiplex: true - inputsFromDependencies: ["installable"] - - Artifact { - filePath: "windeployqt.json" - fileTags: ["dependencies.json"] - } - - prepare: { - var cmd = new JavaScriptCommand(); - cmd.description = "windeployqt"; - cmd.outputFilePath = output.filePath; - cmd.installRoot = product.moduleProperty("qbs", "installRoot"); - cmd.windeployqtArgs = product.windeployqtArgs; - cmd.binaryFilePaths = inputs.installable.filter(function (artifact) { - return artifact.fileTags.contains("application") - || artifact.fileTags.contains("dynamiclibrary"); - }).map(function(a) { return ModUtils.artifactInstalledFilePath(a); }); - cmd.binaryFilePaths.sort(function(a1, a2) { - if (a1.contains("qbs.exe")) - return -1; - if (a2.contains("qbs.exe")) - return 1; - return 0; - }); - cmd.extendedDescription = FileInfo.joinPaths( - product.moduleProperty("Qt.core", "binPath"), "windeployqt") + ".exe " + - ["--json"].concat(cmd.windeployqtArgs).concat(cmd.binaryFilePaths).join(" "); - cmd.sourceCode = function () { - var out; - var process; - try { - process = new Process(); - process.exec(FileInfo.joinPaths(product.moduleProperty("Qt.core", "binPath"), - "windeployqt"), ["--json"] - .concat(windeployqtArgs).concat(binaryFilePaths), true); - out = process.readStdOut(); - } finally { - if (process) - process.close(); - } - - var tf; - try { - tf = new TextFile(outputFilePath, TextFile.WriteOnly); - tf.write(out); - } finally { - if (tf) - tf.close(); - } - }; - return [cmd]; - } - } - - Rule { - multiplex: true - inputs: ["dependencies.json", "installable"] + inputs: ["installable"] inputsFromDependencies: ["installable"] Artifact { @@ -140,46 +66,13 @@ QbsProduct { cmd.outputFilePath = output.filePath; cmd.baseDirectory = product.moduleProperty("archiver", "workingDirectory"); cmd.sourceCode = function() { - var tf; - for (var i = 0; i < (inputs["dependencies.json"] || []).length; ++i) { - try { - tf = new TextFile(inputs["dependencies.json"][i].filePath, - TextFile.ReadOnly); - inputFilePaths = inputFilePaths.concat( - JSON.parse(tf.readAll())["files"].map(function (obj) { - return FileInfo.joinPaths( - FileInfo.fromWindowsSeparators(obj.target), - FileInfo.fileName( - FileInfo.fromWindowsSeparators( - obj.source))); - })); - } finally { - if (tf) - tf.close(); - } - } - inputFilePaths.sort(); - + var tf; try { tf = new TextFile(outputFilePath, TextFile.ReadWrite); for (var i = 0; i < inputFilePaths.length; ++i) { - var ignore = false; var relativePath = FileInfo.relativePath(baseDirectory, inputFilePaths[i]); - for (var j = 0; j < excludedPathPrefixes.length; ++j) { - if (relativePath.startsWith(excludedPathPrefixes[j])) { - ignore = true; - break; - } - } - - // QTBUG-65916 - var fileName = FileInfo.fileName(inputFilePaths[i]); - if (fileName.endsWith(".qm") && !fileName.startsWith("qt_")) - ignore = true; - - if (!ignore) - tf.writeLine(relativePath); + tf.writeLine(relativePath); } } finally { if (tf) diff --git a/src/shared/bundledqt/bundledqt.qbs b/src/shared/bundledqt/bundledqt.qbs index 6e9b744ab..5995ae4d6 100644 --- a/src/shared/bundledqt/bundledqt.qbs +++ b/src/shared/bundledqt/bundledqt.qbs @@ -1,18 +1,29 @@ import qbs +import qbs.File import qbs.FileInfo Product { Depends { name: "qbsbuildconfig" } - Depends { name: "Qt"; submodules: - ["core", "gui", "network", "printsupport", "widgets", "xml"] } - Depends { name: "Qt.script"; required: false } + Depends { name: "Qt"; submodules: ["core", "gui", "network", "printsupport", "widgets", "xml"] } + Depends { name: "Qt.test"; condition: project.withTests === true } + Depends { name: "Qt.script"; condition: !qbsbuildconfig.useBundledQtScript; required: false } + Depends { + name: "Qt"; + submodules: [ "dbus", "xcb_qpa_lib-private" ]; + required: false + } - property bool deployQt: qbsbuildconfig.enableBundledQt && qbs.targetOS.contains("macos") - && Qt.core.qtConfig.contains("rpath") - property bool deployDebugLibraries: qbs.buildVariant === "debug" - || (qbs.buildVariants && qbs.buildVariants.contains("debug")) + condition: { + if (!qbsbuildconfig.enableBundledQt) + return false; + if (Qt.core.staticBuild) + throw("Cannot bundle static Qt libraries"); + return true; + } readonly property string qtDebugLibrarySuffix: { + if (Qt.core.qtBuildVariant !== "debug") + return ""; if (qbs.targetOS.contains("windows")) return "d"; if (qbs.targetOS.contains("darwin")) @@ -21,7 +32,6 @@ Product { } Group { - condition: deployQt && !Qt.core.staticBuild name: "qt.conf" files: ["qt.conf"] qbs.install: true @@ -29,56 +39,135 @@ Product { } Group { - condition: deployQt name: "Qt libraries" - files: !Qt.core.staticBuild ? Array.prototype.concat.apply( - [], Object.getOwnPropertyNames(Qt).map(function(mod) { - if (mod === "script" && !Qt[mod].present) - return []; - if (!Qt[mod].hasLibrary) - return []; - var fp = Qt[mod].libFilePathRelease; - var fpd = Qt.core.frameworkBuild ? fp + qtDebugLibrarySuffix : Qt[mod].libFilePathDebug; - - var list = [fp]; - if (deployDebugLibraries && qtDebugLibrarySuffix) - list.push(fpd); - - if (Qt.core.frameworkBuild) { - var suffix = ".framework/"; - var frameworkPath = fp.substr(0, fp.lastIndexOf(suffix) + suffix.length - 1); - var versionsPath = frameworkPath + "/Versions"; - var versionPath = versionsPath + "/" + Qt.core.versionMajor; - list.push(frameworkPath + "/Resources"); - list.push(versionPath + "/Resources/Info.plist"); - list.push(versionPath + "/" + FileInfo.fileName(fp)); - if (deployDebugLibraries && qtDebugLibrarySuffix) - list.push(versionPath + "/" + FileInfo.fileName(fpd)); - if (qbsbuildconfig.installApiHeaders) { - list.push(frameworkPath + "/Headers"); - list.push(versionPath + "/Headers/**"); + files: { + function getLibsForQtModule(mod) { + if (mod === "script" && !Qt[mod].present) + return []; + if ((mod !== "core") && !Qt[mod].hasLibrary) + return []; + if (Qt[mod].isStaticLibrary) + return []; + + var list = []; + if (qbs.targetOS.contains("windows")) { + var basename = FileInfo.baseName(Qt[mod].libNameForLinker); + var dir = Qt.core.binPath; + list.push(dir + "/" + basename + ".dll"); + + } else if (qbs.targetOS.contains("linux")) { + var fp = Qt[mod].libFilePath; + var basename = FileInfo.baseName(fp); + var dir = FileInfo.path(fp); + list.push(dir + "/" + basename + ".so"); + list.push(dir + "/" + basename + ".so." + Qt.core.versionMajor); + list.push(dir + "/" + basename + ".so." + Qt.core.versionMajor + "." + Qt.core.versionMinor); + list.push(fp); + + } else if (Qt.core.frameworkBuild) { + var fp = Qt[mod].libFilePathRelease; + var fpd = fp + "_debug"; + + if (qtDebugLibrarySuffix) + list.push(fpd); + + var suffix = ".framework/"; + var frameworkPath = fp.substr(0, fp.lastIndexOf(suffix) + suffix.length - 1); + var versionsPath = frameworkPath + "/Versions"; + var versionPath = versionsPath + "/" + Qt.core.versionMajor; + list.push(frameworkPath + "/Resources"); + list.push(versionPath + "/Resources/Info.plist"); + list.push(versionPath + "/" + FileInfo.fileName(fp)); + if (qtDebugLibrarySuffix) + list.push(versionPath + "/" + FileInfo.fileName(fpd)); + if (qbsbuildconfig.installApiHeaders) { + list.push(frameworkPath + "/Headers"); + list.push(versionPath + "/Headers/**"); + } } + return list; + } + + var qtModules = Object.getOwnPropertyNames(Qt); + var libraries = Array.prototype.concat.apply([], qtModules.map(getLibsForQtModule)); + + // Qt might be bundled with additional libraries + if (qbs.targetOS.contains("linux")) { + var dir = FileInfo.path(Qt.core.libFilePathRelease); + var addons = [ "libicui18n", "libicuuc", "libicudata" ]; + addons.forEach(function(lib) { + var fp = dir + "/" + lib + ".so"; + if (File.exists(fp)) + libraries.push(fp + "*"); + }); } - return list; - })) : [] + return libraries; + } + qbs.install: true qbs.installDir: qbsbuildconfig.libInstallDir - qbs.installSourceBase: Qt.core.libPath + qbs.installSourceBase: qbs.targetOS.contains("windows") ? Qt.core.binPath : Qt.core.libPath } Group { - condition: deployQt + name: "Windows Plugins" + condition: qbs.targetOS.contains("windows") prefix: Qt.core.pluginPath + "/" - name: "QPA plugin" - files: !Qt.core.staticBuild ? Array.prototype.concat.apply([], [""].concat( - deployDebugLibraries && qtDebugLibrarySuffix ? [qtDebugLibrarySuffix] : []).map( - function(suffix) { - return ["platforms/" + cpp.dynamicLibraryPrefix + (Qt.gui.defaultQpaPlugin || "qcocoa") - + suffix + cpp.dynamicLibrarySuffix]; - })) : [] + files: [ + "platforms/qwindows" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix, + "styles/qwindowsvistastyle" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix + ] qbs.install: true qbs.installDir: "plugins" qbs.installSourceBase: prefix } + + Group { + name: "macOS Plugins" + condition: qbs.targetOS.contains("darwin") + prefix: Qt.core.pluginPath + "/" + files: [ + "platforms/libqcocoa" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix, + "styles/libqmacstyle" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix + ] + qbs.install: true + qbs.installDir: "plugins" + qbs.installSourceBase: prefix + } + + Group { + name: "Linux Plugins" + condition: qbs.targetOS.contains("linux") + prefix: Qt.core.pluginPath + "/" + files: [ + "platforms/libqxcb" + cpp.dynamicLibrarySuffix, + "platformthemes/libqgtk3" + cpp.dynamicLibrarySuffix + ] + qbs.install: true + qbs.installDir: "plugins" + qbs.installSourceBase: prefix + } + + Group { + name: "MinGW Runtime DLLs" + condition: qbs.targetOS.contains("windows") && qbs.toolchain.contains("mingw") + + files: { + var libFileGlobs = [ + "*libgcc_s*.dll", + "*libstdc++-6.dll", + "*libwinpthread-1.dll" + ]; + var searchPaths = cpp.compilerLibraryPaths; + return Array.prototype.concat.apply([], searchPaths.map(function(path) { + return libFileGlobs.map(function(glob) { + return path + "/" + glob; + }); + })); + } + + qbs.install: true + qbs.installDir: "bin" + } } |