Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport: bitcoin#24603, #26694, #24669, #22546, #22199, #25817 (mac build) #5718

Merged
merged 8 commits into from
Nov 24, 2023
17 changes: 2 additions & 15 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ OSX_APP=Dash-Qt.app
OSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME))
OSX_DMG = $(OSX_VOLNAME).dmg
OSX_TEMP_ISO = $(OSX_DMG:.dmg=).temp.iso
OSX_BACKGROUND_IMAGE=$(top_srcdir)/contrib/macdeploy/background.tiff
OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus
OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/dash.icns
OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed
Expand All @@ -60,7 +59,6 @@ WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/dash.ico \
$(top_srcdir)/doc/README_windows.txt

OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_INSTALLER_ICONS) \
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh

COVERAGE_INFO = baseline.info \
Expand Down Expand Up @@ -125,28 +123,17 @@ $(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING)
deploydir: $(OSX_DMG)
else !BUILD_DARWIN
APP_DIST_DIR=$(top_builddir)/dist
APP_DIST_EXTRAS=$(APP_DIST_DIR)/.background/background.tiff $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/Applications

$(APP_DIST_DIR)/Applications:
@rm -f $@
@cd $(@D); $(LN_S) /Applications $(@F)

$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Dash-Qt

$(OSX_TEMP_ISO): $(APP_DIST_EXTRAS)
$(OSX_TEMP_ISO): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Dash-Qt
$(XORRISOFS) -D -l -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -o $@ $(APP_DIST_DIR) -- $(if $(SOURCE_DATE_EPOCH),-volume_date all_file_dates =$(SOURCE_DATE_EPOCH))

$(OSX_DMG): $(OSX_TEMP_ISO)
$(DMG) dmg "$<" "$@"

$(APP_DIST_DIR)/.background/background.tiff:
$(MKDIR_P) $(@D)
cp $(OSX_BACKGROUND_IMAGE) $@

$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Dash-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING)
INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR)

deploydir: $(APP_DIST_EXTRAS)
deploydir: $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Dash-Qt
endif !BUILD_DARWIN

