Skip to content

Commit 59681be

Browse files
committed
Merge #16477: build: skip deploying plugins we dont use in macdeployqtplus
1ac7b7f scripts: filter more qt plugins we don't use in macdeployqtplus (fanquake) 57cdd06 scripts: misc cleanups in macdeployqtplus (fanquake) 51729a4 scripts: use format() in macdeployqtplus (fanquake) 1c37e81 scripts: add type annotations to macdeployqtplus (fanquake) Pull request description: I frequently run `make deploy` while testing on macOS to get a properly light themed .app. With a brew installed Qt, this currently results in a pretty bloated executable: | branch | .app size | .dmg size | `make deploy` time | | ------- | --------- | --------- | --------------------- | | master (febf3a8) | 235mb | 86mb | 38s | | This PR (da98f6d470d236c027b7eb8b5f5552fdca04e803) | 51mb | 21mb | 22s | Similar change to dd367ff. ```diff 'QtGui.framework'], 'pluginPath': '/usr/local/opt/qt/plugins', 'qtPath': '/usr/local/opt/qt'} -[('platforminputcontexts', 'libqtvirtualkeyboardplugin.dylib'), - ('geoservices', 'libqtgeoservices_esri.dylib'), - ('geoservices', 'libqtgeoservices_mapboxgl.dylib'), - ('geoservices', 'libqtgeoservices_nokia.dylib'), - ('geoservices', 'libqtgeoservices_itemsoverlay.dylib'), - ('geoservices', 'libqtgeoservices_osm.dylib'), - ('geoservices', 'libqtgeoservices_mapbox.dylib'), - ('sceneparsers', 'libgltfsceneexport.dylib'), - ('sceneparsers', 'libgltfsceneimport.dylib'), - ('platforms', 'libqwebgl.dylib'), +[('platforms', 'libqwebgl.dylib'), ('platforms', 'libqoffscreen.dylib'), ('platforms', 'libqminimal.dylib'), ('platforms', 'libqcocoa.dylib'), ('platformthemes', 'libqxdgdesktopportal.dylib'), - ('printsupport', 'libcocoaprintersupport.dylib'), - ('webview', 'libqtwebview_webengine.dylib'), - ('webview', 'libqtwebview_darwin.dylib'), - ('geometryloaders', 'libdefaultgeometryloader.dylib'), - ('geometryloaders', 'libgltfgeometryloader.dylib'), ('styles', 'libqmacstyle.dylib'), - ('canbus', 'libqttinycanbus.dylib'), - ('canbus', 'libqtpassthrucanbus.dylib'), - ('canbus', 'libqtvirtualcanbus.dylib'), - ('canbus', 'libqtpeakcanbus.dylib'), ('bearer', 'libqgenericbearer.dylib'), - ('imageformats', 'libqgif.dylib'), - ('imageformats', 'libqwbmp.dylib'), - ('imageformats', 'libqwebp.dylib'), - ('imageformats', 'libqico.dylib'), - ('imageformats', 'libqmacheif.dylib'), - ('imageformats', 'libqjpeg.dylib'), - ('imageformats', 'libqtiff.dylib'), - ('imageformats', 'libqicns.dylib'), - ('imageformats', 'libqtga.dylib'), - ('imageformats', 'libqmacjp2.dylib'), - ('texttospeech', 'libqtexttospeech_speechosx.dylib'), - ('generic', 'libqtuiotouchplugin.dylib'), - ('renderplugins', 'libscene2d.dylib'), - ('gamepads', 'libdarwingamepad.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_thai.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_openwnn.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_hangul.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_pinyin.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_tcime.dylib')] + ('generic', 'libqtuiotouchplugin.dylib')] ``` ACKs for top commit: laanwj: ACK 1ac7b7f (purely Python code review and the fact that this passes travis, cannot run this on a mac) dongcarl: tested ACK 1ac7b7f Tree-SHA512: 5974eeaf7229bb5bde2b283c1331ec57ee87f624db146401f6b77dee4ee5502e0bd669958a46205f10398a371f8e6c91ddacb9f0e1943f9f7d042fb6de7957a8
2 parents d8fe24c + 1ac7b7f commit 59681be

File tree

1 file changed

+94
-52
lines changed

1 file changed

+94
-52
lines changed

contrib/macdeploy/macdeployqtplus

Lines changed: 94 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import subprocess, sys, re, os, shutil, stat, os.path, time
2020
from string import Template
2121
from argparse import ArgumentParser
22+
from typing import List, Optional
2223

2324
# This is ported from the original macdeployqt with modifications
2425

@@ -48,18 +49,18 @@ class FrameworkInfo(object):
4849
return False
4950

5051
def __str__(self):
51-
return """ Framework name: %s
52-
Framework directory: %s
53-
Framework path: %s
54-
Binary name: %s
55-
Binary directory: %s
56-
Binary path: %s
57-
Version: %s
58-
Install name: %s
59-
Deployed install name: %s
60-
Source file Path: %s
61-
Deployed Directory (relative to bundle): %s
62-
""" % (self.frameworkName,
52+
return """ Framework name: {}
53+
Framework directory: {}
54+
Framework path: {}
55+
Binary name: {}
56+
Binary directory: {}
57+
Binary path: {}
58+
Version: {}
59+
Install name: {}
60+
Deployed install name: {}
61+
Source file Path: {}
62+
Deployed Directory (relative to bundle): {}
63+
""".format(self.frameworkName,
6364
self.frameworkDirectory,
6465
self.frameworkPath,
6566
self.binaryName,
@@ -85,7 +86,7 @@ class FrameworkInfo(object):
8586
bundleBinaryDirectory = "Contents/MacOS"
8687

8788
@classmethod
88-
def fromOtoolLibraryLine(cls, line):
89+
def fromOtoolLibraryLine(cls, line: str) -> Optional['FrameworkInfo']:
8990
# Note: line must be trimmed
9091
if line == "":
9192
return None
@@ -146,13 +147,12 @@ class FrameworkInfo(object):
146147
info.sourceContentsDirectory = os.path.join(info.frameworkPath, "Contents")
147148
info.sourceVersionContentsDirectory = os.path.join(info.frameworkPath, "Versions", info.version, "Contents")
148149
info.destinationResourcesDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Resources")
149-
info.destinationContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Contents")
150150
info.destinationVersionContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Versions", info.version, "Contents")
151151

152152
return info
153153

154154
class ApplicationBundleInfo(object):
155-
def __init__(self, path):
155+
def __init__(self, path: str):
156156
self.path = path
157157
appName = "Bitcoin-Qt"
158158
self.binaryPath = os.path.join(path, "Contents", "MacOS", appName)
@@ -167,7 +167,7 @@ class DeploymentInfo(object):
167167
self.pluginPath = None
168168
self.deployedFrameworks = []
169169

170-
def detectQtPath(self, frameworkDirectory):
170+
def detectQtPath(self, frameworkDirectory: str):
171171
parentDir = os.path.dirname(frameworkDirectory)
172172
if os.path.exists(os.path.join(parentDir, "translations")):
173173
# Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x"
@@ -180,9 +180,9 @@ class DeploymentInfo(object):
180180
if os.path.exists(pluginPath):
181181
self.pluginPath = pluginPath
182182

183-
def usesFramework(self, name):
184-
nameDot = "%s." % name
185-
libNameDot = "lib%s." % name
183+
def usesFramework(self, name: str) -> bool:
184+
nameDot = "{}.".format(name)
185+
libNameDot = "lib{}.".format(name)
186186
for framework in self.deployedFrameworks:
187187
if framework.endswith(".framework"):
188188
if framework.startswith(nameDot):
@@ -192,7 +192,7 @@ class DeploymentInfo(object):
192192
return True
193193
return False
194194

195-
def getFrameworks(binaryPath, verbose):
195+
def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]:
196196
if verbose >= 3:
197197
print("Inspecting with otool: " + binaryPath)
198198
otoolbin=os.getenv("OTOOL", "otool")
@@ -202,7 +202,7 @@ def getFrameworks(binaryPath, verbose):
202202
if verbose >= 1:
203203
sys.stderr.write(o_stderr)
204204
sys.stderr.flush()
205-
raise RuntimeError("otool failed with return code %d" % otool.returncode)
205+
raise RuntimeError("otool failed with return code {}".format(otool.returncode))
206206

207207
otoolLines = o_stdout.split("\n")
208208
otoolLines.pop(0) # First line is the inspected binary
@@ -221,33 +221,33 @@ def getFrameworks(binaryPath, verbose):
221221

222222
return libraries
223223

224-
def runInstallNameTool(action, *args):
224+
def runInstallNameTool(action: str, *args):
225225
installnametoolbin=os.getenv("INSTALLNAMETOOL", "install_name_tool")
226226
subprocess.check_call([installnametoolbin, "-"+action] + list(args))
227227

228-
def changeInstallName(oldName, newName, binaryPath, verbose):
228+
def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int):
229229
if verbose >= 3:
230230
print("Using install_name_tool:")
231231
print(" in", binaryPath)
232232
print(" change reference", oldName)
233233
print(" to", newName)
234234
runInstallNameTool("change", oldName, newName, binaryPath)
235235

236-
def changeIdentification(id, binaryPath, verbose):
236+
def changeIdentification(id: str, binaryPath: str, verbose: int):
237237
if verbose >= 3:
238238
print("Using install_name_tool:")
239239
print(" change identification in", binaryPath)
240240
print(" to", id)
241241
runInstallNameTool("id", id, binaryPath)
242242

243-
def runStrip(binaryPath, verbose):
243+
def runStrip(binaryPath: str, verbose: int):
244244
stripbin=os.getenv("STRIP", "strip")
245245
if verbose >= 3:
246246
print("Using strip:")
247247
print(" stripped", binaryPath)
248248
subprocess.check_call([stripbin, "-x", binaryPath])
249249

250-
def copyFramework(framework, path, verbose):
250+
def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional[str]:
251251
if framework.sourceFilePath.startswith("Qt"):
252252
#standard place for Nokia Qt installer's frameworks
253253
fromPath = "/Library/Frameworks/" + framework.sourceFilePath
@@ -309,7 +309,7 @@ def copyFramework(framework, path, verbose):
309309

310310
return toPath
311311

312-
def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploymentInfo=None):
312+
def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo:
313313
if deploymentInfo is None:
314314
deploymentInfo = DeploymentInfo()
315315

@@ -355,15 +355,15 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym
355355

356356
return deploymentInfo
357357

358-
def deployFrameworksForAppBundle(applicationBundle, strip, verbose):
358+
def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip: bool, verbose: int) -> DeploymentInfo:
359359
frameworks = getFrameworks(applicationBundle.binaryPath, verbose)
360360
if len(frameworks) == 0 and verbose >= 1:
361-
print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path))
361+
print("Warning: Could not find any external frameworks to deploy in {}.".format(applicationBundle.path))
362362
return DeploymentInfo()
363363
else:
364364
return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose)
365365

