From 9f6d02730918faa041afc39ec51b57675b4c5c1d Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Thu, 5 Feb 2015 11:18:47 +0100 Subject: Use windeployqt.exe if available and Win distribution documentation fix If windeployqt.exe is available for Qt5, it will be used to detect which Qt DLLs to put in the Windows distribution and its dependencies correctly. Added a note to our Windows building documentation about the VS redistributable. Test-Information: Tested building a MSI package on Windows 8.1 Pro with Qt 5.3.2 32-bit msvc2013_opengl which successfully installs and runs. Change-Id: I786da40d6467f1de8e64bfae275f8363ac1d5ba8 diff --git a/BuildTools/SCons/Tools/WindowsBundle.py b/BuildTools/SCons/Tools/WindowsBundle.py index 2915141..33ace7f 100644 --- a/BuildTools/SCons/Tools/WindowsBundle.py +++ b/BuildTools/SCons/Tools/WindowsBundle.py @@ -1,7 +1,41 @@ import SCons.Util, os +import subprocess +import re +import shutil + +def which(program_name): + if hasattr(shutil, "which"): + return shutil.which(program_name) + else: + path = os.getenv('PATH') + for p in path.split(os.path.pathsep): + p = os.path.join(p,program_name) + if os.path.exists(p) and os.access(p,os.X_OK): + return p def generate(env) : - def createWindowsBundle(env, bundle, resources = {}, qtplugins = {}, qtlibs = [], qtversion = '4') : + def captureWinDeployQtMapping(release = True): + p = False + if release: + p = subprocess.Popen(['windeployqt', '--release', '--dry-run', '--list', 'mapping', 'Swift.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + else: + p = subprocess.Popen(['windeployqt', '--debug', '--dry-run', '--list', 'mapping', 'Swift.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + if p: + stdout, stderr = p.communicate() + + mappings = [] + + p = re.compile(ur'"([^\"]*)" "([^\"]*)"') + + matches = re.findall(p, stdout) + for match in matches: + mappings.append(match) + return mappings + else: + return False + + def createWindowsBundleManual(env, bundle, resources = {}, qtplugins = {}, qtlibs = [], qtversion = '4') : all_files = [] all_files += env.Install(bundle, bundle + ".exe") for lib in qtlibs : @@ -11,17 +45,69 @@ def generate(env) : plugins_suffix = '' for plugin_type in qtplugins: all_files += env.Install(os.path.join(bundle, plugin_type), [os.path.join(env["QTDIR"], "plugins", plugin_type, "q" + plugin + plugins_suffix + ".dll") for plugin in qtplugins[plugin_type]]) + for dir, resourceFiles in resources.items() : + for resource in resourceFiles : + e = env.Entry(resource) + if e.isdir() : + for subresource in env.Glob(str(e) + "/*") : + all_files += env.Install(os.path.join(bundle, dir, e.name), subresource) + else : + all_files += env.Install(os.path.join(bundle, dir), resource) + return all_files + # This version of uses windeployqt tool + def createWindowsBundleWithWinDeployQt(env, bundle, resources = {}, qtplugins = {}, qtlibs = [], qtversion = '4') : + assert(qtversion == '5') + all_files = [] + + # add swift executable + all_files += env.Install(bundle, bundle + ".exe") + + # adding resources (swift sounds/images/translations) for dir, resourceFiles in resources.items() : for resource in resourceFiles : - e = env.Entry(resource) - if e.isdir() : - for subresource in env.Glob(str(e) + "/*") : - all_files += env.Install(os.path.join(bundle, dir, e.name), subresource) - else : - all_files += env.Install(os.path.join(bundle, dir), resource) + e = env.Entry(resource) + if e.isdir() : + for subresource in env.Glob(str(e) + "/*") : + all_files += env.Install(os.path.join(bundle, dir, e.name), subresource) + else : + all_files += env.Install(os.path.join(bundle, dir), resource) + + qtmappings = captureWinDeployQtMapping() + assert(qtmappings) + + # handle core DLLs + qt_corelib_regex = re.compile(ur".*bin.*\\(.*)\.dll") + + for qtlib in qtlibs: + if qtlib.startswith("Qt5"): + (src_path, target_path) = next(((src_path, target_path) for (src_path, target_path) in qtmappings if qt_corelib_regex.match(src_path) and qt_corelib_regex.match(src_path).group(1) == qtlib), (None, None)) + if src_path != None: + env.Install(bundle, src_path) + + # handle core dependencies + for (src_path, target_path) in qtmappings: + if qt_corelib_regex.match(src_path) and not qt_corelib_regex.match(src_path).group(1).startswith("Qt5"): + env.Install(bundle, src_path) + + # handle plugins + qt_plugin_regex = re.compile(ur".*plugins.*\\(.*)\\(.*)\.dll") + for (src_path, target_path) in qtmappings: + if qt_plugin_regex.match(src_path): + plugin_folder, filename = qt_plugin_regex.match(src_path).groups() + try: + if filename[1:] in qtplugins[plugin_folder]: + env.Install(os.path.join(bundle, plugin_folder), src_path) + except: + pass return all_files + def createWindowsBundle(env, bundle, resources = {}, qtplugins = {}, qtlibs = [], qtversion = '4'): + if which("windeployqt.exe"): + return createWindowsBundleWithWinDeployQt(env, bundle, resources, qtplugins, qtlibs, qtversion) + else: + return createWindowsBundleManual(env, bundle, resources, qtplugins, qtlibs, qtversion) + env.AddMethod(createWindowsBundle, "WindowsBundle") def exists(env) : diff --git a/Documentation/BuildingOnWindows.txt b/Documentation/BuildingOnWindows.txt index a2d9948..c411d62 100644 --- a/Documentation/BuildingOnWindows.txt +++ b/Documentation/BuildingOnWindows.txt @@ -42,12 +42,13 @@ Running tests Packaging Swift --------------- For packaging use: -- Microsoft Visual C++ Express 2008 +- Microsoft Visual C++ Express 2008 or Microsoft VS 2013 Express - No OpenSSL - WiX +- Download the C++ redistributable package from Microsoft and put it at C:\Program Files (x86)\Common Files\Merge Modules\ - config.py should contain: qt = "c:\\qt\\4.7.4" - vcredist = "c:\\Program Files\\Common Files\\Merge Modules" + vcredist = "C:\\Program Files (x86)\\Common Files\\Merge Modules\\vcredist_x86.exe" debug = 1 optimize = 1 wix_bindir = "c:\\program files\\Windows Installer XML v3.5\\bin" diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 6e90cd4..858df19 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -1,4 +1,4 @@ -import os, shutil, datetime, re, time +import os, datetime, re, time import Version def generateDefaultTheme(dir) : @@ -358,7 +358,7 @@ if env["PLATFORM"] == "darwin" : myenv.Command(["#/Packages/Swift/Swift-${SWIFT_VERSION}.dmg"], [app], ["Swift/Packaging/MacOSX/package.sh " + app.path + " Swift/Packaging/MacOSX/Swift.dmg.gz $TARGET $QTDIR"]) dsym = myenv.Command(["Swift-${SWIFT_VERSION}.dSYM"], ["Swift"], ["dsymutil -o ${TARGET} ${SOURCE}"]) myenv.Command(["#/Packages/Swift/Swift-${SWIFT_VERSION}.dSYM.zip"], dsym, ["cd ${SOURCE.dir} && zip -r ${TARGET.abspath} ${SOURCE.name}"]) - + if env.get("SWIFT_INSTALLDIR", "") : env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "bin"), swiftProgram + openURIProgram) env.InstallAs(os.path.join(env["SWIFT_INSTALLDIR"], "share", "pixmaps", "swift.xpm"), "#/Swift/resources/logo/logo-icon-32.xpm") @@ -368,15 +368,15 @@ if env.get("SWIFT_INSTALLDIR", "") : for i in ["16", "22", "24", "64", "128"] : env.InstallAs(os.path.join(icons_path, i + "x" + i, "apps", "swift.png"), "#/Swift/resources/logo/logo-icon-" + i + ".png") env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "applications"), "#/Swift/resources/swift.desktop") - for dir, resource in commonResources.items() : + for dir, resource in commonResources.items() : env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "swift", dir), resource) - + if env["PLATFORM"] == "win32" : if env["DIST"] or ARGUMENTS.get("dump_trace") : commonResources[""] = commonResources.get("", []) + [ - #os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"), + #os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"), #os.path.join(env["OPENSSL_DIR"], "bin", "libeay32.dll"), - "#/Swift/resources/images", + "#/Swift/resources/images", ] if env["SWIFTEN_DLL"] : commonResources[""] = commonResources.get("", []) + ["#/Swiften/${SWIFTEN_LIBRARY_FILE}"] @@ -392,11 +392,12 @@ if env["PLATFORM"] == "win32" : qtlibs += ['icuin51', 'icuuc51', 'icudt51', 'libGLESv2', 'libEGL'] qtplugins["platforms"] = ['windows'] qtplugins["accessible"] = ["taccessiblewidgets"] - windowsBundleFiles = myenv.WindowsBundle("Swift", - resources = commonResources, - qtplugins = qtplugins, - qtlibs = qtlibs, - qtversion = qt_version) + + windowsBundleFiles = myenv.WindowsBundle("Swift", + resources = commonResources, + qtplugins = qtplugins, + qtlibs = qtlibs, + qtversion = qt_version) if env["DIST"] : #myenv.Append(NSIS_OPTIONS = [ @@ -415,7 +416,7 @@ if env["PLATFORM"] == "win32" : # FIXME: This is incorrect, because it only works for latin1. # The correct way is \u? , but this is more # work - outfile.write("\\'%X" % ord(char)) + outfile.write("\\'%X" % ord(char)) else : outfile.write(char) outfile.write('\\par ') @@ -423,10 +424,9 @@ if env["PLATFORM"] == "win32" : outfile.close() infile.close() copying = env.Command(["Swift/COPYING.rtf"], ["COPYING"], convertToRTF) - wixvariables = { 'VCCRTFile': env["vcredist"], - 'Version': str(myenv["SWIFT_VERSION_MAJOR"]) + "." + str(myenv["SWIFT_VERSION_MINOR"]) + "." + str(myenv["SWIFT_VERSION_PATCH"]) + 'Version': str(myenv["SWIFT_VERSION_MAJOR"]) + "." + str(myenv["SWIFT_VERSION_MINOR"]) + "." + str(myenv["SWIFT_VERSION_PATCH"]) } wixincludecontent = "" for key in wixvariables: @@ -438,8 +438,6 @@ if env["PLATFORM"] == "win32" : myenv.WiX_Candle('..\\Packaging\\WiX\\Swift.wixobj', '..\\Packaging\\WiX\\Swift.wxs') myenv.WiX_Candle('..\\Packaging\\WiX\\gen_files.wixobj', '..\\Packaging\\WiX\\gen_files.wxs') myenv.WiX_Light('#/Packages/Swift/Swift-' + myenv["SWIFT_VERSION"] + '.msi', ['..\\Packaging\\WiX\\gen_files.wixobj','..\\Packaging\\WiX\\Swift.wixobj']) - + if myenv["debug"] : myenv.InstallAs('#/Packages/Swift/Swift-' + myenv["SWIFT_VERSION"] + '.pdb', "Swift.pdb") - - -- cgit v0.10.2-6-g49f6