Skip to content

Instantly share code, notes, and snippets.

@abiiranathan
Created September 27, 2025 00:20
Show Gist options
  • Select an option

  • Save abiiranathan/036b62fb3a342afbeed79b84798db26f to your computer and use it in GitHub Desktop.

Select an option

Save abiiranathan/036b62fb3a342afbeed79b84798db26f to your computer and use it in GitHub Desktop.
Script to Statically Compile Poppler-Glib
#!/bin/bash -eux
# This script builds a static version of poppler and its dependencies.
# The script is based on the instructions and examples provided in the article:
# https://fasterthanli.me/series/dont-shell-out/part-3
# Get the absolute path of the script.
SCRIPT_PATH=$(readlink -f "$0")
# Get the directory where the script is located.
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
# Set the installation directory for the static libraries and headers.
export PREFIX="${SCRIPT_DIR}/prefix"
mkdir -p "${PREFIX}"
# Set the PKG_CONFIG_PATH to use the libraries we build.
export PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig:${PREFIX}/lib64/pkgconfig"
# Set compiler flags for building position-independent code (PIC).
export CFLAGS="-fPIC"
export CXXFLAGS="-fPIC"
# Function to check if a library is already installed in our PREFIX
is_installed() {
local pkgname=$1
local libfile=$2 # Optional: specific library file to check
# Only check for the library file in our PREFIX directory
# Don't use pkg-config as it might find system libraries
if [[ -n "${libfile:-}" && -f "$PREFIX/lib/$libfile" ]]; then
echo ">>> $pkgname already installed (found $libfile in $PREFIX). Skipping."
return 0
fi
# Fallback: check if pkg-config finds it specifically in our PREFIX
local pc_file="$PREFIX/lib/pkgconfig/$pkgname.pc"
if [[ -f "$pc_file" ]]; then
echo ">>> $pkgname already installed (found $pc_file). Skipping."
return 0
fi
return 1
}
# Function to download and extract a tarball.
download_and_extract() {
local url=$1
local dir=$2
local strip_components=${3:-1}
local tar_flags
# Check if sources already exist
if [[ -d "sources/${dir}" ]]; then
echo ">>> Sources for ${dir} already exist. Skipping download."
return
fi
# Determine the tar flags based on file extension
case "$url" in
*.tar.xz)
tar_flags="-xJ"
;;
*.tar.gz)
tar_flags="-xz"
;;
*)
echo "Unsupported archive format for URL: $url"
exit 1
;;
esac
echo ">>> Downloading and extracting $dir"
mkdir -p "sources/${dir}"
curl -f -L "${url}" | tar "${tar_flags}" --strip-components="${strip_components}" -C "sources/${dir}"
}
# Function to build with configure (autotools)
build_autotools() {
local name=$1
local source_dir=$2
local build_dir=$3
shift 3
# remaining args are passed to configure
echo ">>> Building $name with autotools"
rm -rf "builds/$build_dir"
mkdir -p "builds/$build_dir"
pushd "builds/$build_dir"
"../../sources/$source_dir/configure" --prefix="${PREFIX}" --disable-shared --enable-static "$@"
make -j "$(nproc)"
make install
popd
}
# Function to build with cmake
build_cmake() {
local name=$1
local source_dir=$2
local build_dir=$3
shift 3
# remaining args are passed to cmake
echo ">>> Building $name with cmake"
rm -rf "builds/$build_dir"
mkdir -p "builds/$build_dir"
pushd "builds/$build_dir"
cmake -S "../../sources/$source_dir" -B . \
-DCMAKE_INSTALL_PREFIX="${PREFIX}" \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=Release \
"$@"
cmake --build . --parallel "$(nproc)"
cmake --install .
popd
}
# Function to build with meson
build_meson() {
local name=$1
local source_dir=$2
local build_dir=$3
shift 3
# remaining args are passed to meson
echo ">>> Building $name with meson"
rm -rf "builds/$build_dir"
mkdir -p "builds/$build_dir"
pushd "builds/$build_dir"
meson setup . "../../sources/$source_dir" \
--prefix="${PREFIX}" \
--buildtype=release \
--default-library=static \
--prefer-static \
"$@"
ninja -v
ninja install
popd
}
# --- Dependencies ---
# zlib
if ! is_installed "zlib" "libz.a"; then
download_and_extract "https://www.zlib.net/zlib-1.3.1.tar.xz" "zlib"
echo ">>> Building zlib"
rm -rf builds/zlib
mkdir -p builds/zlib
pushd builds/zlib
../../sources/zlib/configure --prefix="${PREFIX}" --static
make -j "$(nproc)"
make install
popd
fi
# libpng
if ! is_installed "libpng" "libpng.a"; then
download_and_extract "https://download.sourceforge.net/libpng/libpng-1.6.40.tar.xz" "libpng"
build_autotools "libpng" "libpng" "libpng"
fi
# freetype
if ! is_installed "freetype2" "libfreetype.a"; then
download_and_extract "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.xz" "freetype"
build_autotools "freetype" "freetype" "freetype" \
--with-png=no --with-zlib=yes --with-harfbuzz=no --with-bzip2=no --with-brotli=no
fi
# fontconfig
if ! is_installed "fontconfig" "libfontconfig.a"; then
download_and_extract "https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.15.0.tar.xz" "fontconfig"
build_autotools "fontconfig" "fontconfig" "fontconfig" --disable-docs
fi
# pixman
if ! is_installed "pixman-1" "libpixman-1.a"; then
download_and_extract "https://www.cairographics.org/releases/pixman-0.43.4.tar.gz" "pixman"
build_meson "pixman" "pixman" "pixman" -Dtests=disabled -Dgtk=disabled
fi
# First, clean up the existing cairo build
echo ">>> Cleaning existing cairo build"
# rm -rf builds/cairo
# rm -f "${PREFIX}/lib/libcairo.a"
# rm -f "${PREFIX}/lib/pkgconfig/cairo.pc"
# rm -rf "${PREFIX}/include/cairo"
# exit 0
if ! is_installed "cairo" "libcairo.a"; then
download_and_extract "https://www.cairographics.org/releases/cairo-1.18.4.tar.xz" "cairo"
echo ">>> Building cairo with static pixman linking"
rm -rf "builds/cairo"
mkdir -p "builds/cairo"
pushd "builds/cairo"
# Set environment variables for static linking
export PIXMAN_CFLAGS="$(pkg-config --cflags pixman-1)"
export PIXMAN_LIBS="$(pkg-config --libs --static pixman-1)"
export LDFLAGS="-L${PREFIX}/lib"
export LIBS="-lpixman-1"
meson setup . "../../sources/cairo" \
--prefix="$PREFIX" \
--buildtype=release \
--default-library=static \
--prefer-static \
-Dglib=disabled \
-Dfontconfig=enabled \
-Dfreetype=enabled \
-Dwerror=false \
-Dtests=disabled
ninja -v
ninja install
# Cleanup environment
unset PIXMAN_CFLAGS PIXMAN_LIBS LDFLAGS LIBS
popd
fi
# openjpeg
if ! is_installed "libopenjp2" "libopenjp2.a"; then
download_and_extract "https://github.com/uclouvain/openjpeg/archive/v2.5.4.tar.gz" "openjpeg"
build_cmake "openjpeg" "openjpeg" "openjpeg"
fi
# poppler-data
if [[ ! -d "$PREFIX/share/poppler" ]]; then
download_and_extract "https://poppler.freedesktop.org/poppler-data-0.4.12.tar.gz" "poppler-data"
echo ">>> Installing poppler-data (data files only)"
pushd sources/poppler-data/poppler-data-0.4.12
# First run make to generate poppler-data.pc
make
# Then install with our custom prefix
make install datadir="${PREFIX}/share"
popd
else
echo ">>> poppler-data already installed. Skipping."
fi
# # glib (required for poppler-glib)
# Add before poppler build - minimal gobject-2.0 for core C API
if ! is_installed "gobject-2.0" "libgobject-2.0.a"; then
# We need minimal glib just for GObject, not the full glib ecosystem
download_and_extract "https://download.gnome.org/sources/glib/2.78/glib-2.78.1.tar.xz" "glib"
build_meson "glib (minimal)" "glib" "glib" \
-Dtests=false \
-Dgtk_doc=false \
-Dman=false \
-Dnls=disabled \
-Dlibmount=disabled \
-Dselinux=disabled
fi
# --- Poppler ---
# Build poppler with core C API enabled
if ! is_installed "poppler" "libpoppler.a"; then
download_and_extract "https://poppler.freedesktop.org/poppler-25.09.1.tar.xz" "poppler"
build_cmake "poppler" "poppler" "poppler" \
-DCMAKE_INSTALL_PREFIX=${PREFIX} \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_POSITION_INDEPENDENT_CODE=True \
-DBUILD_GTK_TESTS=OFF \
-DBUILD_QT5_TESTS=OFF \
-DBUILD_QT6_TESTS=OFF \
-DBUILD_CPP_TESTS=OFF \
-DBUILD_MANUAL_TESTS=OFF \
-DENABLE_BOOST=OFF \
-DENABLE_UTILS=OFF \
-DENABLE_CPP=OFF \
-DENABLE_GLIB=ON \
-DENABLE_GOBJECT_INTROSPECTION=OFF \
-DENABLE_GTK_DOC=OFF \
-DENABLE_QT5=OFF \
-DENABLE_QT6=OFF \
-DENABLE_LIBOPENJPEG=none \
-DENABLE_CMS=none \
-DENABLE_DCTDECODER=none \
-DENABLE_LIBCURL=OFF \
-DENABLE_ZLIB=OFF \
-DBUILD_SHARED_LIBS=OFF \
-DRUN_GPERF_IF_PRESENT=OFF
fi
echo "Poppler static build complete."
echo "Libraries and headers are in the '${PREFIX}' directory."
echo
echo "To use in your projects:"
echo " export PKG_CONFIG_PATH=\"${PREFIX}/lib/pkgconfig:${PREFIX}/lib64/pkgconfig\""
echo " pkg-config --cflags --libs poppler"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment