Help with gimptool-2.99

Hi,

I’ve got a plug-in that compiles within a GIMP meson build, now I’m attempting to use gimptool to compile and install it from an external location. However the include directives that do work withing the GIMP project can’t be found when gimptool compiles the plug-in externally.

GIMP meson build is ok with this:
#include "config.h"
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "libgimp/stdplugins-intl.h"
gimptool needs this:
#include "/home/mark/Code/gimp-source/build/gimp/_build/config.h"
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "/home/mark/Code/gimp-source/build/gimp/libgimp/stdplugins-intl.h"

Is there a way of adapting the build environment to provide gimptools with enough information so that it can find #include “config.h” without resorting to using the full path?

Here’s my current shell script to set up a build envirnoment, from GIMP Developer - Building GIMP

#!/usr/bin/env bash

# BUILD ENVIRONMENT
export GIMP_PREFIX=${HOME}/Code/gimp-source/
export PATH="${GIMP_PREFIX}/bin:$PATH"
export PKG_CONFIG_PATH="${GIMP_PREFIX}/share/pkgconfig:${GIMP_PREFIX}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
export PKG_CONFIG_PATH="${GIMP_PREFIX}/lib64/pkgconfig:$PKG_CONFIG_PATH"

export XDG_DATA_DIRS="${XDG_DATA_DIRS:+$XDG_DATA_DIRS:}${GIMP_PREFIX}/share:/usr/local/share:/usr/share"
export LD_LIBRARY_PATH="${GIMP_PREFIX}/lib:${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export ACLOCAL_FLAGS="-I $INSTALL_PREFIX/share/aclocal $ACLOCAL_FLAGS"

GI_TYPELIB_PATH="${GIMP_PREFIX}/lib/girepository-1.0:${GI_TYPELIB_PATH:+:$GI_TYPELIB_PATH}"

arch="$(dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null)"
export PKG_CONFIG_PATH="${GIMP_PREFIX}/lib/${arch}/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="${GIMP_PREFIX}/lib/${arch}:${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export GI_TYPELIB_PATH="${GIMP_PREFIX}/lib/${arch}/girepository-1.0:${GI_TYPELIB_PATH:+:$GI_TYPELIB_PATH}"

# Launch GIMP tool
${GIMP_PREFIX}bin/gimptool-2.99 --install /home/mark/Code/plug-ins-C/hello-world/hello-world.c

read -n 1 -r -s -p "Press any key to exit..."

Both config.h and stdplugins-intl.h are only present in the GIMP source tree (or other source trees with a comparable build setup), and not used when building third-party plug-ins outside of the source tree.

If you are intending to develop a stand-alone GIMP plug-in:

Then the point of this thread should be to change the code of your plug-in to be able to be built without the GIMP source tree being present, as you would do on e.g. a system where only the libgimp-dev package and its dependencies from your Linux distro’s package repository are installed.

A more complex plug-in might have its own config.h (or comparable file) and intl (for internationalisation) header from its own build system, but then that is beyond the scope of building a single C file with gimptool.

If you are developing a plug-in with the intention of having it merged into GIMP:

Then you should be doing so in a git branch and build the GIMP source tree and your plug-in, which will be located in there, with it.

Thanks, this seems to have confirmed my suspicions. I was thinking of taking out any internationalization elements from the plug-in code, so that I could avoid including those two headers.

elements like this, formatted for translation:
#define DIALOG_TITLE _("Hello World!")

would become:
#define DIALOG_TITLE "Hello World!"

my thinking was that it would be good practice, good habit, to include the international elements.
however that doesn’t sit well with gimptool. So i’ll just drop that idea, it was inherited because I started learning from the plug-ins that are part of GIMP source. Now I see there’s a distinction between the scopes of plug-ins and how they are compiled.

A good approach for learning how a more sophisticated plug-in with localization works would be to start from the existing plug-in template for 2.x / 2.10.x and modernize it to a meson-based build system and additionally GIMP 2.99.x/3.x.

The template is available from Index of /gimp/plugin-template/

You will notice that its autotools-based build system creates a config.h (which is different from GIMP’s), and that there is also a plugin-intl.h in the plug-in source directory, where the internationalization includes and definitions are handled.

hmm, reading this, it seems that if my goal is to write a library of functions to share between plug-ins, and gimptool is more for a single plug-in file, then maybe gimptool is not the right tool?

sketching it out, it seems simple;

code dir (external to GIMP)
→ plug-ins
–>–> my_plugin_taskA
–>–> my_plugin_taskB
–>–> my_plugin_taskC

->my_library.h
->my_library.c

I can do this at the moment by modifying the meson build files in…
gimp-source/build/gimp/plug-ins/meson.build
gimp-source/build/gimp/plug-ins/my_plugin/meson.build
…to point at the external files, and the ninja takes care of the compiling and linking stuff.

This isn’t nice at all though. Maybe gimptool can help, but the water is too deep here for me to figure out how.

This may be a good point to explain in less generic terms what goal you are trying to achieve.

Otherwise, we may spend our time (not) solving a lot of X-Y-problems, where you keep asking for how to solve problem X which you see as a step towards solving problem Y, but we will not know about the actual problem Y you are intending to solve. for (quite) some time.

So:

What will the plugin tasks A, B, C, … you mentioned be most likely called by users when they want to use them, and what will their results be/look like?

What is the library supposed to do in regard to these tasks?

Specifically i’d like to build a library of small functions, that work in the context of a C plug-in.
for example, ‘add_normal_layer’, this function simplifies adding a typical (for me) new layer to an image.

#ifndef PIXELMIXER_H
#define PIXELMIXER_H

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

GimpLayer* add_normal_layer(GimpImage *img, GimpDrawable *dstL, const gchar *name);

#endif  /* PIXELMIXER_H */
#include "pixelmixer.h"

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>


GimpLayer*
add_normal_layer (GimpImage    *img,
                  GimpDrawable *dstL,
                  const gchar  *name)
{

  gint type = GIMP_RGBA_IMAGE;
  gint mode = GIMP_LAYER_MODE_NORMAL;
  gint pos = gimp_image_get_item_position (img, (GimpItem *) dstL);
  gint x = gimp_drawable_get_width (dstL);
  gint y = gimp_drawable_get_width (dstL);

  GimpLayer* new_layer = gimp_layer_new (img, name, x, y, type, 100, mode);
  gimp_image_insert_layer(img, new_layer, NULL, pos);

  return new_layer;
}

It might be used by several plug-ins. This will allow me to slowly learn C and the GIMP API. In time I could also convert plug-ins from Script-Fu using this method.

I’d like to work in a separate repo for these plug-ins, outside of the GIMP repo, because it simplifies everything apart from this build issue.

Does that help at all?

i wondered if I could use gimptool to provide the flags for a straightforward compile, it worked :slight_smile:

builds the plugins, as if they were built using gimptool, plus an extra couple of includes and a extra slice of .c

This is all new to me, so chip in with any observations on this.

#!/usr/bin/env bash

# Define paths and plug-in name
gimp_source_dir="/home/mark/Code/gimp-source"
plugin_name="dotty"
source_dir="/home/mark/Code/plug-ins-C/${plugin_name}"
output_dir="${gimp_source_dir}/lib/x86_64-linux-gnu/gimp/2.99/plug-ins/${plugin_name}"

meson_config="/build/gimp/_build"
meson_intl="/build/gimp/libgimp"
pixelmixer="/home/mark/Code/plug-ins-C/include"
pixelmixer_source="/home/mark/Code/plug-ins-C/include/pixelmixer.c"

# Create output directorys
mkdir -p "${output_dir}"

# Compile
# -L line from /home/mark/Code/gimp-source/bin/gimptool-2.99 --libs
# -pthread line from -> /home/mark/Code/gimp-source/bin/gimptool-2.99 --cflags
gcc "${source_dir}/${plugin_name}.c" ${pixelmixer_source} \
-L/home/mark/Code/gimp-source/lib/x86_64-linux-gnu -lgimpui-3.0 -lgimpwidgets-3.0 -lgimpmodule-3.0 -lgimp-3.0 -lgimpbase-3.0 -lgimpcolor-3.0 -lgimpconfig-3.0 -lgimpmath-3.0 -lgegl-0.4 -lgegl-npd-0.4 -Wl,--export-dynamic -lgmodule-2.0 -pthread -ljson-glib-1.0 -lbabl-0.1 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 \
-pthread -I/home/mark/Code/gimp-source/include/gimp-3.0 -I/home/mark/Code/gimp-source/include/gegl-0.4 -I/home/mark/Code/gimp-source/include/babl-0.1 -I/usr/include/json-glib-1.0 -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/fribidi -I/usr/include/harfbuzz -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/x86_64-linux-gnu -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include \
-I"${gimp_source_dir}${meson_config}" \
-I"${gimp_source_dir}${meson_intl}" \
-I"${pixelmixer}" \
-o "${output_dir}/${plugin_name}"

You could consider to make one plug-in dedicated to offer such procedures through the PDB, and have all other plug-in your are creating use them.

One example for this in GIMP’s default plug-in is the PSD plug-in providing a procedure for other file format plug-ins to load PSD metatadata, for example from TIFF files.

For your compile example, note that you can also use gimptool to provide the -L and -l flags with the --libs parameter and the include flags with the --cflags parameter.

gimptool --help will tell you about all the possible parameters, and it is quite common to have a call to it directly in your build script for this purpose instead of just its output, as the example you posted seems to imply.

P.S. calling your plug-in “dotty” might make some people think it is related to a graph editor from the grpahviz package: dotty | Graphviz

Is it?

Thank you, that is helpful!

I like the idea of calling gimptool to provide input to the gcc, rather than manually doing that first.
here’s a summary of what I’ve learned about how to make plug-ins;

  • include single file plug-ins as part of the GIMP build process, simple to do.
  • include multiple file plug-ins as part of GIMP, edit required of meson.build in the plug-in folder.
  • externally compile single file plug-ins with gimptool, simple to do.
  • externally build multiple file plug-ins using gimptool for support, a build process required.

And conceptually, you suggest, one might build every small function as plug-in! Tempting, as the browser would become a useful interface for a library. On the other-hand it breaks the concept of a stand-alone plug-in. Something to think about there. If I produce a library of useful ‘individual’ plugins, any one plugin would require installing lots of plug-ins. And the PDB might get congested with similar sounding but functionally slightly different stuff, hmm, not nice.

no relation to Graphviz dotty, just a random name for testing functions.

You seem to think that one plug-in can only offer one function, judging by that:

[…] one might build every small function as plug-in […]

A plugin can provide any number of procedures.

You’ve hit a vaguely known about, but not understood by me, feature of C plug-ins. This design of a plug-in having multiple procedures. Could you expand on the concept, how it might be used? Are there any practical examples to study? It feels a strange concept having come from the direction of Script-Fu, where one procedure is registered per plug-in.

Are you saying that a whole library of functions can be contained in one plug-in?

Are you saying that a whole library of functions can be contained in one plug-in?

Yes, you certainly can do that. See e.g. plug-ins/common/compose.c for an example of using multiple entries, but also most file import/export plug-ins have multiple functions (load, save and thumbnail in most cases).

This approach of providing multiple procedures from one plug-in is, by no means, limited to C plug-ins, either.

Nor do you have to implement everything in C - you could have a Script-Fu-based script (2.10) or plug-in (2.99 on onwards), implement convenience functions there, and then use them from other C (Script-Fu or Python, or …) plug-ins.

Crikey, thought provoking, very flexible!

Is a Script-Fu plug-in able to register mutiple procedures within it?
by leaving out the menu part? like this…

(script-fu-register "script-fu-add-normal-layer"
 "add normal layer" 
 "adds a typical layer above the active drawable" 
 "Author"
 "Under GNU GENERAL PUBLIC LICENSE Version 3"
 "2023"
 ""
)

@pixelmixer

Indeed! Actually all our bindings are supposedly able to do the same thing in 2.99 because they are all introspected from the C lib. Supposedly because there will still be some functions which are not introspectable, or some differences which are tied to how a specific language work.

The only different one is indeed script-fu which is its own thing, a wrapper directly around the PDB protocol (instead of a binding introspected from the C lib; in other words Script-fu and the C libgimp are on the same level just above the PDB).

Yes. script-fu-menu-register is optional.

Some scripts/plug-ins use this to provide a deprecated version of a procedure for backwards compatibility, but only register the current version in the menus, see e.g. plug-ins/script-fu/scripts/selection-round.scm · master · GNOME / GIMP · GitLab ff.

You can easily do this to provide a bunch of procedures solely for other plug-ins to use, and not have the providing plug-in appear anywhere in the menus.

1 Like

what I like about plug-ins is their stand-alone nature, any kind of niche task can be accomplished by just dropping in one file. So maybe a ‘library plug-in’ isn’t the right way for me to go about this particular issue, using C is great because i can use the include directive.

I have this longstanding problem with Script-Fu, which I love, of not being able to do something like what the include does in C. I manually copy and paste from a library. I wonder if this might be a possibility for Script-Fu? The ability to #include?

Maybe it already has?