GNOME Development Environment

Last update: 2021-05-31 01:36:17 +0800 +0800
Available translations: 日本語 / 中文(简体) / 中文(繁體)

Debugging across GLib and GTK requires a consistent dependency graph. If GTK loads a development libgtk but resolves GLib, Pango, or GDK Pixbuf from the host, source lines and runtime types no longer correspond to one coherent build. An isolated installation prefix provides that consistency without replacing distribution packages.

Choose the Isolation Boundary #

GNOME recommends Builder for application development and Toolbx for libraries, services, and host-integrated modules. JHBuild remains available for building a dependency graph. Those tools encode more of the graph than a hand-written script and should be preferred for sustained contribution work.

A manual Meson/Ninja prefix remains useful for source inspection or a small, controlled stack. Use it inside a container or disposable development environment when possible. The prefix isolates installed files, while the container isolates build tools and dependencies that still come from the distribution.

GLib, GObject, GModule, GThread, and GIO are built from the same GLib repository; GObject is not a separate source checkout. GTK is a separate repository. GTK’s exact dependency set varies with its enabled Wayland, X11, Vulkan, documentation, and introspection features, so each checkout’s README.md, meson_options.txt, and Meson error messages are authoritative for that revision.

Install the distribution’s compiler, Python, Meson, Ninja, pkg-config, and the development headers needed to bootstrap the graph. Documentation builds may additionally require tools such as gi-docgen, Graphviz, and Doxygen; they are not required for every GLib or GTK configuration.

Define One Development Prefix #

Keep source, build directories, and installed artifacts separate:

g`n-o-meeps`-nrr-dvec-e.f/vsigg/hxlt/ikb

An activation script makes all discovery paths refer to the same prefix:

sh
#!/usr/bin/env bash

ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
PREFIX="$ROOT/prefix"

export PREFIX
export PATH="$PREFIX/bin:$PATH"
export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig"
export LD_LIBRARY_PATH="$PREFIX/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export GI_TYPELIB_PATH="$PREFIX/lib/girepository-1.0"
export GIO_EXTRA_MODULES="$PREFIX/lib/gio/modules"
export GSETTINGS_SCHEMA_DIR="$PREFIX/share/glib-2.0/schemas"
export XDG_DATA_DIRS="$PREFIX/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"

Setting --libdir=lib during every Meson setup makes these paths independent of a distribution’s lib64 or multiarch default. PKG_CONFIG_PATH searches the prefix first but still permits host fallback. After the entire required dependency closure has been installed into the prefix, strict builds can replace it with:

sh
export PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig"
unset PKG_CONFIG_PATH

PKG_CONFIG_LIBDIR suppresses pkg-config’s standard search directories. Enabling it too early also hides bootstrap libraries such as libffi, PCRE2, FreeType, and Fontconfig, so either build those into the prefix or use a container with an explicitly documented host baseline.

Do not place this activation in a login profile. LD_LIBRARY_PATH applies to every process started from the shell and can make unrelated host applications load ABI-incompatible development libraries.

Build in Dependency Order #

Build leaves before roots because Meson resolves dependencies when configuring each build directory. A GTK stack commonly includes the following groups:

  1. GLib’s bootstrap dependencies, including libffi and PCRE2.
  2. GLib, which produces GLib, GObject, and GIO together.
  3. Graphics and text dependencies such as pixman/Cairo, FreeType, Fontconfig, HarfBuzz, GDK Pixbuf, Pango, Graphene, and libepoxy.
  4. Backend dependencies, such as Wayland and wayland-protocols or the required X11 libraries.
  5. GTK, followed by language bindings such as gtkmm when the project needs them.

Dependency edges within the middle groups depend on selected features. A topological module set from JHBuild or GNOME Build Metadata is safer than copying a fixed list across releases.

The same build function can be used for each Meson project:

sh
build_one()
{
  source_dir=$1
  build_dir=$2

  meson setup "$build_dir" "$source_dir" \
    --prefix="$PREFIX" \
    --libdir=lib \
    -Ddebug=true \
    -Doptimization=0 \
    -Dstrip=false
  meson compile -C "$build_dir"
  meson test -C "$build_dir" --print-errorlogs
  meson install -C "$build_dir"
}

Run the function from a shell that has sourced env.sh:

sh
mkdir -p "$PREFIX"

build_one "$PWD/src/glib" "$PWD/src/glib/_build"
build_one "$PWD/src/gtk"  "$PWD/src/gtk/_build"

The two calls show the endpoints, not a complete GTK build plan. Invoke the same function for every source-built dependency between GLib and GTK in the module set’s topological order.

Meson’s debug build type currently corresponds to debug information with optimization level 0, but spelling out debug, optimization, and strip makes the intended debugger behavior visible. Individual projects can add feature options after inspecting meson configure _build; disabling an unneeded backend is preferable to accidentally satisfying it from the host.

Installing each completed layer matters because the next project finds its headers, .pc files, shared objects, schemas, and introspection data under one prefix. Compile installed schemas after installing a project that provides them:

sh
glib-compile-schemas "$PREFIX/share/glib-2.0/schemas"

Prevent Mixed-System Builds #

Check dependency resolution immediately after Meson setup:

sh
pkg-config --variable=prefix glib-2.0
pkg-config --variable=prefix gtk4
meson introspect src/gtk/_build --dependencies

Both pkg-config prefix queries should print the development prefix. Meson’s setup log must also show prefix paths for Pango, GDK Pixbuf, Graphene, and other libraries intended to be under source control.

Check the final ELF resolution rather than trusting link-time output:

sh
ldd "$PREFIX/bin/gtk4-demo"
readelf -d "$PREFIX/bin/gtk4-demo" | grep -E 'NEEDED|RPATH|RUNPATH'

All libraries in the source-built closure should resolve below $PREFIX. System C libraries, the dynamic loader, GPU drivers, and deliberately retained bootstrap dependencies may still resolve from the host. Record that boundary instead of claiming complete isolation.

An rpath can make binaries usable without LD_LIBRARY_PATH:

sh
export LDFLAGS="-Wl,-rpath,$PREFIX/lib"

Use the comma-separated linker form shown above. An rpath only changes runtime loading; it does not influence which headers or .pc metadata Meson selected. pkg-config inspection is still required.

Make Updates Repeatable #

Clone each upstream repository once:

sh
git clone https://gitlab.gnome.org/GNOME/glib.git src/glib
git clone https://gitlab.gnome.org/GNOME/gtk.git src/gtk

Apply the same pattern to source-built dependencies from the selected module set. Subsequent updates should not delete untracked work:

sh
git -C src/glib fetch --prune
git -C src/glib switch main
git -C src/glib pull --ff-only

git -C src/gtk fetch --prune
git -C src/gtk switch main
git -C src/gtk pull --ff-only

For each dependency, record the tested commit in a lock file or build log. “Current source” changes continuously; commit IDs make a successful graph reproducible. Update leaves first, then rebuild and install dependents. Use meson setup --reconfigure when only options or detected dependencies changed, and meson setup --wipe only for a generated build directory when cached state must be discarded.

Avoid git clean -fdx in update scripts because it destroys untracked source work. Build directories already provide a replaceable boundary.

Debug the Installed Graph #

Run the debugger from the activated environment:

sh
gdb --args "$PREFIX/bin/gtk4-demo"

Useful initial checks are:

gdb
(gdb) set breakpoint pending on
(gdb) break g_main_context_dispatch
(gdb) break gtk_widget_snapshot
(gdb) run
(gdb) info sharedlibrary

info sharedlibrary should show the intended prefix. If a breakpoint resolves to a system path, inspect LD_DEBUG=libs, ldd, pkg-config prefixes, and Meson’s dependency report before debugging application logic. Source lookup can be corrected with GDB’s directory or set substitute-path, but path substitution cannot repair a binary linked against the wrong library.

The update workflow is therefore deterministic:

  1. Activate the environment.
  2. Fetch pinned or selected commits.
  3. Reconfigure, build, test, and install in dependency order.
  4. Recompile schemas and any generated loader caches required by the stack.
  5. Audit pkg-config and ELF resolution.
  6. Start the debugger only after the graph passes those checks.

Upstream References #

Comments

Read or comment on GitHub (sign-in required to comment)