aboutsummaryrefslogtreecommitdiff
path: root/macos-install.sh
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2025-11-08 18:47:51 +0100
committerPřemysl Eric Janouch <p@janouch.name>2025-11-11 19:28:45 +0100
commit690e60cd74c44ed1e2d21b27e3152856845ead28 (patch)
tree4a11dff3cec93315170c0caf9a0540c80aef8b75 /macos-install.sh
parenta7ff9f220db0785e88a6013d286b5f6b92f71693 (diff)
downloadfiv-690e60cd74c44ed1e2d21b27e3152856845ead28.tar.gz
fiv-690e60cd74c44ed1e2d21b27e3152856845ead28.tar.xz
fiv-690e60cd74c44ed1e2d21b27e3152856845ead28.zip
Build an application bundle on macOSorigin/masterorigin/HEAD
This is far from done, but nonetheless constitutes a big improvement. macOS application bundles are more or less necessary for: - showing a nice icon; - having spawned off instances actually be brought to the foreground; - file associations (yet files currently do not open properly); - having a reasonable method of distribution. Also resolving a bunch of minor issues: - The context menu had duplicate items, and might needlessly end up with (null) labels.
Diffstat (limited to 'macos-install.sh')
-rwxr-xr-xmacos-install.sh115
1 files changed, 115 insertions, 0 deletions
diff --git a/macos-install.sh b/macos-install.sh
new file mode 100755
index 0000000..884e1b1
--- /dev/null
+++ b/macos-install.sh
@@ -0,0 +1,115 @@
+#!/bin/sh -e
+export LC_ALL=C
+cd "$MESON_INSTALL_DESTDIR_PREFIX"
+
+# Input: Half-baked application bundle linked against Homebrew.
+# Output: Portable application bundle.
+source=/opt/homebrew
+bindir=Contents/MacOS
+libdir=Contents/Resources/lib
+datadir=Contents/Resources/share
+
+mkdir -p "$datadir"/glib-2.0/schemas
+cp -p "$source"/share/glib-2.0/schemas/org.gtk.Settings.* \
+ "$datadir"/glib-2.0/schemas
+mkdir -p "$datadir"/icons
+cp -pRL "$source"/share/icons/Adwaita "$datadir/"icons
+mkdir -p "$datadir"/icons/hicolor
+cp -p "$source"/share/icons/hicolor/index.theme "$datadir"/icons/hicolor
+mkdir -p "$datadir/mime"
+# GIO doesn't use the database on macOS, this subset is for us.
+find "$source"/share/mime/ -maxdepth 1 -type f -exec cp -p {} "$datadir"/mime \;
+
+# Copy binaries we directly or indirectly depend on.
+#
+# Homebrew is a bit chaotic in that some libraries are linked against locations
+# in /opt/homebrew/Cellar, and some against /opt/homebrew/opt symlinks.
+# We'll process things in such a way that it does not matter.
+#
+# As a side note, libraries in /usr/lib are now actually being served from
+# a shared cache by the dynamic linker and aren't visible on the filesystem.
+# There is an alternative to "otool -L" which can see them but it isn't
+# particularly nicer to parse: "dyld_info -dependents/-linked_dylibs".
+rm -rf "$libdir"
+mkdir -p "$libdir"
+
+pixbufdir=$libdir/gdk-pixbuf-2.0
+loadersdir=$pixbufdir/loaders
+cp -RL "$source"/lib/gdk-pixbuf-2.0/* "$pixbufdir"
+
+# Fix a piece of crap loader that needs to be special.
+svg=$loadersdir/libpixbufloader_svg.so
+rm -f "$loadersdir"/libpixbufloader_svg.dylib
+otool -L "$svg" | grep -o '@rpath/[^ ]*' | while IFS= read -r bad
+do install_name_tool -change "$bad" "$source/lib/$(basename "$bad")" "$svg"
+done
+
+GDK_PIXBUF_MODULEDIR=$loadersdir gdk-pixbuf-query-loaders \
+ | sed "s,$libdir,@rpath," > "$pixbufdir/loaders.cache"
+
+gtkdir=$libdir/gtk-3.0
+printbackendsdir=$gtkdir/printbackends
+cp -RL "$source"/lib/gtk-3.0/* "$gtkdir"
+
+# TODO: Figure out how to make gtk-query-immodules-3.0 pick up exactly
+# what it needs to. So far I'm not sure if this is at all even useful.
+rm -rf "$gtkdir"/immodules*
+
+find "$bindir" "$loadersdir" "$printbackendsdir" -type f -maxdepth 1 | awk '
+ function collect(binary, command, line) {
+ if (seen[binary]++)
+ return
+
+ command = "otool -L \"" binary "\""
+ while ((command | getline line) > 0)
+ if (match(line, /^\t\/opt\/.+ \(/))
+ collect(substr(line, RSTART + 1, RLENGTH - 3))
+ close(command)
+ } {
+ collect($0)
+ delete seen[$0]
+ } END {
+ for (library in seen)
+ print library
+ }
+' | while IFS= read -r binary
+do test -f "$libdir/$(basename "$binary")" || cp "$binary" "$libdir"
+done
+
+# Now redirect all binaries to internal linking.
+# A good overview of how this works is "man dyld" and:
+# https://itwenty.me/posts/01-understanding-rpath/
+rewrite() {
+ otool -L "$1" | sed -n 's,^\t\(.*\) (.*,\1,p' | grep '^/opt/' \
+ | while IFS= read -r lib
+ do install_name_tool -change "$lib" "@rpath/$(basename "$lib")" "$1"
+ done
+}
+
+find "$bindir" -type f -maxdepth 1 | while IFS= read -r binary
+do
+ install_name_tool -add_rpath @executable_path/../Resources/lib "$binary"
+ rewrite "$binary"
+done
+
+find "$libdir" -type f \( -name '*.so' -o -name '*.dylib' \) \
+ | while IFS= read -r binary
+do
+ chmod 644 "$binary"
+ install_name_tool -id "@rpath/${binary#$libdir/}" "$binary"
+ rewrite "$binary"
+
+ # Discard pointless @loader_path/../lib and absolute Homebrew paths.
+ otool -l "$binary" | awk '
+ $1 == "cmd" { command = $2 }
+ command == "LC_RPATH" && $1 == "path" { print $2 }
+ ' | xargs -R 1 -I % install_name_tool -delete_rpath % "$binary"
+
+ # Replace freshly invalidated code signatures with ad-hoc ones.
+ codesign --force --sign - "$binary"
+done
+
+glib-compile-schemas "$datadir"/glib-2.0/schemas
+
+# This may speed up program start-up a little bit.
+gtk-update-icon-cache "$datadir"/icons/Adwaita