366-
def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
366+
def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: DeploymentInfo, strip: bool, verbose: int):
367367
# Lookup available plugins, exclude unneeded
368368
plugins = []
369369
if deploymentInfo.pluginPath is None:
@@ -373,10 +373,12 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
373373
if pluginDirectory == "designer":
374374
# Skip designer plugins
375375
continue
376-
elif pluginDirectory == "phonon" or pluginDirectory == "phonon_backend":
377-
# Deploy the phonon plugins only if phonon is in use
378-
if not deploymentInfo.usesFramework("phonon"):
379-
continue
376+
elif pluginDirectory == "printsupport":
377+
# Skip printsupport plugins
378+
continue
379+
elif pluginDirectory == "imageformats":
380+
# Skip imageformats plugins
381+
continue
380382
elif pluginDirectory == "sqldrivers":
381383
# Deploy the sql plugins only if QtSql is in use
382384
if not deploymentInfo.usesFramework("QtSql"):
@@ -409,6 +411,42 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
409411
# Deploy the mediaservice plugins only if QtMultimediaWidgets is in use
410412
if not deploymentInfo.usesFramework("QtMultimediaWidgets"):
411413
continue
414+
elif pluginDirectory == "canbus":
415+
# Deploy the canbus plugins only if QtSerialBus is in use
416+
if not deploymentInfo.usesFramework("QtSerialBus"):
417+
continue
418+
elif pluginDirectory == "webview":
419+
# Deploy the webview plugins only if QtWebView is in use
420+
if not deploymentInfo.usesFramework("QtWebView"):
421+
continue
422+
elif pluginDirectory == "gamepads":
423+
# Deploy the webview plugins only if QtGamepad is in use
424+
if not deploymentInfo.usesFramework("QtGamepad"):
425+
continue
426+
elif pluginDirectory == "geoservices":
427+
# Deploy the webview plugins only if QtLocation is in use
428+
if not deploymentInfo.usesFramework("QtLocation"):
429+
continue
430+
elif pluginDirectory == "texttospeech":
431+
# Deploy the texttospeech plugins only if QtTextToSpeech is in use
432+
if not deploymentInfo.usesFramework("QtTextToSpeech"):
433+
continue
434+
elif pluginDirectory == "virtualkeyboard":
435+
# Deploy the virtualkeyboard plugins only if QtVirtualKeyboard is in use
436+
if not deploymentInfo.usesFramework("QtVirtualKeyboard"):
437+
continue
438+
elif pluginDirectory == "sceneparsers":
439+
# Deploy the virtualkeyboard plugins only if Qt3DCore is in use
440+
if not deploymentInfo.usesFramework("Qt3DCore"):
441+
continue
442+
elif pluginDirectory == "renderplugins":
443+
# Deploy the renderplugins plugins only if Qt3DCore is in use
444+
if not deploymentInfo.usesFramework("Qt3DCore"):
445+
continue
446+
elif pluginDirectory == "geometryloaders":
447+
# Deploy the geometryloaders plugins only if Qt3DCore is in use
448+
if not deploymentInfo.usesFramework("Qt3DCore"):
449+
continue
412450

413451
for pluginName in filenames:
414452
pluginPath = os.path.join(pluginDirectory, pluginName)
@@ -431,6 +469,10 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
431469
# Deploy the accessible qtquick plugin only if QtQuick is in use
432470
if not deploymentInfo.usesFramework("QtQuick"):
433471
continue
472+
elif pluginPath == "platforminputcontexts/libqtvirtualkeyboardplugin.dylib":
473+
# Deploy the virtualkeyboardplugin plugin only if QtVirtualKeyboard is in use
474+
if not deploymentInfo.usesFramework("QtVirtualKeyboard"):
475+
continue
434476

435477
plugins.append((pluginDirectory, pluginName))
436478

@@ -499,7 +541,7 @@ app_bundle = config.app_bundle[0]
499541

500542
if not os.path.exists(app_bundle):
501543
if verbose >= 1:
502-
sys.stderr.write("Error: Could not find app bundle \"%s\"\n" % (app_bundle))
544+
sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle))
503545
sys.exit(1)
504546

505547
app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0]
@@ -511,7 +553,7 @@ if config.translations_dir and config.translations_dir[0]:
511553
translations_dir = config.translations_dir[0]
512554
else:
513555
if verbose >= 1:
514-
sys.stderr.write("Error: Could not find translation dir \"%s\"\n" % (translations_dir))
556+
sys.stderr.write("Error: Could not find translation dir \"{}\"\n".format(translations_dir))
515557
sys.exit(1)
516558
# ------------------------------------------------
517559

@@ -520,7 +562,7 @@ for p in config.add_resources:
520562
print("Checking for \"%s\"..." % p)
521563
if not os.path.exists(p):
522564
if verbose >= 1:
523-
sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p))
565+
sys.stderr.write("Error: Could not find additional resource file \"{}\"\n".format(p))
524566
sys.exit(1)
525567

526568
# ------------------------------------------------
@@ -537,17 +579,17 @@ if len(config.fancy) == 1:
537579

538580
p = config.fancy[0]
539581
if verbose >= 3:
540-
print("Fancy: Loading \"%s\"..." % p)
582+
print("Fancy: Loading \"{}\"...".format(p))
541583
if not os.path.exists(p):
542584
if verbose >= 1:
543-
sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p))
585+
sys.stderr.write("Error: Could not find fancy disk image plist at \"{}\"\n".format(p))
544586
sys.exit(1)
545587

