build, gitlab-ci, meson: Add macOS builds to our CI
This adds macOS support on our CI aiming to MacPorts + macOS SDK 11. But since the GNOME runner have short timeout and no cache we fallback to Homebrew for now (which inelegantly links to X11 and follows runner's very high macOS 14). There is also still work to do: .dmg creation, multi-arch and notarization. Even so, this is a huge improvement, because macOS devs can now easily test MRs inhouse and non-macOS devs can contribute for macOS inhouse too. With the word "inhouse" I mean from this official gimp repo, without needing gimp-macos-build. For making that possible, I ported various concepts from gimp-macos-build: - .typelib regeneration for relocatability - LC_RPATH, LC_LOAD_DYLIB and LC_ID_DYLIB patching for relocatability - LC_BUILD_VERSION (minos) check for compatibility - GdkPixBuf loaders.cache patching - NEW: immodules.cache patching - Python.framework complex handling - Ad-hoc code signing on binaries (do not confuse with notarization) - .dSYM generation for babl, gegl and gimp - etc All these concepts into few scripts, without depending on gtk-mac-bundler. Since it was designed to work with MacPorts, we could make use of it on gimp-macos-build, but things are so endlessly complicated there into the 9999 scripts and CircleCI is very slow, so I'm not sure if gimp-macos-build have any future. The ideal would be official macOS 11 builds on GIMP repo.
This commit is contained in:
parent
85b1f052c2
commit
7accd52ce1
12 changed files with 978 additions and 4 deletions
|
|
@ -8,6 +8,7 @@ spec:
|
|||
- GIMP_CI_SNAP #trigger the snap build (base but slow)
|
||||
- GIMP_CI_WIN_INSTALLER #trigger all native MSYS2 builds then creates Inno Windows installer (base but slow)
|
||||
- GIMP_CI_MS_STORE #trigger arm64 and x64 native MSYS2 builds then creates a .msixbundle (base but slow)
|
||||
- GIMP_CI_MACOS #trigger arm64 native macOS builds (base but slow)
|
||||
- none
|
||||
default: 'none'
|
||||
test_pipeline:
|
||||
|
|
@ -78,7 +79,6 @@ workflow:
|
|||
retry:
|
||||
max: 1
|
||||
when:
|
||||
- 'runner_system_failure'
|
||||
- 'scheduler_failure'
|
||||
needs: []
|
||||
# Default Docker image (keep variables: DEB_VERSION: consistent with devel-docs/os-support.txt)
|
||||
|
|
@ -647,6 +647,62 @@ gimp-win-eol:
|
|||
artifacts: !reference [gimp-win, artifacts]
|
||||
|
||||
|
||||
## macOS pipelines (Homebrew) ##
|
||||
.macos-inhouse:
|
||||
extends: .default
|
||||
rules:
|
||||
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*Package:Macos Dmg.*/'
|
||||
interruptible: true
|
||||
- if: '$GIMP_CI_MACOS != null || "$[[ inputs.distribution_pipeline ]]" =~ /.*GIMP_CI_MACOS.*/'
|
||||
tags:
|
||||
- macos
|
||||
variables:
|
||||
#FIXME: Our runner #926 (by MacStadium) do not have cache nor timeout for MacPorts builds
|
||||
OPT_PREFIX: /opt/homebrew
|
||||
PKGCONF_RELOCATABLE_OPTION: '-Dpkgconfig.relocatable=true'
|
||||
DMG_OPTION: '-Ddmg=true'
|
||||
before_script:
|
||||
- export GIMP_PREFIX="$PWD/_install-$(uname -m)"
|
||||
- export PATH="$OPT_PREFIX/bin:$PATH"
|
||||
timeout: 30m
|
||||
|
||||
.macos_environ: &MAC_ENVIRON
|
||||
- printf "\e[0Ksection_start:`date +%s`:macos_environ[collapsed=true]\r\e[0KPreparing build environment\n"
|
||||
## Build-time vars
|
||||
- export PKG_CONFIG_PATH="${GIMP_PREFIX}/lib/pkgconfig:${OPT_PREFIX}/lib/pkgconfig:${OPT_PREFIX}/opt/libarchive/lib/pkgconfig"
|
||||
- export XDG_DATA_DIRS="${GIMP_PREFIX}/share:${OPT_PREFIX}/share"
|
||||
## Runtime vars
|
||||
- export PATH="${GIMP_PREFIX}/bin:${OPT_PREFIX}/bin:$PATH"
|
||||
- export GI_TYPELIB_PATH="${GIMP_PREFIX}/lib/girepository-1.0:${OPT_PREFIX}/lib/girepository-1.0"
|
||||
- printf "\e[0Ksection_end:`date +%s`:macos_environ\r\e[0K\n"
|
||||
|
||||
deps-macos-inhouse:
|
||||
extends: .macos-inhouse
|
||||
stage: dependencies
|
||||
script:
|
||||
- sh build/macos/1_build-deps-macports.sh
|
||||
artifacts:
|
||||
paths:
|
||||
- _install-*
|
||||
- babl/_build-*/meson-logs/meson-log.txt
|
||||
- gegl/_build-*/meson-logs/meson-log.txt
|
||||
expire_in: 2 hours
|
||||
|
||||
gimp-macos-inhouse:
|
||||
extends: .macos-inhouse
|
||||
needs: ["deps-macos-inhouse"]
|
||||
stage: build
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
script:
|
||||
- sh build/macos/2_build-gimp-macports.sh
|
||||
artifacts:
|
||||
paths:
|
||||
- gimp-*.app
|
||||
- _build*/meson-logs/meson-log.txt
|
||||
- _build*/done-dylib.list
|
||||
|
||||
|
||||
## Analysis ##
|
||||
|
||||
file-plug-in-tests:
|
||||
|
|
|
|||
87
build/macos/1_build-deps-macports.sh
Normal file
87
build/macos/1_build-deps-macports.sh
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Ensure the script work properly
|
||||
case $(readlink /proc/$$/exe) in
|
||||
*bash)
|
||||
set -o posix
|
||||
;;
|
||||
esac
|
||||
set -e
|
||||
if [ "$0" != 'build/macos/1_build-deps-macports.sh' ] && [ $(basename "$PWD") != 'macos' ]; then
|
||||
printf '\033[31m(ERROR)\033[0m: Script called from wrong dir. Please, call this script from the root of gimp git dir/\n'
|
||||
exit 1
|
||||
elif [ $(basename "$PWD") = 'macos' ]; then
|
||||
cd ../../..
|
||||
fi
|
||||
if [ -z "$GITLAB_CI" ]; then
|
||||
GIT_DEPTH='1'
|
||||
|
||||
PARENT_DIR='/..'
|
||||
fi
|
||||
|
||||
|
||||
# Install part of the deps
|
||||
if [ -z "$OPT_PREFIX" ]; then
|
||||
export OPT_PREFIX=$(which port | sed 's|/bin/port||' || brew --prefix)
|
||||
if echo "$OPT_PREFIX" | grep -q 'not found'; then
|
||||
printf '\033[31m(ERROR)\033[0m: MacPorts installation not found. Please, install it on: https://www.macports.org/install.php\n'
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ "$OPT_PREFIX" != '/opt/local' ] && [ "$OPT_PREFIX" != '/opt/homebrew' ]; then
|
||||
sed -i .bak "s/^#build_arch.*/build_arch $(uname -m)/" "${OPT_PREFIX}/etc/macports/macports.conf" >/dev/null 2>&1 || true
|
||||
fi
|
||||
export MACOSX_DEPLOYMENT_TARGET=$(awk '/LSMinimumSystemVersion/{found=1} found && /<string>/{gsub(/.*<string>|<\/string>.*/, ""); print; exit}' build/macos/Info.plist) #End of config
|
||||
|
||||
printf "\e[0Ksection_start:`date +%s`:deps_install[collapsed=true]\r\e[0KInstalling dependencies provided by $( [ -f "$OPT_PREFIX/bin/port" ] && echo MacPorts || echo Homebrew )\n"
|
||||
if [ -f "$OPT_PREFIX/bin/port" ]; then
|
||||
eval $( [ "$OPT_PREFIX"=/opt/local ] && echo sudo ) port sync && eval $( [ "$OPT_PREFIX"=/opt/local ] && echo sudo ) port upgrade outdated
|
||||
eval $( [ "$OPT_PREFIX"=/opt/local ] && echo sudo ) port install -N $(grep -v '^#' build/macos/all-deps-uni.txt | sed 's/|homebrew:[^ ]*//g' | tr -d '\' | xargs)
|
||||
git apply -v build/macos/patches/0001-meson-Patch-python-version.patch || true
|
||||
else
|
||||
brew upgrade --quiet
|
||||
brew install --quiet $(tr '\\' '\n' < build/macos/all-deps-uni.txt | grep -v '#' | sed -n 's/.*|homebrew://p' | awk '{print $1}' | xargs)
|
||||
git apply -v build/macos/patches/0001-build-macos-Do-not-require-gexiv2-0.14-on-homebrew.patch || true
|
||||
fi
|
||||
git apply -v build/macos/patches/0001-app-libgimpwidgets-meson-plug-ins-Patch-macOS-bundle.patch || true
|
||||
printf "\e[0Ksection_end:`date +%s`:deps_install\r\e[0K\n"
|
||||
|
||||
|
||||
# Prepare env (only GIMP_PREFIX is needed for flatpak)
|
||||
GIMP_DIR="$PWD"
|
||||
cd ${GIMP_DIR}${PARENT_DIR}
|
||||
|
||||
if [ -z "$GIMP_PREFIX" ]; then
|
||||
export GIMP_PREFIX="$PWD/_install"
|
||||
fi
|
||||
eval "$(sed -n -e 's/- //' -e '/macos_environ\[/,/macos_environ/p' $GIMP_DIR/.gitlab-ci.yml)"
|
||||
|
||||
|
||||
# Build some deps (including babl and GEGL)
|
||||
self_build()
|
||||
{
|
||||
dep=$(basename "$1" .git)
|
||||
printf "\e[0Ksection_start:`date +%s`:${dep}_build[collapsed=true]\r\e[0KBuilding $dep\n"
|
||||
if [ ! -d "$dep" ]; then
|
||||
git clone --depth $GIT_DEPTH --branch ${2:-master} $1
|
||||
fi
|
||||
cd $dep
|
||||
git pull
|
||||
|
||||
# Configure and build
|
||||
if [ ! -f "_build-$(uname -m)/build.ninja" ]; then
|
||||
meson setup _build-$(uname -m) -Dprefix="$GIMP_PREFIX" $PKGCONF_RELOCATABLE_OPTION \
|
||||
-Dbuildtype=debugoptimized \
|
||||
-Dc_args="-I${OPT_PREFIX}/include" -Dcpp_args="-I${OPT_PREFIX}/include" -Dc_link_args="-L${OPT_PREFIX}/lib" -Dcpp_link_args="-L${OPT_PREFIX}/lib"
|
||||
fi
|
||||
cd _build-$(uname -m)
|
||||
ninja
|
||||
ninja install
|
||||
cd ../..
|
||||
printf "\e[0Ksection_end:`date +%s`:${dep}_build\r\e[0K\n"
|
||||
}
|
||||
|
||||
self_build https://gitlab.gnome.org/GNOME/babl
|
||||
self_build https://gitlab.gnome.org/GNOME/gegl
|
||||
|
||||
cd $GIMP_DIR
|
||||
55
build/macos/2_build-gimp-macports.sh
Normal file
55
build/macos/2_build-gimp-macports.sh
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Ensure the script work properly
|
||||
case $(readlink /proc/$$/exe) in
|
||||
*bash)
|
||||
set -o posix
|
||||
;;
|
||||
esac
|
||||
set -e
|
||||
if [ "$0" != 'build/macos/2_build-gimp-macports.sh' ] && [ $(basename "$PWD") != 'macos' ]; then
|
||||
printf '\033[31m(ERROR)\033[0m: Script called from wrong dir. Please, call this script from the root of gimp git dir/\n'
|
||||
exit 1
|
||||
elif [ $(basename "$PWD") = 'macos' ]; then
|
||||
cd ../../..
|
||||
fi
|
||||
if [ -z "$GITLAB_CI" ]; then
|
||||
git submodule update --init
|
||||
|
||||
NON_RELOCATABLE_OPTION='-Drelocatable-bundle=no'
|
||||
fi
|
||||
|
||||
|
||||
# Install part of the deps (again)
|
||||
eval "$(sed -n '/Install part/,/End of config/p' build/macos/1_build-deps-macports.sh)"
|
||||
|
||||
if [ "$GITLAB_CI" ]; then
|
||||
eval "$(sed -n '/deps_install\[/,/deps_install/p' build/macos/1_build-deps-macports.sh)"
|
||||
fi
|
||||
|
||||
|
||||
# Prepare env (only GIMP_PREFIX is needed for flatpak)
|
||||
if [ -z "$GIMP_PREFIX" ]; then
|
||||
export GIMP_PREFIX="$PWD/../_install"
|
||||
fi
|
||||
eval "$(sed -n -e 's/- //' -e '/macos_environ\[/,/macos_environ/p' .gitlab-ci.yml)"
|
||||
|
||||
|
||||
# Build GIMP only
|
||||
printf "\e[0Ksection_start:`date +%s`:gimp_build[collapsed=true]\r\e[0KBuilding GIMP\n"
|
||||
if [ ! -f "_build-$(uname -m)/build.ninja" ]; then
|
||||
meson setup _build-$(uname -m) -Dprefix="$GIMP_PREFIX" $NON_RELOCATABLE_OPTION \
|
||||
$PKGCONF_RELOCATABLE_OPTION $DMG_OPTION \
|
||||
-Dbuild-id=org.gimp.GIMP_official \
|
||||
-Dc_args="-I${OPT_PREFIX}/include" -Dcpp_args="-I${OPT_PREFIX}/include" -Dc_link_args="-L${OPT_PREFIX}/lib" -Dcpp_link_args="-L${OPT_PREFIX}/lib"
|
||||
fi
|
||||
cd _build-$(uname -m)
|
||||
ninja
|
||||
printf "\e[0Ksection_end:`date +%s`:gimp_build\r\e[0K\n"
|
||||
|
||||
|
||||
# Bundle GIMP
|
||||
printf "\e[0Ksection_start:`date +%s`:gimp_bundle[collapsed=true]\r\e[0K$(if ! grep -q "dmg=true" meson-logs/meson-log.txt; then echo "Installing GIMP as non-relocatable on GIMP_PREFIX"; else echo "Creating .app bundle"; fi)\n"
|
||||
ninja install > ninja_install.log 2>&1 || { cat ninja_install.log; exit 1; };
|
||||
cd ..
|
||||
printf "\e[0Ksection_end:`date +%s`:gimp_bundle\r\e[0K\n"
|
||||
344
build/macos/2_bundle-gimp-uni_base.py
Normal file
344
build/macos/2_bundle-gimp-uni_base.py
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import stat
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from glob import glob
|
||||
|
||||
# This script is used to create a GIMP .app bundle on macOS. A bundle
|
||||
# is used as source of files for making the .dmg installer
|
||||
if not os.getenv("MESON_BUILD_ROOT"):
|
||||
# Let's prevent contributors from creating broken bundles
|
||||
print("\033[31m(ERROR)\033[0m: Script called standalone. Please build GIMP targeting DMG installer creation.")
|
||||
sys.exit(1)
|
||||
# Get variables from MESON_BUILD_ROOT/config.h that can be used on this script
|
||||
with open("config.h") as file:
|
||||
for line in file:
|
||||
match = re.match(r'^#\s*define\s+(\S+)(?:\s+(.*))?$', line)
|
||||
if match:
|
||||
key, value = match.groups()
|
||||
if value is None or not value.strip():
|
||||
value = "1" #needed when there is no explicit value
|
||||
else:
|
||||
value = value.strip().strip('"').strip("'")
|
||||
os.environ[key] = value
|
||||
if not os.getenv("ENABLE_RELOCATABLE_RESOURCES"):
|
||||
print("\n\033[31m(ERROR)\033[0m: No relocatable GIMP build found. You can build GIMP with '-Drelocatable-bundle=yes' to make a build suitable for .app creation.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Bundle deps and GIMP files
|
||||
GIMP_SOURCE = Path(os.getenv("MESON_SOURCE_ROOT"))
|
||||
|
||||
## System prefix: it is OPT_PREFIX (see 1_build-deps-macports)
|
||||
OPT_PREFIX = Path(os.getenv("OPT_PREFIX"))
|
||||
## GIMP prefix: as set at meson configure time
|
||||
GIMP_PREFIX = Path(os.getenv("MESON_INSTALL_DESTDIR_PREFIX"))
|
||||
|
||||
## Bundle dir: we make a "perfect" bundle separated from GIMP_PREFIX
|
||||
#NOTE: The bundling script need to set $OPT_PREFIX to our dist scripts
|
||||
#fallback code be able to identify what arch they are distributing
|
||||
GIMP_DISTRIB = Path(GIMP_SOURCE) / f"gimp-{platform.machine()}.app" / "Contents"
|
||||
|
||||
def bundle(src_root, pattern, option="None", override=None):
|
||||
## Search for targets in search path
|
||||
src_root = Path(src_root)
|
||||
paths_to_bundle = list(src_root.glob(pattern))
|
||||
if not paths_to_bundle:
|
||||
print(f"\033[31m(ERROR)\033[0m: not found {src_root}/{pattern}")
|
||||
sys.exit(1)
|
||||
for src_path in paths_to_bundle:
|
||||
## Copy found targets to bundle path
|
||||
symlink_cleanup = True
|
||||
if "--dest" in option:
|
||||
dest_path = GIMP_DISTRIB / Path(override) / src_path.name
|
||||
elif "--rename" in option:
|
||||
dest_path = GIMP_DISTRIB / Path(override)
|
||||
elif "bin/" in pattern:
|
||||
symlink_cleanup = False
|
||||
dest_path = GIMP_DISTRIB / "MacOS" / Path(src_path.relative_to(src_root)).name
|
||||
elif "lib/" in pattern:
|
||||
dest_path = GIMP_DISTRIB / "Frameworks" / src_path.relative_to(src_root / "lib")
|
||||
elif "share/" in pattern:
|
||||
dest_path = GIMP_DISTRIB / "Resources" / src_path.relative_to(src_root / "share")
|
||||
elif "etc/" in pattern:
|
||||
dest_path = GIMP_DISTRIB / "SharedSupport" / src_path.relative_to(src_root / "etc")
|
||||
dest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
print(f"Bundling {src_path} to {dest_path.parent}")
|
||||
if src_path.is_dir():
|
||||
try:
|
||||
shutil.copytree(src_path, dest_path, dirs_exist_ok=True)
|
||||
except shutil.Error as e:
|
||||
print(f"\033[33m(WARNING)\033[0m: {dest_path} seems to already exist and have permission problems")
|
||||
else:
|
||||
if not str(src_path).endswith(".typelib"):
|
||||
try:
|
||||
shutil.copy2(src_path, dest_path, follow_symlinks=symlink_cleanup)
|
||||
except shutil.Error as e:
|
||||
print(f"\033[33m(WARNING)\033[0m: {dest_path} seems to already exist and have permission problems")
|
||||
if "MacOS/" in str(dest_path) and not dest_path.is_symlink():
|
||||
os.chmod(dest_path, 0o755)
|
||||
else:
|
||||
## Process .typelib dependencies (as relocatable)
|
||||
tmp_gir_dir = GIMP_DISTRIB / "tmp"
|
||||
tmp_gir_dir.mkdir(parents=True, exist_ok=True)
|
||||
def set_typelib_rpath(typelib, prefix):
|
||||
typelib_path = Path(f"{prefix}/lib/girepository-1.0/{typelib}.typelib")
|
||||
target_path = dest_path.parent / typelib_path.name
|
||||
if typelib_path.exists() and not target_path.exists():
|
||||
if typelib_path != src_path:
|
||||
print(f"Bundling {typelib_path} to {dest_path.parent}")
|
||||
tmp_gir_path = Path(f"{tmp_gir_dir}/{typelib}.gir")
|
||||
shutil.copy2(Path(f"{prefix}/share/gir-1.0/{typelib}.gir"), tmp_gir_path)
|
||||
text = tmp_gir_path.read_text()
|
||||
text = re.sub(r'shared-library="([^"]+)"', lambda m: 'shared-library="' + ",".join("@rpath/" + os.path.basename(p) for p in m.group(1).split(",")) + '"', text)
|
||||
tmp_gir_path.write_text(text)
|
||||
subprocess.run(["g-ir-compiler", f"--includedir={tmp_gir_dir}", str(tmp_gir_path), "-o", target_path], check=True)
|
||||
def process_typelib(path, typelib_list=None):
|
||||
set_typelib_rpath(Path(path).stem, GIMP_PREFIX)
|
||||
if typelib_list is None:
|
||||
typelib_list = set()
|
||||
cmd = ['g-ir-inspect', '--print-typelibs', os.path.basename(path).split('-')[0]]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
for line in result.stdout.splitlines():
|
||||
typelib = line.replace("typelib: ", "").strip()
|
||||
if typelib and typelib not in typelib_list:
|
||||
typelib_list.add(typelib)
|
||||
for prefix in [GIMP_PREFIX, OPT_PREFIX]:
|
||||
typelib_path = Path(f"{prefix}/lib/girepository-1.0/{typelib}.typelib")
|
||||
target_path = dest_path.parent / typelib_path.name
|
||||
if typelib_path.exists() and not target_path.exists():
|
||||
set_typelib_rpath(typelib, prefix)
|
||||
process_typelib(typelib, typelib_list)
|
||||
process_typelib(src_path)
|
||||
shutil.rmtree(tmp_gir_dir)
|
||||
|
||||
def clean(base_path, pattern):
|
||||
base_path = Path(base_path)
|
||||
first_found = False
|
||||
for parent_path in base_path.glob(os.path.dirname(pattern)):
|
||||
for path in parent_path.rglob(os.path.basename(pattern)):
|
||||
if path.exists():
|
||||
if not first_found:
|
||||
print(f"Cleaning {base_path}/{pattern}")
|
||||
first_found = True
|
||||
if path.is_dir():
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
path.unlink()
|
||||
|
||||
|
||||
## PREPARE BUNDLE
|
||||
GIMP_DISTRIB.mkdir(parents=True, exist_ok=True)
|
||||
### Prevent Git going crazy
|
||||
(GIMP_DISTRIB / ".." / ".gitignore").write_text("*\n")
|
||||
### Configure Info.plist
|
||||
text = (GIMP_SOURCE / "build/macos/Info.plist").read_text()
|
||||
if not os.getenv("GIMP_RELEASE") or os.getenv("GIMP_IS_RC_GIT"):
|
||||
BUNDLE_IDENTIFIER = "org.gimp.gimp.internal"
|
||||
BUNDLE_NAME = "GIMP (Nightly)"
|
||||
MUTEX_SUFFIX = ""
|
||||
elif (os.getenv("GIMP_RELEASE") and os.getenv("GIMP_UNSTABLE")) or os.getenv("GIMP_RC_VERSION"):
|
||||
BUNDLE_IDENTIFIER = "org.gimp.gimp.seed"
|
||||
BUNDLE_NAME = "GIMP (Beta)"
|
||||
MUTEX_SUFFIX = f"-{os.getenv('GIMP_MUTEX_VERSION')}"
|
||||
else:
|
||||
BUNDLE_IDENTIFIER = "org.gimp.gimp"
|
||||
BUNDLE_NAME = "GIMP"
|
||||
MUTEX_SUFFIX = f"-{os.getenv('GIMP_MUTEX_VERSION')}"
|
||||
new_text = text.replace("%BUNDLE_IDENTIFIER%", BUNDLE_IDENTIFIER)
|
||||
new_text = new_text.replace("%BUNDLE_NAME%", BUNDLE_NAME)
|
||||
new_text = new_text.replace("%GIMP_VERSION%", os.getenv("GIMP_VERSION"))
|
||||
new_text = new_text.replace("%MUTEX_SUFFIX%", MUTEX_SUFFIX)
|
||||
(GIMP_DISTRIB / "Info.plist").write_text(new_text)
|
||||
### FIXME: Icon (generate Assets.car for Liquid Glass)
|
||||
(GIMP_DISTRIB / "Resources").mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(Path(f"{os.getenv('MESON_BUILD_ROOT')}/gimp-data/images/logo/gimp.icns"), GIMP_DISTRIB / "Resources/AppIcon.icns")
|
||||
|
||||
|
||||
## BUNDLE BASE (BARE MINIMUM TO RUN GTK APPS).
|
||||
### FIXME: Needed for 'Send to Email' support (should be on sendmail.c source)
|
||||
bundle(GIMP_SOURCE, "build/macos/patches/xdg-email", "--dest", "MacOS")
|
||||
### Needed for file dialogs (only .compiled file is needed on macOS)
|
||||
bundle(OPT_PREFIX, "share/glib-*/schemas/gschemas.compiled")
|
||||
### Needed to open remote files
|
||||
if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
bundle(OPT_PREFIX, "lib/libproxy/libpxbackend*.dylib", "--dest", "Frameworks")
|
||||
bundle(OPT_PREFIX, "lib/gio")
|
||||
### Needed to not crash UI. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/6165
|
||||
bundle(OPT_PREFIX, "share/icons/Adwaita")
|
||||
### Needed by GTK to use icon themes. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/5080
|
||||
bundle(GIMP_PREFIX, "share/icons/hicolor")
|
||||
### Needed to loading icons in GUI
|
||||
bundle(OPT_PREFIX, "lib/gdk-pixbuf-*/*/loaders/libpixbufloader*svg*")
|
||||
bundle(OPT_PREFIX, "lib/gdk-pixbuf-*/*/loaders.cache")
|
||||
loaders_cache = glob(f"{GIMP_DISTRIB}/Frameworks/gdk-pixbuf-*/*/loaders.cache")
|
||||
text = Path(loaders_cache[0]).read_text()
|
||||
new_text = text.replace(f"{OPT_PREFIX}/lib/", "")
|
||||
Path(loaders_cache[0]).write_text(new_text)
|
||||
### Needed for printing support
|
||||
bundle(OPT_PREFIX, "lib/gtk-3.0/*.*.*/printbackends/*.so")
|
||||
### Needed for macOS emoji keyboard support (with im-quartz.so)
|
||||
bundle(OPT_PREFIX, "lib/gtk-3.0/*.*.*/immodules/*.so")
|
||||
if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
bundle(OPT_PREFIX, "etc/gtk-3.0/gtk.immodules", "--rename", "Frameworks/gtk-3.0/3.0.0/immodules.cache")
|
||||
else: #os.path.exists(OPT_PREFIX / "bin/brew"):
|
||||
bundle(OPT_PREFIX, "lib/gtk-3.0/*.*.*/immodules.cache")
|
||||
im_cache = glob(f"{GIMP_DISTRIB}/Frameworks/gtk-3.0/*.*.*/immodules.cache")
|
||||
text = Path(im_cache[0]).read_text()
|
||||
new_text = re.sub(r'/.*?(?=gtk-3\.0/)', '', text)
|
||||
Path(im_cache[0]).write_text(new_text)
|
||||
### Needed for MacOS-style keyboard shortcuts
|
||||
bundle(OPT_PREFIX, "share/themes/Mac")
|
||||
|
||||
|
||||
## CORE FEATURES.
|
||||
bundle(GIMP_PREFIX, "lib/libbabl*-*.*.*.dylib")
|
||||
bundle(GIMP_PREFIX, "lib/babl-*")
|
||||
bundle(GIMP_PREFIX, "lib/libgegl*-*.*.*.dylib")
|
||||
bundle(GIMP_PREFIX, "lib/gegl-*")
|
||||
bundle(GIMP_PREFIX, "lib/libgimp*-*.*.*.dylib")
|
||||
bundle(GIMP_PREFIX, "lib/gimp")
|
||||
bundle(GIMP_PREFIX, "share/gimp")
|
||||
lang_array = [Path(f).stem for f in glob(str(Path(GIMP_SOURCE)/"po/*.po"))]
|
||||
for lang in lang_array:
|
||||
bundle(GIMP_PREFIX, f"share/locale/{lang}/LC_MESSAGES/*.mo")
|
||||
# Needed for eventually used widgets, GTK inspector etc
|
||||
if glob(f"{OPT_PREFIX}/share/locale/{lang}/LC_MESSAGES/gtk*.mo"):
|
||||
bundle(OPT_PREFIX, f"share/locale/{lang}/LC_MESSAGES/gtk*.mo")
|
||||
# For language list in text tool options
|
||||
if glob(f"{OPT_PREFIX}/share/locale/{lang}/LC_MESSAGES/iso_639_3.mo"):
|
||||
bundle(OPT_PREFIX, f"share/locale/{lang}/LC_MESSAGES/iso_639_3.mo")
|
||||
bundle(GIMP_PREFIX, "etc/gimp")
|
||||
|
||||
|
||||
## OTHER FEATURES AND PLUG-INS.
|
||||
### Support for non .PAT patterns: https://gitlab.gnome.org/GNOME/gimp/-/issues/12351
|
||||
bundle(OPT_PREFIX, "lib/gdk-pixbuf-*/*/loaders/libpixbufloader-bmp*")
|
||||
bundle(OPT_PREFIX, "lib/gdk-pixbuf-*/*/loaders/libpixbufloader-gif*")
|
||||
bundle(OPT_PREFIX, "lib/gdk-pixbuf-*/*/loaders/libpixbufloader-tiff*")
|
||||
### FIXME: mypaint brushes (needs patching https://github.com/Homebrew/homebrew-core/pull/262039)
|
||||
bundle(OPT_PREFIX, "share/mypaint-data/2.0")
|
||||
### Needed for fontconfig
|
||||
bundle(OPT_PREFIX, "etc/fonts")
|
||||
#### Avoid writing in the system and avoid other programs breaking the cache
|
||||
fonts_conf = GIMP_DISTRIB / "SharedSupport/fonts/fonts.conf"
|
||||
text = fonts_conf.read_text()
|
||||
new_text = text.replace(
|
||||
f"{os.getenv('OPT_PREFIX')}/var",
|
||||
f"~/Library/Application Support/GIMP/{os.getenv('GIMP_APP_VERSION')}"
|
||||
)
|
||||
fonts_conf.write_text(new_text)
|
||||
### FIXME: Needed for 'th' word breaking in Text tool etc (https://github.com/macports/macports-ports/pull/30702 e https://github.com/Homebrew/homebrew-core/pull/262071)
|
||||
#if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
#bundle(OPT_PREFIX, "share/libthai")
|
||||
### Needed for full CJK and Cyrillic support in file-pdf
|
||||
bundle(OPT_PREFIX, "share/poppler")
|
||||
#### Needed for signature support in file-pdf lib
|
||||
if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
bundle(OPT_PREFIX, "lib/nss/libssl3.dylib", "--dest", "Frameworks")
|
||||
bundle(OPT_PREFIX, "lib/nss/libsmime3.dylib", "--dest", "Frameworks")
|
||||
bundle(OPT_PREFIX, "lib/nss/libnssutil3.dylib", "--dest", "Frameworks")
|
||||
bundle(OPT_PREFIX, "lib/nss/libnss3.dylib", "--dest", "Frameworks")
|
||||
bundle(OPT_PREFIX, "lib/nspr/*.dylib", "--dest", "Frameworks")
|
||||
### FIXME: Needed for file-ps work (but maintaining GS_LIB on app/main.c is tough)
|
||||
if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
bundle(OPT_PREFIX, "share/ghostscript/1*/iccprofiles/*.icc", "--dest", "Resources/ghostscript/iccprofiles")
|
||||
bundle(OPT_PREFIX, "share/ghostscript/1*/Resource/Init/*", "--dest", "Resources/ghostscript/Resource/Init")
|
||||
bundle(OPT_PREFIX, "share/ghostscript/1*/Resource/Font/*", "--dest", "Resources/ghostscript/Resource/Font")
|
||||
else: #os.path.exists(OPT_PREFIX / "bin/brew"):
|
||||
bundle(OPT_PREFIX, "share/ghostscript/iccprofiles/*.icc")
|
||||
bundle(OPT_PREFIX, "share/ghostscript/Resource/Init")
|
||||
bundle(OPT_PREFIX, "share/ghostscript/Resource/Font")
|
||||
### Needed for file-wmf work
|
||||
if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
bundle(OPT_PREFIX, "share/fonts/libwmf/*", "--dest", "Resources/libwmf/fonts")
|
||||
else: #os.path.exists(OPT_PREFIX / "bin/brew"):
|
||||
bundle(OPT_PREFIX, "Cellar/libwmf/*/share/libwmf/fonts/*", "--dest", "Resources/libwmf/fonts")
|
||||
### Needed for 'Show image graph'.
|
||||
#### See: https://gitlab.gnome.org/GNOME/gimp/-/issues/6045
|
||||
bundle(OPT_PREFIX, "bin/dot", "--dest", "MacOS")
|
||||
#### See: https://gitlab.gnome.org/GNOME/gimp/-/issues/12119
|
||||
bundle(OPT_PREFIX, "lib/graphviz/libgvplugin_dot*.dylib")
|
||||
bundle(OPT_PREFIX, "lib/graphviz/libgvplugin_pango*.dylib")
|
||||
bundle(OPT_PREFIX, "lib/graphviz/config*")
|
||||
### Binaries for GObject Introspection support. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/13170
|
||||
bundle(GIMP_PREFIX, "lib/girepository-*/*.typelib")
|
||||
bundle(OPT_PREFIX, "lib/libgirepository-*.dylib")
|
||||
#### Python support
|
||||
bundle(OPT_PREFIX, f"bin/python{os.getenv('PYTHON_VERSION')}", "--rename", "MacOS/python3")
|
||||
if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
bundle(OPT_PREFIX, f"Library/Frameworks/Python.framework/Versions/{os.getenv('PYTHON_VERSION')}", "--dest", "Frameworks/Python.framework/Versions")
|
||||
else: #os.path.exists(OPT_PREFIX / "bin/brew"):
|
||||
bundle(OPT_PREFIX, f"Frameworks/Python.framework/Versions/{os.getenv('PYTHON_VERSION')}", "--dest", "Frameworks/Python.framework/Versions")
|
||||
bundle(OPT_PREFIX, f"lib/python{os.getenv('PYTHON_VERSION')}/site-packages/*", "--dest", f"Frameworks/Python.framework/Versions/{os.getenv('PYTHON_VERSION')}/lib/python{os.getenv('PYTHON_VERSION')}/site-packages")
|
||||
clean(GIMP_DISTRIB, "Frameworks/Python.framework/*.pyc")
|
||||
#####Needed for internet connection on python. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/14722
|
||||
pythonpath = Path(f"{GIMP_DISTRIB}/Frameworks/Python.framework/Versions/{os.getenv('PYTHON_VERSION')}/lib/python{os.getenv('PYTHON_VERSION')}")
|
||||
for d in (pythonpath, pythonpath / "site-packages"):
|
||||
sitecustomize = d / "sitecustomize.py"
|
||||
code = """\nimport os\nimport certifi\n\n# Only set if not already configured by user\nif not os.environ.get('SSL_CERT_FILE'):\n os.environ['SSL_CERT_FILE'] = certifi.where()\n"""
|
||||
if sitecustomize.exists() and code.strip() not in sitecustomize.read_text():
|
||||
sitecustomize.write_text(sitecustomize.read_text() + code)
|
||||
elif not sitecustomize.exists():
|
||||
sitecustomize.write_text(code)
|
||||
#####Needed since we use [[NSBundle mainBundle] bundlePath] on libgimpbase/gimpenv.c
|
||||
real_path = Path(f"{GIMP_DISTRIB}/Resources/icons")
|
||||
link_path = Path(f"{GIMP_DISTRIB}/Frameworks/Python.framework/Versions/{os.getenv('PYTHON_VERSION')}/Resources/Python.app/Contents/Resources/icons")
|
||||
link_path.symlink_to(os.path.relpath(real_path, link_path.parent))
|
||||
#### lua is buggy, and hard to bundle due to LUA_*PATH etc (see AppImage script)
|
||||
#if os.path.exists(OPT_PREFIX / "bin/port"):
|
||||
#bundle(OPT_PREFIX, "bin/luajit", "--dest", "MacOS")
|
||||
#bundle(OPT_PREFIX, "lib/lua")
|
||||
#bundle(OPT_PREFIX, "share/lua")
|
||||
|
||||
|
||||
## MAIN EXECUTABLES AND DEPENDENCIES
|
||||
### Minimal (and some additional) executables for the 'MacOS' folder
|
||||
bundle(GIMP_PREFIX, "bin/gimp*")
|
||||
if os.path.exists(OPT_PREFIX / "bin/brew"):
|
||||
bundle(OPT_PREFIX, "Cellar/libarchive/*/lib/libarchive.*.dylib", "--dest", "Frameworks")
|
||||
### Bundled just to promote GEGL. See: https://gitlab.gnome.org/GNOME/gimp/-/issues/10580
|
||||
bundle(GIMP_PREFIX, "bin/gegl")
|
||||
### Deps (DYLIBs) of the binaries in 'MacOS' and 'Frameworks' dirs
|
||||
### We save the list of already copied DLLs to keep a state between 2_bundle-gimp-uni_dep runs.
|
||||
done_dylib = Path(f"{os.getenv('MESON_BUILD_ROOT')}/done-dylib.list")
|
||||
done_dylib.unlink(missing_ok=True)
|
||||
for dir in ["MacOS", "Frameworks"]:
|
||||
search_dir = GIMP_DISTRIB / dir
|
||||
print(f"Searching for dependencies of {search_dir} in {GIMP_PREFIX} and {OPT_PREFIX}")
|
||||
for dep in search_dir.rglob("*"):
|
||||
if "Mach-O" in subprocess.run(["file", str(dep)], capture_output=True, text=True).stdout and ".dSYM" not in str(dep):
|
||||
subprocess.run([
|
||||
sys.executable, f"{GIMP_SOURCE}/tools/lib_bundle.py",
|
||||
str(dep), f"{GIMP_PREFIX}/", f"{OPT_PREFIX}/",
|
||||
str(GIMP_DISTRIB), "--output-dll-list", done_dylib
|
||||
], check=True)
|
||||
|
||||
|
||||
## .DSYM/DWARF DEBUG SYMBOLS (from babl, gegl and GIMP binaries)
|
||||
for dir in ["MacOS", "Frameworks"]:
|
||||
search_dir = GIMP_DISTRIB / dir
|
||||
for binary in search_dir.rglob("*"):
|
||||
if "Mach-O" in subprocess.run(["file", str(binary)], capture_output=True, text=True).stdout and ".dSYM" not in str(binary) and not binary.is_symlink():
|
||||
result = subprocess.run(["dsymutil", "--no-output", binary], capture_output=True, text=True)
|
||||
if not "no debug symbols" in result.stdout + result.stderr:
|
||||
print(f"(INFO): generating debug symbols file as {binary}.dSYM")
|
||||
try:
|
||||
subprocess.run(["dsymutil", binary, "-o", f"{binary}.dSYM"], check=True, stderr=subprocess.DEVNULL)
|
||||
except subprocess.CalledProcessError as e:
|
||||
sys.stderr.write(f"Failed to generate debug symbols from {binary}: {e}\n")
|
||||
|
||||
|
||||
## FIXME: DEVELOPMENT FILES (bundle babl, gegl and gimp libs as .framework with Headers/ ?).
|
||||
#clean(GIMP_DISTRIB, "lib/*.a")
|
||||
#bundle(GIMP_PREFIX, "include/gimp-*")
|
||||
#bundle(GIMP_PREFIX, "include/babl-*")
|
||||
#bundle(GIMP_PREFIX, "include/gegl-*")
|
||||
#bundle(GIMP_PREFIX, "lib/pkgconfig/gimp*")
|
||||
#bundle(GIMP_PREFIX, "lib/pkgconfig/babl*")
|
||||
#bundle(GIMP_PREFIX, "lib/pkgconfig/gegl*")
|
||||
43
build/macos/Info.plist
Normal file
43
build/macos/Info.plist
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>gimp%MUTEX_SUFFIX%</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>AppIcon.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>%BUNDLE_IDENTIFIER%</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>%BUNDLE_NAME%</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>%GIMP_VERSION%</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>GIMP</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>%GIMP_VERSION%</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© The GIMP Team</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.photography</string>
|
||||
<!--keep LSMinimumSystemVersion consistent with devel-docs/os-support.txt-->
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>14.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSRequiresAquaSystemAppearance</key>
|
||||
<false/>
|
||||
<key>NLSRequiresNativeExecution</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
## macOS files not here
|
||||
## Note about macOS build situation
|
||||
|
||||
macOS build files are not stored here yet.
|
||||
These macOS build files on GIMP repo do not fully support older macOS yet.
|
||||
You can use them only the latest 3 versions of macOS.
|
||||
|
||||
They are in: [gimp-macos-build](https://gitlab.gnome.org/Infrastructure/gimp-macos-build) repo.
|
||||
The build files for older macOS are in: [gimp-macos-build]
|
||||
(https://gitlab.gnome.org/Infrastructure/gimp-macos-build) repo.
|
||||
|
|
|
|||
50
build/macos/all-deps-uni.txt
Normal file
50
build/macos/all-deps-uni.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# For easier quality of life and to avoid disparity between pacakges,
|
||||
# KEEP THIS FILE ORDERING SIMILAR to build/windows/all-deps-uni.txt
|
||||
|
||||
# BUILD-TIME ONLY DEPS
|
||||
gettext \
|
||||
gi-docgen \
|
||||
gobject-introspection +quartz -x11|homebrew:gobject-introspection \
|
||||
libxslt|homebrew:libxslt \
|
||||
meson|homebrew:meson \
|
||||
pkgconfig|homebrew:pkgconf \
|
||||
vala -valadoc \
|
||||
|
||||
# RUNTIME DEPS
|
||||
aalib -x11 \
|
||||
appstream -x11|homebrew:appstream \
|
||||
atk \
|
||||
cairo +quartz -x11|homebrew:cairo \
|
||||
#cfitsio not built by Apple Clang
|
||||
gexiv2|homebrew:gexiv2 \
|
||||
ghostscript -x11|homebrew:ghostscript \
|
||||
glib2 +quartz -x11|homebrew:glib \
|
||||
glib-networking|homebrew:glib-networking \
|
||||
graphviz -x11|homebrew:graphviz \
|
||||
gtk3 +quartz -x11|homebrew:gtk+3 \ adwaita-icon-theme +quartz -x11|homebrew:adwaita-icon-theme \ shared-mime-info|homebrew:shared-mime-info \
|
||||
iso-codes|homebrew:iso-codes \
|
||||
json-glib|homebrew:json-glib \
|
||||
lcms2|homebrew:lcms2 \
|
||||
libarchive|homebrew:libarchive \
|
||||
libheif \
|
||||
libjpeg-turbo|homebrew:libjpeg-turbo \
|
||||
libjxl \
|
||||
libmng \
|
||||
libmypaint \
|
||||
libpng|homebrew:libpng \
|
||||
librsvg|homebrew:librsvg \
|
||||
tiff \
|
||||
webp \
|
||||
libwmf -x11|homebrew:libwmf \
|
||||
#maxflow not available yet
|
||||
mypaint-brushes|homebrew:mypaint-brushes \
|
||||
openexr \
|
||||
openjpeg \
|
||||
pango +quartz -x11 \
|
||||
poppler|homebrew:poppler \
|
||||
poppler-data \
|
||||
python313|homebrew:python \ py313-certifi|homebrew:certifi
|
||||
py313-gobject3|homebrew:pygobject3 \
|
||||
qoi \
|
||||
#suitesparse not built by Apple Clang
|
||||
#xpm depends on x11
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
From fc8868bdd2900e6bc1399dc336d73ac1c27e60f5 Mon Sep 17 00:00:00 2001
|
||||
From: Bruno Lopes <brunvonlope@outlook.com>
|
||||
Date: Tue, 6 Jan 2026 09:59:35 -0300
|
||||
Subject: [PATCH] app, libgimpwidgets, meson, plug-ins: Patch macOS bundle
|
||||
|
||||
This is needed because our current code assumes that
|
||||
the prefix is .app/Contents/Resources, which should not.
|
||||
---
|
||||
app/config/gimpcoreconfig.c | 2 +-
|
||||
app/main.c | 39 +++++++++++++---------------
|
||||
libgimpbase/gimpenv.c | 12 +++++----
|
||||
libgimpwidgets/gimpwidgets-private.c | 2 +-
|
||||
meson.build | 2 +-
|
||||
plug-ins/common/file-wmf.c | 4 +--
|
||||
6 files changed, 30 insertions(+), 31 deletions(-)
|
||||
|
||||
diff --git a/app/config/gimpcoreconfig.c b/app/config/gimpcoreconfig.c
|
||||
index a4591055d6..853cf99f10 100644
|
||||
--- a/app/config/gimpcoreconfig.c
|
||||
+++ b/app/config/gimpcoreconfig.c
|
||||
@@ -311,7 +311,7 @@ gimp_core_config_class_init (GimpCoreConfigClass *klass)
|
||||
|
||||
#ifdef ENABLE_RELOCATABLE_RESOURCES
|
||||
mypaint_brushes = g_build_filename ("${gimp_installation_dir}",
|
||||
- "share", "mypaint-data",
|
||||
+ "Resources", "mypaint-data",
|
||||
"2.0", "brushes", NULL);
|
||||
#else
|
||||
mypaint_brushes = g_strdup (MYPAINT_BRUSHES_DIR);
|
||||
diff --git a/app/main.c b/app/main.c
|
||||
index d577dd0b04..b0c326ac5c 100644
|
||||
--- a/app/main.c
|
||||
+++ b/app/main.c
|
||||
@@ -355,13 +355,13 @@ gimp_macos_setenv (const char * progname)
|
||||
gboolean need_pythonhome = TRUE;
|
||||
|
||||
bin_dir = g_path_get_dirname (resolved_path);
|
||||
- tmp = g_strdup_printf ("%s/../Resources/lib", bin_dir);
|
||||
+ tmp = g_strdup_printf ("%s/../Frameworks", bin_dir);
|
||||
lib_dir = g_canonicalize_filename (tmp, NULL);
|
||||
g_free (tmp);
|
||||
- tmp = g_strdup_printf ("%s/../Resources/share", bin_dir);
|
||||
+ tmp = g_strdup_printf ("%s/../Resources", bin_dir);
|
||||
share_dir = g_canonicalize_filename (tmp, NULL);
|
||||
g_free (tmp);
|
||||
- tmp = g_strdup_printf ("%s/../Resources/etc", bin_dir);
|
||||
+ tmp = g_strdup_printf ("%s/../SharedSupport", bin_dir);
|
||||
etc_dir = g_canonicalize_filename (tmp, NULL);
|
||||
g_free (tmp);
|
||||
|
||||
@@ -392,23 +392,6 @@ gimp_macos_setenv (const char * progname)
|
||||
}
|
||||
}
|
||||
|
||||
- /* Detect we were built in homebrew for MacOS (for PYTHONHOME purposes) */
|
||||
- tmp = g_strdup_printf ("%s/../Frameworks/Python.framework", share_dir);
|
||||
- if (tmp && !stat (tmp, &sb) && S_ISDIR (sb.st_mode))
|
||||
- {
|
||||
- g_print ("GIMP was built with homebrew\n");
|
||||
- need_pythonhome = FALSE;
|
||||
- }
|
||||
- g_free (tmp);
|
||||
- /* Detect we were built in MacPorts for MacOS (for PYTHONHOME purposes) */
|
||||
- tmp = g_strdup_printf ("%s/../Library/Frameworks/Python.framework", share_dir);
|
||||
- if (tmp && !stat (tmp, &sb) && S_ISDIR (sb.st_mode))
|
||||
- {
|
||||
- g_print ("GIMP was built with MacPorts\n");
|
||||
- need_pythonhome = FALSE;
|
||||
- }
|
||||
- g_free (tmp);
|
||||
-
|
||||
/* Minimum runtime paths */
|
||||
path_len = strlen (g_getenv ("PATH") ? g_getenv ("PATH") : "") + strlen (bin_dir) + 2;
|
||||
path = g_try_malloc (path_len);
|
||||
@@ -461,6 +444,20 @@ gimp_macos_setenv (const char * progname)
|
||||
g_setenv ("GTK_IM_MODULE", tmp, TRUE);
|
||||
g_free (tmp);
|
||||
|
||||
+ /* Packaging-specific paths */
|
||||
+ tmp = g_strdup_printf ("%s/%s/%s", lib_dir, GIMP_PACKAGE, GIMP_PLUGIN_VERSION);
|
||||
+ g_setenv ("GIMP3_PLUGINDIR", tmp, TRUE);
|
||||
+ g_free (tmp);
|
||||
+ tmp = g_strdup_printf ("%s/%s/%s", share_dir, GIMP_PACKAGE, GIMP_DATA_VERSION);
|
||||
+ g_setenv ("GIMP3_DATADIR", tmp, TRUE);
|
||||
+ g_free (tmp);
|
||||
+ tmp = g_strdup_printf ("%s/locale", share_dir);
|
||||
+ g_setenv ("GIMP3_LOCALEDIR", tmp, TRUE);
|
||||
+ g_free (tmp);
|
||||
+ tmp = g_strdup_printf ("%s/%s/%s", etc_dir, GIMP_PACKAGE, GIMP_SYSCONF_VERSION);
|
||||
+ g_setenv ("GIMP3_SYSCONFDIR", tmp, TRUE);
|
||||
+ g_free (tmp);
|
||||
+
|
||||
/* Other needed runtime paths (related to features) */
|
||||
tmp = g_strdup_printf ("%s/fonts", etc_dir);
|
||||
g_setenv ("FONTCONFIG_PATH", tmp, TRUE);
|
||||
@@ -479,7 +476,7 @@ gimp_macos_setenv (const char * progname)
|
||||
g_free (tmp);
|
||||
if (need_pythonhome)
|
||||
{
|
||||
- tmp = g_strdup_printf ("%s/Library/Frameworks/Python.framework/Versions/%s", share_dir, PYTHON_VERSION);
|
||||
+ tmp = g_strdup_printf ("%s/Python.framework/Versions/%s", lib_dir, PYTHON_VERSION);
|
||||
g_setenv ("PYTHONHOME", tmp, TRUE);
|
||||
g_free (tmp);
|
||||
}
|
||||
diff --git a/libgimpbase/gimpenv.c b/libgimpbase/gimpenv.c
|
||||
index 0af4f2f653..7293fe4bb1 100644
|
||||
--- a/libgimpbase/gimpenv.c
|
||||
+++ b/libgimpbase/gimpenv.c
|
||||
@@ -415,17 +415,18 @@ gimp_installation_directory (void)
|
||||
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
- NSString *resource_path;
|
||||
+ NSString *app_path;
|
||||
+ gchar *app_gpath;
|
||||
gchar *basename;
|
||||
gchar *basepath;
|
||||
gchar *dirname;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
- resource_path = [[NSBundle mainBundle] resourcePath];
|
||||
+ app_path = [[NSBundle mainBundle] bundlePath];
|
||||
|
||||
- basename = g_path_get_basename ([resource_path UTF8String]);
|
||||
- basepath = g_path_get_dirname ([resource_path UTF8String]);
|
||||
+ basename = g_path_get_basename ([app_path UTF8String]);
|
||||
+ basepath = g_path_get_dirname ([app_path UTF8String]);
|
||||
dirname = g_path_get_basename (basepath);
|
||||
|
||||
if (! strcmp (basename, ".libs"))
|
||||
@@ -488,7 +489,8 @@ gimp_installation_directory (void)
|
||||
{
|
||||
/* if none of the above match, we assume that we are really in a bundle */
|
||||
|
||||
- toplevel = g_strdup ([resource_path UTF8String]);
|
||||
+ app_gpath = g_strdup ([app_path UTF8String]);
|
||||
+ toplevel = g_strconcat (app_gpath, "/Contents", NULL);
|
||||
}
|
||||
|
||||
g_free (basename);
|
||||
diff --git a/libgimpwidgets/gimpwidgets-private.c b/libgimpwidgets/gimpwidgets-private.c
|
||||
index 0ebe7fa7e0..c7ab6d6950 100644
|
||||
--- a/libgimpwidgets/gimpwidgets-private.c
|
||||
+++ b/libgimpwidgets/gimpwidgets-private.c
|
||||
@@ -97,7 +97,7 @@ gimp_widgets_init (GimpHelpFunc standard_help_func,
|
||||
{
|
||||
cat_dir = "apps";
|
||||
#ifdef ENABLE_RELOCATABLE_RESOURCES
|
||||
- base_dir = g_build_filename (gimp_installation_directory (), "share", "icons", "hicolor", NULL);
|
||||
+ base_dir = g_build_filename (gimp_installation_directory (), "Resources", "icons", "hicolor", NULL);
|
||||
#else
|
||||
base_dir = g_build_filename (DATAROOTDIR, "icons", "hicolor", NULL);
|
||||
#endif
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 9614be6197..b18955cdf9 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -536,7 +536,7 @@ mypaint_brushes = dependency('mypaint-brushes-2.0')
|
||||
|
||||
if relocatable_bundle
|
||||
mypaint_brushes_dir = '${gimp_installation_dir}'\
|
||||
- /'share'/'mypaint-data'/'2.0'/'brushes'
|
||||
+ /'Resources'/'mypaint-data'/'2.0'/'brushes'
|
||||
else
|
||||
mypaint_brushes_dir = mypaint_brushes.get_variable(pkgconfig: 'brushesdir')
|
||||
endif
|
||||
diff --git a/plug-ins/common/file-wmf.c b/plug-ins/common/file-wmf.c
|
||||
index 62c33ab221..b7517e0624 100644
|
||||
--- a/plug-ins/common/file-wmf.c
|
||||
+++ b/plug-ins/common/file-wmf.c
|
||||
@@ -382,7 +382,7 @@ load_wmf_size (GFile *file,
|
||||
|
||||
#ifdef ENABLE_RELOCATABLE_RESOURCES
|
||||
wmffontdirs[0] = g_build_filename (gimp_installation_directory (),
|
||||
- "share/libwmf/fonts", NULL);
|
||||
+ "Resources/libwmf/fonts", NULL);
|
||||
flags |= WMF_OPT_FONTDIRS;
|
||||
api_options.fontdirs = wmffontdirs;
|
||||
#endif
|
||||
@@ -529,7 +529,7 @@ wmf_load_file (GFile *file,
|
||||
|
||||
#ifdef ENABLE_RELOCATABLE_RESOURCES
|
||||
wmffontdirs[0] = g_build_filename (gimp_installation_directory (),
|
||||
- "share/libwmf/fonts/", NULL);
|
||||
+ "Resources/libwmf/fonts/", NULL);
|
||||
flags |= WMF_OPT_FONTDIRS;
|
||||
api_options.fontdirs = wmffontdirs;
|
||||
#endif
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
From 2dd50107f6a700527741eb2373a8ba26975a961c Mon Sep 17 00:00:00 2001
|
||||
From: Bruno Lopes <brunvonlope@outlook.com>
|
||||
Date: Fri, 26 Dec 2025 19:54:22 -0300
|
||||
Subject: [PATCH] build/macos: Do not require gexiv2-0.14 on homebrew
|
||||
|
||||
---
|
||||
libgimp/meson.build | 2 +-
|
||||
meson.build | 6 ++----
|
||||
2 files changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libgimp/meson.build b/libgimp/meson.build
|
||||
index c12e60c2cd..738564c2b9 100644
|
||||
--- a/libgimp/meson.build
|
||||
+++ b/libgimp/meson.build
|
||||
@@ -387,7 +387,7 @@ libgimp_deps_table = [
|
||||
{ 'gir': 'cairo-1.0', 'vapi': 'cairo-1.0', },
|
||||
{ 'gir': 'GdkPixbuf-2.0', 'vapi': 'gdk-pixbuf-2.0', },
|
||||
{ 'gir': 'Gegl-0.4', 'vapi': 'gegl-0.4', },
|
||||
- { 'gir': 'GExiv2-0.10', 'vapi': 'gexiv2', },
|
||||
+ { 'gir': 'GExiv2-0.16', 'vapi': 'gexiv2-0.16', },
|
||||
{ 'gir': 'Gio-2.0', 'vapi': 'gio-2.0', },
|
||||
{ 'gir': gio_specific_gir, 'vapi': gio_specific_vapi, },
|
||||
{ 'gir': 'GLib-2.0', 'vapi': 'glib-2.0', },
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 97662d62d7..4fcf576cce 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -454,9 +454,8 @@ gegl_minver = '0.4.66'
|
||||
gegl = dependency('gegl-0.4', version: '>='+gegl_minver)
|
||||
exiv2_minver = '0.27.4'
|
||||
exiv2 = dependency('exiv2', version: '>='+exiv2_minver)
|
||||
-gexiv2_minver = '0.14.0'
|
||||
-gexiv2_maxver = '0.15.0'
|
||||
-gexiv2 = dependency('gexiv2', version: ['>='+gexiv2_minver, '<'+gexiv2_maxver])
|
||||
+gexiv2_minver = '0.16.0'
|
||||
+gexiv2 = dependency('gexiv2-0.16', version: '>='+gexiv2_minver)
|
||||
|
||||
gio = dependency('gio-2.0')
|
||||
gio_specific_name = platform_windows ? 'gio-windows-2.0' : 'gio-unix-2.0'
|
||||
@@ -1686,7 +1685,6 @@ install_conf.set('GDK_PIXBUF_REQUIRED_VERSION', gdk_pixbuf_minver)
|
||||
install_conf.set('GEGL_REQUIRED_VERSION', gegl_minver)
|
||||
install_conf.set('EXIV2_REQUIRED_VERSION', exiv2_minver)
|
||||
install_conf.set('GEXIV2_REQUIRED_VERSION', gexiv2_minver)
|
||||
-install_conf.set('GEXIV2_MAX_VERSION', gexiv2_maxver)
|
||||
install_conf.set('GLIB_REQUIRED_VERSION', glib_minver)
|
||||
install_conf.set('GTK_REQUIRED_VERSION', gtk3_minver)
|
||||
install_conf.set('HARFBUZZ_REQUIRED_VERSION', harfbuzz_minver)
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
24
build/macos/patches/0001-meson-Patch-python-version.patch
Normal file
24
build/macos/patches/0001-meson-Patch-python-version.patch
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
From 9ee6b4e10c0b429358640aac4e081e2aca329ddb Mon Sep 17 00:00:00 2001
|
||||
From: Bruno Lopes <brunvonlope@outlook.com>
|
||||
Date: Sat, 10 Jan 2026 15:49:22 -0300
|
||||
Subject: [PATCH] meson: Patch python version
|
||||
|
||||
---
|
||||
meson.build | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/meson.build b/meson.build
|
||||
index cd51137d6f..b59fb6cceb 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -130,7 +130,7 @@ versionconfig.set('GIMP_API_VERSION', gimp_api_version)
|
||||
pkgconfig = import('pkgconfig')
|
||||
i18n = import('i18n')
|
||||
gnome = import('gnome')
|
||||
-python = import('python').find_installation()
|
||||
+python = import('python').find_installation('python3.13')
|
||||
simd = import('unstable-simd')
|
||||
fs = import('fs')
|
||||
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
67
build/macos/patches/xdg-email
Normal file
67
build/macos/patches/xdg-email
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#!/bin/sh
|
||||
|
||||
# this is poor man xdg-email wrapper for osx.
|
||||
# It is intended to emulate xdg-email functionality using Mail.app and oascript.
|
||||
# currently only --attach --subject and --body commands are supported
|
||||
# and only first email address is used
|
||||
|
||||
# There is now ling args support in osx getopt, so we are doing this hack
|
||||
# and transforming long options to short ones
|
||||
#
|
||||
# Written by Alex Samorukov, samm@os2.kiev.ua
|
||||
|
||||
for arg in "$@"; do
|
||||
shift
|
||||
case "$arg" in
|
||||
"--attach") set -- "$@" "-a" ;;
|
||||
"--subject") set -- "$@" "-s" ;;
|
||||
"--body") set -- "$@" "-b" ;;
|
||||
"--help") set -- "$@" "-h" ;;
|
||||
*) set -- "$@" "$arg"
|
||||
esac
|
||||
done
|
||||
|
||||
# Default behavior
|
||||
rest=false; ws=false
|
||||
|
||||
ATTACH=""
|
||||
SUBJECT=""
|
||||
BODY=""
|
||||
# Parse short options
|
||||
OPTIND=1
|
||||
while getopts "a:s:b:h" opt
|
||||
do
|
||||
case "$opt" in
|
||||
"a") ATTACH="$OPTARG"; ;;
|
||||
"s") SUBJECT="$OPTARG"; ;;
|
||||
"b") BODY="$OPTARG"; ;;
|
||||
"h") echo "sends email using Mail.app from commandline"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
shift $(expr $OPTIND - 1) # remove options from positional parameters
|
||||
|
||||
TO_ADDR="$1"
|
||||
|
||||
SCRIPT="
|
||||
set recipientName to \"\"
|
||||
set recipientAddress to \"${TO_ADDR}\"
|
||||
set theSubject to \"${SUBJECT}\"
|
||||
set theContent to \"${BODY}\"
|
||||
set theAttachmentFile to \"${ATTACH}\" -- the attachment path
|
||||
|
||||
tell application \"Mail\"
|
||||
## set focus
|
||||
activate
|
||||
## Create the message
|
||||
set theMessage to make new outgoing message with properties {subject:theSubject, content:theContent, visible:true}
|
||||
|
||||
## attach file
|
||||
tell theMessage to make new attachment with properties {file name:theAttachmentFile}
|
||||
|
||||
## Set a recipient
|
||||
tell theMessage
|
||||
make new to recipient with properties {name:recipientName, address:recipientAddress}
|
||||
end tell
|
||||
end tell
|
||||
"
|
||||
echo "$SCRIPT"|/usr/bin/osascript
|
||||
|
|
@ -2143,6 +2143,12 @@ if get_option('windows-installer') or get_option('ms-store')
|
|||
meson.add_install_script(install_win_bundling_script)
|
||||
endif
|
||||
|
||||
# On macOS, install deps in an .app bundle before distributing
|
||||
if get_option('dmg')
|
||||
install_macos_debug_script = find_program('build/macos/2_bundle-gimp-uni_base.py')
|
||||
meson.add_install_script(install_macos_debug_script)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Subdir installations
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue