From 2cbfad8ef3c064b0ce16fe60567f08fa04a5a285 Mon Sep 17 00:00:00 2001 From: Bruno Lopes Date: Fri, 27 Feb 2026 09:17:20 -0300 Subject: [PATCH] build/macos: Use symlinks instead of patches for macOS bundle structuring This is way cleaner. --- build/macos/2_bundle-gimp-uni_base.py | 29 ++--- ...ts-meson-plug-ins-Patch-macOS-bundle.patch | 114 ++++-------------- 2 files changed, 39 insertions(+), 104 deletions(-) diff --git a/build/macos/2_bundle-gimp-uni_base.py b/build/macos/2_bundle-gimp-uni_base.py index ef92a2924e..bc7b7a55f6 100644 --- a/build/macos/2_bundle-gimp-uni_base.py +++ b/build/macos/2_bundle-gimp-uni_base.py @@ -63,10 +63,22 @@ def bundle(src_root, pattern, option="None", override=None): 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") + #Needed by app/main.c + link_lib_path = Path(f"{GIMP_DISTRIB}/lib") + link_lib_path.unlink(missing_ok=True) + link_lib_path.symlink_to(os.path.relpath(Path(f"{GIMP_DISTRIB}/Frameworks"), link_lib_path.parent)) elif "share/" in pattern: dest_path = GIMP_DISTRIB / "Resources" / src_path.relative_to(src_root / "share") + #Needed by app/main.c, app/config/gimpcoreconfig.c, app/core/gimpdata.c, libgimpwidgets/gimpwidgets-private.c and plug-ins/common/file-wmf.c + link_share_path = Path(f"{GIMP_DISTRIB}/share") + link_share_path.unlink(missing_ok=True) + link_share_path.symlink_to(os.path.relpath(Path(f"{GIMP_DISTRIB}/Resources"), link_share_path.parent)) elif "etc/" in pattern: dest_path = GIMP_DISTRIB / "SharedSupport" / src_path.relative_to(src_root / "etc") + #Needed by app/main.c + link_etc_path = Path(f"{GIMP_DISTRIB}/etc") + link_etc_path.unlink(missing_ok=True) + link_etc_path.symlink_to(os.path.relpath(Path(f"{GIMP_DISTRIB}/SharedSupport"), link_etc_path.parent)) dest_path.parent.mkdir(parents=True, exist_ok=True) print(f"Bundling {src_path} to {dest_path.parent}") if src_path.is_dir(): @@ -272,8 +284,9 @@ for d in (pythonpath, pythonpath / "site-packages"): 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") +real_path = Path(f"{GIMP_DISTRIB}/share/icons") +link_path = Path(f"{GIMP_DISTRIB}/Frameworks/Python.framework/Versions/{os.getenv('PYTHON_VERSION')}/Resources/Python.app/Contents/share/icons") +link_path.parent.mkdir(parents=True, exist_ok=True) 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"): @@ -331,15 +344,3 @@ bundle(GIMP_PREFIX, "include/gegl-*", "--dest", "include") bundle(GIMP_PREFIX, "lib/pkgconfig/gimp*") bundle(GIMP_PREFIX, "lib/pkgconfig/babl*") bundle(GIMP_PREFIX, "lib/pkgconfig/gegl*") -real_bin_path = Path(f"{GIMP_DISTRIB}/MacOS") -link_bin_path = Path(f"{GIMP_DISTRIB}/bin") -link_bin_path.symlink_to(os.path.relpath(real_bin_path, link_bin_path.parent)) -real_lib_path = Path(f"{GIMP_DISTRIB}/Frameworks") -link_lib_path = Path(f"{GIMP_DISTRIB}/lib") -link_lib_path.symlink_to(os.path.relpath(real_lib_path, link_lib_path.parent)) -real_share_path = Path(f"{GIMP_DISTRIB}/Resources") -link_share_path = Path(f"{GIMP_DISTRIB}/share") -link_share_path.symlink_to(os.path.relpath(real_share_path, link_share_path.parent)) -real_etc_path = Path(f"{GIMP_DISTRIB}/SharedSupport") -link_etc_path = Path(f"{GIMP_DISTRIB}/etc") -link_etc_path.symlink_to(os.path.relpath(real_etc_path, link_etc_path.parent)) diff --git a/build/macos/patches/0001-app-libgimpwidgets-meson-plug-ins-Patch-macOS-bundle.patch b/build/macos/patches/0001-app-libgimpwidgets-meson-plug-ins-Patch-macOS-bundle.patch index 37a570963e..32b892781f 100644 --- a/build/macos/patches/0001-app-libgimpwidgets-meson-plug-ins-Patch-macOS-bundle.patch +++ b/build/macos/patches/0001-app-libgimpwidgets-meson-plug-ins-Patch-macOS-bundle.patch @@ -1,39 +1,20 @@ -From fc8868bdd2900e6bc1399dc336d73ac1c27e60f5 Mon Sep 17 00:00:00 2001 +From 976e872640437e2ef9335363b6e6bf9d2a96d5f1 Mon Sep 17 00:00:00 2001 From: Bruno Lopes -Date: Tue, 6 Jan 2026 09:59:35 -0300 +Date: Fri, 27 Feb 2026 09:19:22 -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(-) + app/main.c | 39 ++++++++++++++++++--------------------- + libgimpbase/gimpenv.c | 12 +++++++----- + 2 files changed, 25 insertions(+), 26 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 +index d22bd04725..a5ab759597 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); @@ -47,11 +28,11 @@ index d577dd0b04..b0c326ac5c 100644 + 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)) @@ -72,10 +53,10 @@ index d577dd0b04..b0c326ac5c 100644 /* 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) +@@ -458,6 +441,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); @@ -93,7 +74,7 @@ index d577dd0b04..b0c326ac5c 100644 /* 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) +@@ -476,7 +473,7 @@ gimp_macos_setenv (const char * progname) g_free (tmp); if (need_pythonhome) { @@ -103,11 +84,11 @@ index d577dd0b04..b0c326ac5c 100644 g_free (tmp); } diff --git a/libgimpbase/gimpenv.c b/libgimpbase/gimpenv.c -index 0af4f2f653..7293fe4bb1 100644 +index 3cc12b414a..2b23156de3 100644 --- a/libgimpbase/gimpenv.c +++ b/libgimpbase/gimpenv.c -@@ -415,17 +415,18 @@ gimp_installation_directory (void) - +@@ -432,17 +432,18 @@ gimp_installation_directory (void) + { NSAutoreleasePool *pool; - NSString *resource_path; @@ -116,76 +97,29 @@ index 0af4f2f653..7293fe4bb1 100644 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) +@@ -505,7 +506,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) +