Skip to content

Commit e9a4793

Browse files
committed
Merge bitcoin#28432: build: Produce a .zip for macOS distribution
b5790c3 build: remove dmg dependencies (fanquake) 33ae0bd macdeploy: remove DMG generation from deploy script (fanquake) a128111 build: produce a .zip for macOS distribution (Hennadii Stepanov) c38561d build: add -zip option to macdeployqtplus (fanquake) Pull request description: It is bitcoin#27099 revived with addressed [comments](bitcoin#27099 (comment)). From bitcoin#27099 (comment): > Reviving the discussion around using a `.zip` for the distributed macOS binaries, as opposed to a `.dmg`. > > Given we only had a single report of the "no finder window" issue (bitcoin#26176), I wonder if that means macOS users were able to figure it out, they gave up/didn't report, or, we just have very few macOS users. > > Related to bitcoin#18128. That's how it looks on macOS: ![image](https://github.com/bitcoin/bitcoin/assets/32963518/baa637bb-256b-4b24-8645-8c2754c2ae64) ACKs for top commit: Sjors: tACK b5790c3 jarolrod: ACK b5790c3 TheCharlatan: utACK b5790c3 Tree-SHA512: 6e9cb3ab0f60f8a92bfec50577e8d096c5b23ec09ebbb334826415609140ddc96d470aea37379495c1c6bb1beec0d306b09460f62e1543bb0f4396c10a1dfbe2
2 parents 1bf915d + b5790c3 commit e9a4793

File tree

16 files changed

+36
-172
lines changed

16 files changed

+36
-172
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ src/qt/bitcoin-qt.includes
7474

7575
*.log
7676
*.trs
77-
*.dmg
77+
*.zip
7878

7979
*.json.h
8080
*.raw.h

Makefile.am

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ space := $(empty) $(empty)
3737

3838
OSX_APP=Bitcoin-Qt.app
3939
OSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME))
40-
OSX_DMG = $(OSX_VOLNAME).dmg
40+
OSX_ZIP = $(OSX_VOLNAME).zip
4141
OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus
4242
OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns
4343
OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed
@@ -124,23 +124,24 @@ osx_volname:
124124
echo $(OSX_VOLNAME) >$@
125125

126126
if BUILD_DARWIN
127-
$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING)
128-
$(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR) -dmg
127+
$(OSX_ZIP): $(OSX_APP_BUILT) $(OSX_PACKAGING)
128+
$(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR) -zip
129129

130-
deploydir: $(OSX_DMG)
130+
deploydir: $(OSX_ZIP)
131131
else !BUILD_DARWIN
132132
APP_DIST_DIR=$(top_builddir)/dist
133133

134-
$(OSX_DMG): deploydir
135-
$(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))
134+
$(OSX_ZIP): deploydir
135+
if [ -n "$(SOURCE_DATE_EPOCH)" ]; then find $(APP_DIST_DIR) -exec touch -d @$(SOURCE_DATE_EPOCH) {} +; fi
136+
cd $(APP_DIST_DIR) && find . | sort | $(ZIP) -X@ $@
136137

137138
$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING)
138139
INSTALL_NAME_TOOL=$(INSTALL_NAME_TOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR)
139140

140141
deploydir: $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt
141142
endif !BUILD_DARWIN
142143

143-
deploy: $(OSX_DMG)
144+
deploy: $(OSX_ZIP)
144145
endif
145146

146147
$(BITCOIN_QT_BIN): FORCE
@@ -313,7 +314,7 @@ EXTRA_DIST += \
313314
test/util/data/txcreatesignv2.hex \
314315
test/util/rpcauth-test.py
315316

316-
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
317+
CLEANFILES = $(OSX_ZIP) $(BITCOIN_WIN_INSTALLER)
317318

318319
DISTCHECK_CONFIGURE_FLAGS = --enable-man
319320

ci/test/00_setup_env_mac.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}
1111
export CONTAINER_NAME=ci_macos_cross
1212
export CI_IMAGE_NAME_TAG="docker.io/ubuntu:22.04"
1313
export HOST=x86_64-apple-darwin
14-
export PACKAGES="cmake libz-dev python3-setuptools xorriso"
14+
export PACKAGES="cmake libz-dev python3-setuptools zip"
1515
export XCODE_VERSION=12.2
1616
export XCODE_BUILD_ID=12B45b
1717
export RUN_UNIT_TESTS=false

configure.ac

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ case $host in
799799
AC_PATH_TOOL([DSYMUTIL], [dsymutil], [dsymutil])
800800
AC_PATH_TOOL([INSTALL_NAME_TOOL], [install_name_tool], [install_name_tool])
801801
AC_PATH_TOOL([OTOOL], [otool], [otool])
802-
AC_PATH_PROGS([XORRISOFS], [xorrisofs], [xorrisofs])
802+
AC_PATH_PROG([ZIP], [zip], [zip])
803803

804804
dnl libtool will try to strip the static lib, which is a problem for
805805
dnl cross-builds because strip attempts to call a hard-coded ld,
@@ -1936,7 +1936,6 @@ AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/spl
19361936
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])])
19371937
AC_CONFIG_LINKS([contrib/devtools/iwyu/bitcoin.core.imp:contrib/devtools/iwyu/bitcoin.core.imp])
19381938
AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py])
1939-
AC_CONFIG_LINKS([contrib/macdeploy/background.tiff:contrib/macdeploy/background.tiff])
19401939
AC_CONFIG_LINKS([src/.bear-tidy-config:src/.bear-tidy-config])
19411940
AC_CONFIG_LINKS([src/.clang-tidy:src/.clang-tidy])
19421941
AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])

contrib/guix/libexec/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ mkdir -p "$DISTSRC"
315315
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" \
316316
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" && exit 1 )
317317
)
318-
make deploy ${V:+V=1} OSX_DMG="${OUTDIR}/${DISTNAME}-${HOST}-unsigned.dmg"
318+
make deploy ${V:+V=1} OSX_ZIP="${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip"
319319
;;
320320
esac
321321
(

contrib/guix/libexec/codesign.sh

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,8 @@ mkdir -p "$DISTSRC"
8585
# Apply detached codesignatures to dist/ (in-place)
8686
signapple apply dist/Bitcoin-Qt.app codesignatures/osx/dist
8787

88-
# Make a DMG from dist/
89-
xorrisofs -D -l -V "$(< osx_volname)" -no-pad -r -dir-mode 0755 \
90-
-o "${OUTDIR}/${DISTNAME}-${HOST}.dmg" \
91-
dist \
92-
-- -volume_date all_file_dates ="$SOURCE_DATE_EPOCH"
88+
# Make a .zip from dist/
89+
zip "${OUTDIR}/${DISTNAME}-${HOST}.zip" dist/*
9390
;;
9491
*)
9592
exit 1

contrib/guix/manifest.scm

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
((gnu packages bash) #:select (bash-minimal))
44
(gnu packages bison)
55
((gnu packages certs) #:select (nss-certs))
6-
((gnu packages cdrom) #:select (xorriso))
76
((gnu packages cmake) #:select (cmake-minimal))
87
(gnu packages commencement)
98
(gnu packages compression)
@@ -606,5 +605,5 @@ inspecting signatures in Mach-O binaries.")
606605
((string-contains target "-linux-")
607606
(list (make-bitcoin-cross-toolchain target)))
608607
((string-contains target "darwin")
609-
(list clang-toolchain-15 binutils cmake-minimal xorriso python-signapple))
608+
(list clang-toolchain-15 binutils cmake-minimal python-signapple zip))
610609
(else '())))))

contrib/macdeploy/README.md

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The `macdeployqtplus` script should not be run manually. Instead, after building
66
make deploy
77
```
88

9-
When complete, it will have produced `Bitcoin-Core.dmg`.
9+
When complete, it will have produced `Bitcoin-Core.zip`.
1010

1111
## SDK Extraction
1212

@@ -60,10 +60,10 @@ previous stage) as the first argument.
6060

6161
The `sha256sum` of the generated TAR.GZ archive should be `df75d30ecafc429e905134333aeae56ac65fac67cb4182622398fd717df77619`.
6262

63-
## Deterministic macOS DMG Notes
63+
## Deterministic macOS App Notes
6464

65-
Working macOS DMGs are created in Linux by combining a recent `clang`, the Apple
66-
`binutils` (`ld`, `ar`, etc) and DMG authoring tools.
65+
macOS Applications are created in Linux by combining a recent `clang` and the Apple
66+
`binutils` (`ld`, `ar`, etc).
6767

6868
Apple uses `clang` extensively for development and has upstreamed the necessary
6969
functionality so that a vanilla clang can take advantage. It supports the use of `-F`,
@@ -93,20 +93,15 @@ created using these tools. The build process has been designed to avoid includin
9393
SDK's files in Guix's outputs. All interim tarballs are fully deterministic and may be freely
9494
redistributed.
9595

96-
[`xorrisofs`](https://www.gnu.org/software/xorriso/) is used to create the DMG.
97-
98-
A background image is added to DMG files by inserting a `.DS_Store` during creation.
99-
10096
As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a requirement in
10197
order to satisfy the new Gatekeeper requirements. Because this private key cannot be
10298
shared, we'll have to be a bit creative in order for the build process to remain somewhat
10399
deterministic. Here's how it works:
104100

105-
- Builders use Guix to create an unsigned release. This outputs an unsigned DMG which
101+
- Builders use Guix to create an unsigned release. This outputs an unsigned ZIP which
106102
users may choose to bless and run. It also outputs an unsigned app structure in the form
107-
of a tarball, which also contains all of the tools that have been previously (deterministically)
108-
built in order to create a final DMG.
103+
of a tarball.
109104
- The Apple keyholder uses this unsigned app to create a detached signature, using the
110105
script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs).
111106
- Builders feed the unsigned app + detached signature back into Guix. It uses the
112-
pre-built tools to recombine the pieces into a deterministic DMG.
107+
pre-built tools to recombine the pieces into a deterministic ZIP.

contrib/macdeploy/background.tiff

-18 KB
Binary file not shown.

contrib/macdeploy/macdeployqtplus

Lines changed: 7 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
import sys, re, os, platform, shutil, stat, subprocess, os.path
2020
from argparse import ArgumentParser
21-
from ds_store import DSStore
22-
from mac_alias import Alias
2321
from pathlib import Path
2422
from subprocess import PIPE, run
2523
from typing import List, Optional
@@ -385,7 +383,7 @@ def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: Deployme
385383

386384
ap = ArgumentParser(description="""Improved version of macdeployqt.
387385
388-
Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file.
386+
Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .zip file.
389387
Note, that the "dist" folder will be deleted before deploying on each run.
390388
391389
Optionally, Qt translation files (.qm) can be added to the bundle.""")
@@ -395,8 +393,8 @@ ap.add_argument("appname", nargs=1, metavar="appname", help="name of the app bei
395393
ap.add_argument("-verbose", nargs="?", const=True, help="Output additional debugging information")
396394
ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")
397395
ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")
398-
ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image")
399396
ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.")
397+
ap.add_argument("-zip", nargs="?", const="", metavar="zip", help="create a .zip containing the app bundle")
400398

401399
config = ap.parse_args()
402400

@@ -417,12 +415,9 @@ if os.path.exists("dist"):
417415
print("+ Removing existing dist folder +")
418416
shutil.rmtree("dist")
419417

420-
if os.path.exists(appname + ".dmg"):
421-
print("+ Removing existing DMG +")
422-
os.unlink(appname + ".dmg")
423-
424-
if os.path.exists(appname + ".temp.dmg"):
425-
os.unlink(appname + ".temp.dmg")
418+
if os.path.exists(appname + ".zip"):
419+
print("+ Removing existing .zip +")
420+
os.unlink(appname + ".zip")
426421

427422
# ------------------------------------------------
428423

@@ -497,99 +492,13 @@ with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f:
497492

498493
# ------------------------------------------------
499494

500-
print("+ Generating .DS_Store +")
501-
502-
output_file = os.path.join("dist", ".DS_Store")
503-
504-
ds = DSStore.open(output_file, 'w+')
505-
506-
ds['.']['bwsp'] = {
507-
'WindowBounds': '{{300, 280}, {500, 343}}',
508-
'PreviewPaneVisibility': False,
509-
}
510-
511-
icvp = {
512-
'gridOffsetX': 0.0,
513-
'textSize': 12.0,
514-
'viewOptionsVersion': 1,
515-
'backgroundImageAlias': b'\x00\x00\x00\x00\x02\x1e\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x94\\\xb0H+\x00\x05\x00\x00\x00\x98\x0fbackground.tiff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xd19\xb0\xf8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\r\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b.background\x00\x00\x10\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x11\x00\x08\x00\x00\xd19\xb0\xf8\x00\x00\x00\x01\x00\x04\x00\x00\x00\x98\x00\x0e\x00 \x00\x0f\x00b\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x00.\x00t\x00i\x00f\x00f\x00\x0f\x00\x02\x00\x00\x00\x12\x00\x1c/.background/background.tiff\x00\x14\x01\x06\x00\x00\x00\x00\x01\x06\x00\x02\x00\x00\x0cMacintosh HD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x97\xab\xc3H+\x00\x00\x01\x88[\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02u\xab\x8d\xd1\x94\\\xb0devrddsk\xff\xff\xff\xff\x00\x00\t \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07bitcoin\x00\x00\x10\x00\x08\x00\x00\xce\x97\xab\xc3\x00\x00\x00\x11\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x01\x00\x14\x01\x88[\x88\x00\x16\xa9\t\x00\x08\xfaR\x00\x08\xfaQ\x00\x02d\x8e\x00\x0e\x00\x02\x00\x00\x00\x0f\x00\x1a\x00\x0c\x00M\x00a\x00c\x00i\x00n\x00t\x00o\x00s\x00h\x00 \x00H\x00D\x00\x13\x00\x01/\x00\x00\x15\x00\x02\x00\x14\xff\xff\x00\x00\xff\xff\x00\x00',
516-
'backgroundColorBlue': 1.0,
517-
'iconSize': 96.0,
518-
'backgroundColorGreen': 1.0,
519-
'arrangeBy': 'none',
520-
'showIconPreview': True,
521-
'gridSpacing': 100.0,
522-
'gridOffsetY': 0.0,
523-
'showItemInfo': False,
524-
'labelOnBottom': True,
525-
'backgroundType': 2,
526-
'backgroundColorRed': 1.0
527-
}
528-
alias = Alias().from_bytes(icvp['backgroundImageAlias'])
529-
alias.volume.name = appname
530-
alias.volume.posix_path = '/Volumes/' + appname
531-
icvp['backgroundImageAlias'] = alias.to_bytes()
532-
ds['.']['icvp'] = icvp
533-
534-
ds['.']['vSrn'] = ('long', 1)
535-
536-
ds['Applications']['Iloc'] = (370, 156)
537-
ds['Bitcoin-Qt.app']['Iloc'] = (128, 156)
538-
539-
ds.flush()
540-
ds.close()
541-
542-
# ------------------------------------------------
543-
544495
if platform.system() == "Darwin":
545496
subprocess.check_call(f"codesign --deep --force --sign - {target}", shell=True)
546497

547-
print("+ Installing background.tiff +")
548-
549-
bg_path = os.path.join('dist', '.background', 'background.tiff')
550-
os.mkdir(os.path.dirname(bg_path))
551-
552-
tiff_path = os.path.join('contrib', 'macdeploy', 'background.tiff')
553-
shutil.copy2(tiff_path, bg_path)
554-
555-
# ------------------------------------------------
556-
557-
print("+ Generating symlink for /Applications +")
558-
559-
os.symlink("/Applications", os.path.join('dist', "Applications"))
560-
561498
# ------------------------------------------------
562499

563-
if config.dmg is not None:
564-
565-
print("+ Preparing .dmg disk image +")
566-
567-
if verbose:
568-
print("Determining size of \"dist\"...")
569-
size = 0
570-
for path, dirs, files in os.walk("dist"):
571-
for file in files:
572-
size += os.path.getsize(os.path.join(path, file))
573-
size += int(size * 0.15)
574-
575-
if verbose:
576-
print("Creating temp image for modification...")
577-
578-
tempname: str = appname + ".temp.dmg"
579-
580-
run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, text=True)
581-
582-
if verbose:
583-
print("Attaching temp image...")
584-
output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, text=True, stdout=PIPE).stdout
585-
586-
print("+ Finalizing .dmg disk image +")
587-
588-
run(["hdiutil", "detach", f"/Volumes/{appname}"], text=True)
589-
590-
run(["hdiutil", "convert", tempname, "-format", "UDZO", "-o", appname, "-imagekey", "zlib-level=9"], check=True, text=True)
591-
592-
os.unlink(tempname)
500+
if config.zip is not None:
501+
shutil.make_archive('{}'.format(appname), format='zip', root_dir='dist', base_dir='Bitcoin-Qt.app')
593502

594503
# ------------------------------------------------
595504

0 commit comments

Comments
 (0)