546588
try:
547589
fancy = plistlib.readPlist(p)
548590
except:
549591
if verbose >= 1:
550-
sys.stderr.write("Error: Could not parse fancy disk image plist at \"%s\"\n" % (p))
592+
sys.stderr.write("Error: Could not parse fancy disk image plist at \"{}\"\n".format(p))
551593
sys.exit(1)
552594

553595
try:
@@ -561,18 +603,18 @@ if len(config.fancy) == 1:
561603
assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int)
562604
except:
563605
if verbose >= 1:
564-
sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p))
606+
sys.stderr.write("Error: Bad format of fancy disk image plist at \"{}\"\n".format(p))
565607
sys.exit(1)
566608

567609
if "background_picture" in fancy:
568610
bp = fancy["background_picture"]
569611
if verbose >= 3:
570-
print("Fancy: Resolving background picture \"%s\"..." % bp)
612+
print("Fancy: Resolving background picture \"{}\"...".format(bp))
571613
if not os.path.exists(bp):
572614
bp = os.path.join(os.path.dirname(p), bp)
573615
if not os.path.exists(bp):
574616
if verbose >= 1:
575-
sys.stderr.write("Error: Could not find background picture at \"%s\" or \"%s\"\n" % (fancy["background_picture"], bp))
617+
sys.stderr.write("Error: Could not find background picture at \"{}\" or \"{}\"\n".format(fancy["background_picture"], bp))
576618
sys.exit(1)
577619
else:
578620
fancy["background_picture"] = bp
@@ -623,7 +665,7 @@ try:
623665
config.plugins = False
624666
except RuntimeError as e:
625667
if verbose >= 1:
626-
sys.stderr.write("Error: %s\n" % str(e))
668+
sys.stderr.write("Error: {}\n".format(str(e)))
627669
sys.exit(1)
628670

629671
# ------------------------------------------------
@@ -636,7 +678,7 @@ if config.plugins:
636678
deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose)
637679
except RuntimeError as e:
638680
if verbose >= 1:
639-
sys.stderr.write("Error: %s\n" % str(e))
681+
sys.stderr.write("Error: {}\n".format(str(e)))
640682
sys.exit(1)
641683

642684
# ------------------------------------------------
@@ -652,14 +694,14 @@ else:
652694
else:
653695
sys.stderr.write("Error: Could not find Qt translation path\n")
654696
sys.exit(1)
655-
add_qt_tr = ["qt_%s.qm" % lng for lng in config.add_qt_tr[0].split(",")]
697+
add_qt_tr = ["qt_{}.qm".format(lng) for lng in config.add_qt_tr[0].split(",")]
656698
for lng_file in add_qt_tr:
657699
p = os.path.join(qt_tr_dir, lng_file)
658700
if verbose >= 3:
659-
print("Checking for \"%s\"..." % p)
701+
print("Checking for \"{}\"...".format(p))
660702
if not os.path.exists(p):
661703
if verbose >= 1:
662-
sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file))
704+
sys.stderr.write("Error: Could not find Qt translation file \"{}\"\n".format(lng_file))
663705
sys.exit(1)
664706

665707
# ------------------------------------------------
@@ -700,14 +742,14 @@ if config.sign and 'CODESIGNARGS' not in os.environ:
700742
print("You must set the CODESIGNARGS environment variable. Skipping signing.")
701743
elif config.sign:
702744
if verbose >= 1:
703-
print("Code-signing app bundle %s"%(target,))
704-
subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True)
745+
print("Code-signing app bundle {}".format(target))
746+
subprocess.check_call("codesign --force {} {}".format(os.environ['CODESIGNARGS'], target), shell=True)
705747

706748
# ------------------------------------------------
707749

708750
if config.dmg is not None:
709751

710-
def runHDIUtil(verb, image_basename, **kwargs):
752+
def runHDIUtil(verb: str, image_basename: str, **kwargs) -> int:
711753
hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"]
712754
if "capture_stdout" in kwargs:
713755
del kwargs["capture_stdout"]
@@ -721,7 +763,7 @@ if config.dmg is not None:
721763

722764
for key, value in kwargs.items():
723765
hdiutil_args.append("-" + key)
724-
if not value is True:
766+
if value is not True:
725767
hdiutil_args.append(str(value))
726768

727769
return run(hdiutil_args, universal_newlines=True)

0 commit comments

Comments
 (0)