appbundle: $(OSX_APP_BUILT)
Expand Down
2 changes: 1 addition & 1 deletion ci/test/00_setup_env_native_qt5.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
export TEST_PREVIOUS_RELEASES=true
export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.15.0.0 v0.16.1.1 v0.17.0.3 v18.2.2 v19.3.0"
export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.15.0.0 v0.16.1.1 v0.17.0.3 v18.2.2 v19.3.0 v20.0.1"
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --disable-fuzz-binary LDFLAGS=-static-libstdc++"
2 changes: 1 addition & 1 deletion contrib/guix/libexec/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ mkdir -p "$DISTSRC"
mkdir -p "unsigned-app-${HOST}"
cp --target-directory="unsigned-app-${HOST}" \
osx_volname \
contrib/macdeploy/detached-sig-{apply,create}.sh \
contrib/macdeploy/detached-sig-create.sh \
"${BASEPREFIX}/${HOST}"/native/bin/dmg
mv --target-directory="unsigned-app-${HOST}" dist
(
Expand Down
27 changes: 0 additions & 27 deletions contrib/macdeploy/detached-sig-apply.sh

This file was deleted.

221 changes: 62 additions & 159 deletions contrib/macdeploy/macdeployqtplus
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

import plistlib
import sys, re, os, shutil, stat, os.path
import sys, re, os, platform, shutil, stat, subprocess, os.path
from argparse import ArgumentParser
from ds_store import DSStore
from mac_alias import Alias
Expand Down Expand Up @@ -53,7 +52,7 @@ class FrameworkInfo(object):
return False

def __str__(self):
return f""" Framework name: {frameworkName}
return f""" Framework name: {self.frameworkName}
Framework directory: {self.frameworkDirectory}
Framework path: {self.frameworkPath}
Binary name: {self.binaryName}
Expand Down Expand Up @@ -85,8 +84,8 @@ class FrameworkInfo(object):
if line == "":
return None

# Don't deploy system libraries (exception for libQtuitools and libQtlucene).
if line.startswith("/System/Library/") or line.startswith("@executable_path") or (line.startswith("/usr/lib/") and "libQt" not in line):
# Don't deploy system libraries
if line.startswith("/System/Library/") or line.startswith("@executable_path") or line.startswith("/usr/lib/"):
return None

m = cls.reOLine.match(line)
Expand Down Expand Up @@ -246,56 +245,46 @@ def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional
toDir = os.path.join(path, framework.destinationDirectory)
toPath = os.path.join(toDir, framework.binaryName)

if not os.path.exists(fromPath):
raise RuntimeError(f"No file at {fromPath}")
if framework.isDylib():
if not os.path.exists(fromPath):
raise RuntimeError(f"No file at {fromPath}")

if os.path.exists(toPath):
return None # Already there
if os.path.exists(toPath):
return None # Already there

if not os.path.exists(toDir):
os.makedirs(toDir)
if not os.path.exists(toDir):
os.makedirs(toDir)

shutil.copy2(fromPath, toPath)
if verbose:
print("Copied:", fromPath)
print(" to:", toPath)
shutil.copy2(fromPath, toPath)
if verbose:
print("Copied:", fromPath)
print(" to:", toPath)
else:
to_dir = os.path.join(path, "Contents", "Frameworks", framework.frameworkName)
if os.path.exists(to_dir):
return None # Already there

from_dir = framework.frameworkPath
if not os.path.exists(from_dir):
raise RuntimeError(f"No directory at {from_dir}")

shutil.copytree(from_dir, to_dir, symlinks=True)
if verbose:
print("Copied:", from_dir)
print(" to:", to_dir)

headers_link = os.path.join(to_dir, "Headers")
if os.path.exists(headers_link):
os.unlink(headers_link)

headers_dir = os.path.join(to_dir, framework.binaryDirectory, "Headers")
if os.path.exists(headers_dir):
shutil.rmtree(headers_dir)

permissions = os.stat(toPath)
if not permissions.st_mode & stat.S_IWRITE:
os.chmod(toPath, permissions.st_mode | stat.S_IWRITE)

if not framework.isDylib(): # Copy resources for real frameworks

linkfrom = os.path.join(path, "Contents","Frameworks", framework.frameworkName, "Versions", "Current")
linkto = framework.version
if not os.path.exists(linkfrom):
os.symlink(linkto, linkfrom)
print("Linked:", linkfrom, "->", linkto)
fromResourcesDir = framework.sourceResourcesDirectory
if os.path.exists(fromResourcesDir):
toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory)
shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True)
if verbose:
print("Copied resources:", fromResourcesDir)
print(" to:", toResourcesDir)
fromContentsDir = framework.sourceVersionContentsDirectory
if not os.path.exists(fromContentsDir):
fromContentsDir = framework.sourceContentsDirectory
if os.path.exists(fromContentsDir):
toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory)
shutil.copytree(fromContentsDir, toContentsDir, symlinks=True)
if verbose:
print("Copied Contents:", fromContentsDir)
print(" to:", toContentsDir)
elif framework.frameworkName.startswith("libQtGui"): # Copy qt_menu.nib (applies to non-framework layout)
qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib")
qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib")
if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath):
shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True)
if verbose:
print("Copied for libQtGui:", qtMenuNibSourcePath)
print(" to:", qtMenuNibDestinationPath)

return toPath

def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo:
Expand Down Expand Up @@ -351,115 +340,20 @@ def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip
return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose)

def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: DeploymentInfo, strip: bool, verbose: int):
# Lookup available plugins, exclude unneeded
plugins = []
if deploymentInfo.pluginPath is None:
return
for dirpath, dirnames, filenames in os.walk(deploymentInfo.pluginPath):
pluginDirectory = os.path.relpath(dirpath, deploymentInfo.pluginPath)
if pluginDirectory == "designer":
# Skip designer plugins
continue
elif pluginDirectory == "printsupport":
# Skip printsupport plugins
continue
elif pluginDirectory == "imageformats":
# Skip imageformats plugins

if pluginDirectory not in ['styles', 'platforms']:
continue
elif pluginDirectory == "sqldrivers":
# Deploy the sql plugins only if QtSql is in use
if not deploymentInfo.usesFramework("QtSql"):
continue
elif pluginDirectory == "script":
# Deploy the script plugins only if QtScript is in use
if not deploymentInfo.usesFramework("QtScript"):
continue
elif pluginDirectory == "qmltooling" or pluginDirectory == "qml1tooling":
# Deploy the qml plugins only if QtDeclarative is in use
if not deploymentInfo.usesFramework("QtDeclarative"):
continue
elif pluginDirectory == "bearer":
# Deploy the bearer plugins only if QtNetwork is in use
if not deploymentInfo.usesFramework("QtNetwork"):
continue
elif pluginDirectory == "position":
# Deploy the position plugins only if QtPositioning is in use
if not deploymentInfo.usesFramework("QtPositioning"):
continue
elif pluginDirectory == "sensors" or pluginDirectory == "sensorgestures":
# Deploy the sensor plugins only if QtSensors is in use
if not deploymentInfo.usesFramework("QtSensors"):
continue
elif pluginDirectory == "audio" or pluginDirectory == "playlistformats":
# Deploy the audio plugins only if QtMultimedia is in use
if not deploymentInfo.usesFramework("QtMultimedia"):
continue
elif pluginDirectory == "mediaservice":
# Deploy the mediaservice plugins only if QtMultimediaWidgets is in use
if not deploymentInfo.usesFramework("QtMultimediaWidgets"):
continue
elif pluginDirectory == "canbus":
# Deploy the canbus plugins only if QtSerialBus is in use
if not deploymentInfo.usesFramework("QtSerialBus"):
continue
elif pluginDirectory == "webview":
# Deploy the webview plugins only if QtWebView is in use
if not deploymentInfo.usesFramework("QtWebView"):
continue
elif pluginDirectory == "gamepads":
# Deploy the webview plugins only if QtGamepad is in use
if not deploymentInfo.usesFramework("QtGamepad"):
continue
elif pluginDirectory == "geoservices":
# Deploy the webview plugins only if QtLocation is in use
if not deploymentInfo.usesFramework("QtLocation"):
continue
elif pluginDirectory == "texttospeech":
# Deploy the texttospeech plugins only if QtTextToSpeech is in use
if not deploymentInfo.usesFramework("QtTextToSpeech"):
continue
elif pluginDirectory == "virtualkeyboard":
# Deploy the virtualkeyboard plugins only if QtVirtualKeyboard is in use
if not deploymentInfo.usesFramework("QtVirtualKeyboard"):
continue
elif pluginDirectory == "sceneparsers":
# Deploy the virtualkeyboard plugins only if Qt3DCore is in use
if not deploymentInfo.usesFramework("Qt3DCore"):
continue
elif pluginDirectory == "renderplugins":
# Deploy the renderplugins plugins only if Qt3DCore is in use
if not deploymentInfo.usesFramework("Qt3DCore"):
continue
elif pluginDirectory == "geometryloaders":
# Deploy the geometryloaders plugins only if Qt3DCore is in use
if not deploymentInfo.usesFramework("Qt3DCore"):
continue

for pluginName in filenames:
pluginPath = os.path.join(pluginDirectory, pluginName)
if pluginName.endswith("_debug.dylib"):
# Skip debug plugins

if pluginName.split('.')[0] not in ['libqminimal', 'libqcocoa', 'libqmacstyle']:
continue
elif pluginPath == "imageformats/libqsvg.dylib" or pluginPath == "iconengines/libqsvgicon.dylib":
# Deploy the svg plugins only if QtSvg is in use
if not deploymentInfo.usesFramework("QtSvg"):
continue
elif pluginPath == "accessible/libqtaccessiblecompatwidgets.dylib":
# Deploy accessibility for Qt3Support only if the Qt3Support is in use
if not deploymentInfo.usesFramework("Qt3Support"):
continue
elif pluginPath == "graphicssystems/libqglgraphicssystem.dylib":
# Deploy the opengl graphicssystem plugin only if QtOpenGL is in use
if not deploymentInfo.usesFramework("QtOpenGL"):
continue
elif pluginPath == "accessible/libqtaccessiblequick.dylib":
# Deploy the accessible qtquick plugin only if QtQuick is in use
if not deploymentInfo.usesFramework("QtQuick"):
continue
elif pluginPath == "platforminputcontexts/libqtvirtualkeyboardplugin.dylib":
# Deploy the virtualkeyboardplugin plugin only if QtVirtualKeyboard is in use
if not deploymentInfo.usesFramework("QtVirtualKeyboard"):
continue

plugins.append((pluginDirectory, pluginName))

Expand Down Expand Up @@ -527,6 +421,9 @@ if os.path.exists(appname + ".dmg"):
print("+ Removing existing DMG +")
os.unlink(appname + ".dmg")

if os.path.exists(appname + ".temp.dmg"):
os.unlink(appname + ".temp.dmg")

# ------------------------------------------------

target = os.path.join("dist", "Dash-Qt.app")
Expand Down Expand Up @@ -644,6 +541,25 @@ ds.close()

# ------------------------------------------------

if platform.system() == "Darwin":
subprocess.check_call(f"codesign --deep --force --sign - {target}", shell=True)

print("+ Installing background.tiff +")

bg_path = os.path.join('dist', '.background', 'background.tiff')
os.mkdir(os.path.dirname(bg_path))

tiff_path = os.path.join('contrib', 'macdeploy', 'background.tiff')
shutil.copy2(tiff_path, bg_path)

# ------------------------------------------------

print("+ Generating symlink for /Applications +")

os.symlink("/Applications", os.path.join('dist', "Applications"))

# ------------------------------------------------

if config.dmg is not None:

print("+ Preparing .dmg disk image +")
Expand All @@ -667,19 +583,6 @@ if config.dmg is not None:
print("Attaching temp image...")
output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, universal_newlines=True, stdout=PIPE).stdout

m = re.search(r"/Volumes/(.+$)", output)
disk_root = m.group(0)

print("+ Applying fancy settings +")

bg_path = os.path.join(disk_root, ".background", os.path.basename('background.tiff'))
os.mkdir(os.path.dirname(bg_path))
if verbose:
print('background.tiff', "->", bg_path)
shutil.copy2('contrib/macdeploy/background.tiff', bg_path)

os.symlink("/Applications", os.path.join(disk_root, "Applications"))

print("+ Finalizing .dmg disk image +")

run(["hdiutil", "detach", f"/Volumes/{appname}"], universal_newlines=True)
Expand Down
3 changes: 3 additions & 0 deletions depends/packages/qt.mk
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ $(package)_config_opts_darwin += -no-feature-corewlan
$(package)_config_opts_darwin += -no-freetype
$(package)_config_opts_darwin += QMAKE_MACOSX_DEPLOYMENT_TARGET=$(OSX_MIN_VERSION)

# Optimizing using > -O1 causes non-determinism when building across arches.
$(package)_config_opts_aarch64_darwin += "QMAKE_CFLAGS_OPTIMIZE_FULL = -O1"

ifneq ($(build_os),darwin)
$(package)_config_opts_darwin += -xplatform macx-clang-linux
$(package)_config_opts_darwin += -device-option MAC_SDK_PATH=$(OSX_SDK)
Expand Down
Loading
Loading