Home / Alt manpages / glib-genmarshal(1)

  • glib-genmarshal(1)
  • User command
  • linux

Generate GLib Closure Marshallers with glib-genmarshal

You will turn a small marshaller list into the matching GLib header and C source files, then check that the generated names and includes are usable by your build. The examples use glib-genmarshal 2.86.4 from the installed libglib2.0-dev-bin package, version 2.80.0-6ubuntu3.9. Allow about fifteen minutes if you already know the callback signatures.

This tool generates C code for GObject closures. It does not compile that code, register a signal, or change a running service. You need the development package and a writable project directory. The generation commands are ordinary user commands; they do not need sudo.

1. Check the installed command

Confirm that the command and package are the ones you expect:

$ command -v glib-genmarshal
/home/linuxbrew/.linuxbrew/bin/glib-genmarshal
$ glib-genmarshal --version
glib-genmarshal version 2.86.4
$ dpkg-query -W -f='${Package} ${Version}\n' libglib2.0-dev-bin
libglib2.0-dev-bin 2.80.0-6ubuntu3.9

The executable can come from a different prefix than the Debian package query suggests. That is a reason to check command -v, not a reason to run the generator as root. If the command is missing, install the development tools through your normal package-management process before continuing.

2. Describe the callbacks in a list

Create a project file called marshal.list. Each non-comment line has the form RETURN:PARAMETER,PARAMETER. The first and last callback arguments are always the closure data pointers and are not written in the list.

# Callbacks: void with no extra argument, and float with two arguments
VOID:VOID
VOID:INT
FLOAT:BOOLEAN,UCHAR

These entries represent callbacks whose visible signatures are equivalent to void (gpointer, gpointer), void (gpointer, gint, gpointer), and gfloat (gpointer, gboolean, guchar, gpointer). Type names are the tokens supported by the installed manual, such as INT, BOOLEAN, STRING, OBJECT and VARIANT. VOID is the no-return or no-extra-parameter marker. Do not write C declarations in this file.

Checkpoint: validate the list by asking for header output. The diagnostic is written to standard error, while the generated C header is written to standard output:

$ glib-genmarshal --header marshal.list > /tmp/marshal.h
INFO: Reading marshal.list...
$ grep -E 'VOID__VOID|VOID__INT|FLOAT__BOOLEAN_UCHAR' /tmp/marshal.h
#define g_cclosure_user_marshal_VOID__VOID    g_cclosure_marshal_VOID__VOID
#define g_cclosure_user_marshal_VOID__INT     g_cclosure_marshal_VOID__INT
g_cclosure_user_marshal_FLOAT__BOOLEAN_UCHAR (GClosure

The exact spacing in the header can vary. The important check is that all three expected names exist and that the command returned status 0.

3. Generate the header and body separately

Generate a header with --header, then a C source file with --body. Use --output when the destination is a named file. The body includes the header name supplied with --include-header:

$ glib-genmarshal --header --output=marshal.h marshal.list
INFO: Reading marshal.list...
$ glib-genmarshal --body --include-header=marshal.h --output=marshal.c marshal.list
INFO: Reading marshal.list...
$ test -s marshal.h && test -s marshal.c
$ grep -F '#include "marshal.h"' marshal.c
#include "marshal.h"

The header contains aliases to standard GObject marshallers where one exists, and declares generated functions for the remaining signatures. The body contains the implementations. Generate both from the same list so they cannot drift apart.

Do not confuse --header and --body: they are mutually exclusive. A command without either option is not a substitute for generating the two build artefacts as separate steps.

4. Inspect names and source-location comments

Marshaller names encode the return type and parameter types after a double underscore. For the list above, the expected names are:

$ grep -o 'g_cclosure_user_marshal_[A-Z0-9_]*' marshal.h | sort -u
g_cclosure_user_marshal_FLOAT__BOOLEAN_UCHAR
g_cclosure_user_marshal_VOID__INT
g_cclosure_user_marshal_VOID__VOID

Generated comments normally include the input file and line number. That is useful when a compiler diagnostic points into generated code. If reproducible output must not contain source locations, add --skip-source. This changes comments, not the marshaller contract:

$ printf '%s\n' 'VOID:VOID' | glib-genmarshal --header --skip-source - | grep -F 'VOID__VOID'
#define g_cclosure_user_marshal_VOID__VOID    g_cclosure_marshal_VOID__VOID

5. Choose a prefix only when the project needs one

The default prefix is g_cclosure_user_marshal. A custom prefix changes the generated identifier, so every C caller must use that same identifier. It does not rename the standard GObject marshaller on the right-hand side of an alias:

$ printf '%s\n' 'VOID:VOID' | glib-genmarshal --header --prefix project_marshal - | grep -F 'project_marshal_VOID__VOID'
#define project_marshal_VOID__VOID    g_cclosure_marshal_VOID__VOID

Keep the default unless a naming collision or project convention gives you a reason to change it. If you do change it, regenerate the header and body together and update the declarations or calls that refer to the old prefix.

6. Connect the files to a build

With Meson, the GLib GNOME module wraps the dependency ordering for you:

gnome = import('gnome')
marshal_files = gnome.genmarshal('marshal',
  sources: 'marshal.list',
  internal: true,
)

mainlib = library('project',
  sources: project_sources + marshal_files,
)

The returned array contains the generated source target first and the header target second. If another target consumes the library and includes the generated header, pass that header through a dependency so it is built first. Do not add the generated source again through both the library and that dependency, or it can be compiled twice.

For a hand-written Make rule, make the header depend on the list, and the body depend on both:

marshal.h: marshal.list
        glib-genmarshal --header --output=$@ $<

marshal.c: marshal.list marshal.h
        glib-genmarshal --body --include-header=marshal.h --output=$@ $<

Use tabs for the recipe lines in a Makefile. In an existing Autotools project, discover the generator with the GLib package's glib_genmarshal variable rather than hard-coding a path, so the build uses the selected GLib installation.

7. Protect existing generated files

Shell redirection with > truncates its destination before the generator runs. The --output examples above still overwrite an existing file. Before replacing checked-in or locally edited output, compare the generated result or write to a temporary name and move it into place only after success:

$ glib-genmarshal --header --output=marshal.h.new marshal.list
$ glib-genmarshal --body --include-header=marshal.h --output=marshal.c.new marshal.list
$ test -s marshal.h.new && test -s marshal.c.new
$ mv marshal.h.new marshal.h
$ mv marshal.c.new marshal.c

The two moves are ordinary file replacements and cannot be undone by glib-genmarshal. If either generation command fails, leave the old files in place and inspect the error. If the generated files are tracked, use your version-control revert workflow to recover an earlier version; do not delete them blindly.

8. Diagnose the usual failures

A malformed type or an extra parameter after VOID is an input error. Recheck the spelling and the colon or comma separators. A missing input file is also reported before useful output can be generated:

$ glib-genmarshal --header does-not-exist.list > /tmp/missing.h
ERROR: can't open input file does-not-exist.list: No such file or directory

Do not treat a non-empty output file as proof of success when using redirection. Check the exit status and write to a temporary destination when preserving the old file matters.

If a compiler reports a missing prototype, use --prototypes with --body. If the generated source needs a project declaration, add --include-header=your-header.h. If the generated header should use #pragma once, add --pragma-once with --header. These options affect generated C structure; they do not repair an incorrect marshaller list.

Use --g-fatal-warnings in a strict build when a warning must fail generation. Use --quiet to suppress informational output, or --verbose while investigating a build. They are mutually exclusive. Standard input is supported with -, which is useful for a short check but less reviewable than a versioned list file.

Done means

  • The installed command and GLib development package were checked.
  • The marshaller list uses supported type tokens and matches the callback signatures.
  • A header and body were generated from the same list and the body includes that header.
  • Generated identifiers were checked before C code was updated to call them.
  • The build depends on the generated files without compiling the generated source twice.
  • Existing output is protected when regeneration fails, and no elevated privileges are involved.