resynthesizer icon indicating copy to clipboard operation
resynthesizer copied to clipboard

Support building on macOS.

Open brainy opened this issue 6 months ago • 6 comments

The GIMP App on macOS has all the shared libraries that the plugin needs, it just doesn't have the headers. This change uses include paths from pre-built libraries (from Homebrew or MacPorts) and the GIMP source tree (from git or a release tarball) to build the plugin and force it to use the shared libraries that are installed with GIMP.app.

brainy avatar Jul 02 '25 04:07 brainy

I use this shell script to build the plugin:

#!/usr/bin/env bash

gimpver=gimp-3.0.4
gimptar=${gimpver}.tar.xz
gimpurl=https://download.gimp.org/gimp/v3.0/$gimptar
resynth=https://github.com/bootchk/resynthesizer.git
srcdir=resynthesizer
builddir=resynth-build
prefix=/opt/gimp
plugins=$prefix/3.0/plug-ins

here="$(cd $(dirname "$0") && pwd)"
abs_gimpsrc="$here/$gimpver"
abs_srcdir="$here/$srcdir"
abs_builddir="$here/$builddir"

set -e
set -x

cd $here

if [ ! -d $gimpver ]; then
    rm -fr $gimpver
    if [ ! -r $gimptar ]; then
        curl -LO $gimpurl
        shasum -c ${gimptar}.sha256
    fi
    xzcat ${gimptar} | tar x

    # Configure the libgimp version header.
    ver=$(sed -E 's/^( +version: +'"'"'([0-9.]+))?.*$/\2/' $gimpver/meson.build)
    vmaj=$(echo $ver | sed -Ee 's/^([0-9]+).*$/\1/')
    vmin=$(echo $ver | sed -Ee 's/^[^.]+\.([0-9]+).*$/\1/')
    vmic=$(echo $ver | sed -Ee 's/^[^.]+\.[^.]+\.([0-9]+).*$/\1/')
    cat $gimpver/libgimpbase/gimpversion.h.in         \
        | sed -e s/@GIMP_MAJOR_VERSION@/$vmaj/        \
              -e s/@GIMP_MINOR_VERSION@/$vmin/        \
              -e s/@GIMP_MICRO_VERSION@/$vmic/        \
              -e s/@GIMP_API_VERSION@/$vmaj.$vmin/    \
              -e s/@GIMP_VERSION@/$vmaj.$vmin.$vmic/  \
        > $gimpver/libgimpbase/gimpversion.h
fi

if [ ! -d $srcdir ]; then
    rm -fr $srcdir
    git clone $resynth --branch resynthesizer3 $srcdir
    (
        cd $srcdir
        git checkout -b macosbuild3
    )
fi

rm -fr $builddir
mkdir $builddir
meson setup \
      --prefix="$prefix" \
      -Dgimp-plugin-dir="$plugins" \
      -Dgimp-source-dir="$abs_gimpsrc" \
      -Dmac-gimp-app="/Applications/GIMP.app" \
      $builddir $srcdir
cd $builddir
meson compile
meson install

brainy avatar Jul 02 '25 04:07 brainy

Thanks.

I don't understand. If the resynthesizer doesn't directly call those libraries (I don't think it does) then it doesn't need the headers for those libraries.

I agree that during linking, it must use the same libraries as GIMP. So there is a transitive dependence on those libraries (the libraries themselves, not their headers.)

But I am wondering why meson doesn't do that. Maybe it just doesn't, and parts of your fix are necessary. IOW I hate to make the meson.build more complicated than necessary. I could be wrong, I will need to study it more.

bootchk avatar Jul 02 '25 12:07 bootchk

When you #include <libgimp/gimp.h>, that eventually pulls in headers from all the other packages. Those packages are, in fact if not in intent, part of libgimp's public API.

I considered calling pkg-config --cflags-only-I directly from meson.build instead of using dependency(). It might be better, because it would avoid silently pulling in the actual libraries from the installed packages, which in turn requires all those "unnecessary" cc.find_library() calls that are there only in order to prioritize the libs from GIMP.app for linking.

I'll try that, it might end up simplifying meson.build. I'm not happy with all the bespoke dependency juggling, either.

Unfortunately macOS does not have a common package manager and installer. A mac "app" is just a directory tree with everything the app needs in there, including shared libraries that, on Linux, would normally be separate dependencies installed in /usr.

brainy avatar Jul 02 '25 18:07 brainy

When you #include <libgimp/gimp.h>, that eventually pulls in headers from all the other packages. Those packages are, in fact if not in intent, part of libgimp's public API.

In fact you get those include paths automagically on Linux from the dependency('gimp-3.0', version : '>=2.99.0') call. I simply have to make them explicit on macOS.

brainy avatar Jul 02 '25 19:07 brainy

So it turns out that even with the recent commit that uses only the include paths from all the dependent packages, I still have to explicitly list all the shared libs provided in GIMP.app. That's because cc.find_library() doesn't create a transitive tree of all loaded libraries, so the linker needs to be told explicitly where to find the symbols it needs.

Again, this is something what would happen automagically on Linux with the gimp-3.0-dev dependency.

brainy avatar Jul 02 '25 19:07 brainy

To follow up, with this patch I can build a working resynthesizer plugin on macOS. Tested with GIMP 3.0.2 and 3.0.4 on ARM64 (M3 Max).

$ otool -L /opt/gimp/3.0/plug-ins/resynthesizer/resynthesizer 
/opt/gimp/3.0/plug-ins/resynthesizer/resynthesizer:
	@rpath/lib/libgimp-3.0.0.dylib (compatibility version 0.0.0, current version 0.0.0)
	@rpath/lib/libglib-2.0.0.dylib (compatibility version 7801.0.0, current version 7801.4.0)
	@rpath/lib/libgobject-2.0.0.dylib (compatibility version 7801.0.0, current version 7801.4.0)
	@rpath/lib/libgegl-0.4.0.dylib (compatibility version 0.0.0, current version 0.0.0)
	@rpath/lib/libbabl-0.1.0.dylib (compatibility version 0.0.0, current version 0.0.0)
	@rpath/lib/libintl.8.dylib (compatibility version 13.0.0, current version 13.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)

and

$ otool -l /opt/gimp/3.0/plug-ins/resynthesizer/resynthesizer | fgrep -C2 RPATH
Load command 21
          cmd LC_RPATH
      cmdsize 56
         path /Applications/GIMP.app/Contents/Resources (offset 12)

brainy avatar Jul 19 '25 07:07 brainy