From “Library Not Found” to Lambda Hero: A Deep Dive into Zbar, Poppler, and Shared Libraries
You have an idea. A brilliant, simple idea: an AWS Lambda function, written in Python, that automatically processes uploaded PDFs. It needs…
From “Library Not Found” to Lambda Hero: A Deep Dive into Zbar, Poppler, and Shared Libraries
You have an idea. A brilliant, simple idea: an AWS Lambda function, written in Python, that automatically processes uploaded PDFs. It needs to read QR codes and maybe some text. You grab some great libraries like pyzbar for the QR codes and pdf2image to handle the PDFs. It all works flawlessly on your local machine.
You package it, deploy it to Lambda, and trigger it with a test file. And then…
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': Unable to find zbar shared library
If you’ve seen this error, or its equally frustrating cousin, PDFInfoNotInstalledError: Is poppler installed and in PATH?, then this post is for you. You are about to embark on a journey into the world of C shared libraries, linker paths, and Docker builds. Don't worry, I've already made the trip, and I’ve drawn a map so you don’t get lost.
The Core Problem: Python Wrappers and Their Hidden Needs
The first thing to understand is that libraries like pyzbar and pdf2image are not pure Python. They are brilliant Python "wrappers" around powerful, high-performance programs written in C/C++.
pyzbaris a wrapper for thezbarC library. It needs a file calledlibzbar.so.pdf2imageis a wrapper for thepopplerutility suite. It needs executable programs likepdfinfoandpdftoppm.
The AWS Lambda environment is a minimal, stripped-down version of Linux. It does not come with these C libraries and programs pre-installed. When your Python code says import pyzbar, the system looks for libzbar.so and, finding nothing, crashes.
To fix this, we need to package all these hidden dependencies into a Lambda Layer.
The Two Paths You Must Know: PATH vs. LD_LIBRARY_PATH
This is the single most important concept. In Linux:
**PATHis an environment variable that tells the system where to look for executable programs** (likepdfinfo).**LD_LIBRARY_PATHis an environment variable that tells the system where to look for shared libraries** (.sofiles) that executables depend on.
Our solution needs to satisfy both.
The Ultimate Solution: Building a Complete Layer with Docker
We can’t just pip install these dependencies. We need to build them in an environment that perfectly matches our Lambda runtime (Amazon Linux 2, x86_64 architecture). Docker is the perfect tool for this.
Here is the final, battle-hardened build script that will create a layer containing everything you need.
1. Your Project Setup
Create a directory on your machine with two files:
**requirements.txt**
Plaintext
pyzbar
pdf2image
Pillow
boto3
**build_layer.sh** (The star of our show)
#!/bin/bash
#Stop on any error
set -e
LAYER_NAME="lambda_complete_layer"
echo "Cleaning up previous build artifacts..."
rm -rf ./build
mkdir -p ./build
echo "Building final layer: Compiling Zbar and packaging Poppler with all dependencies..."
docker run \
--platform linux/amd64 \
-v "$PWD":/var/task \
public.ecr.aws/sam/build-python3.9 \
/bin/bash -c '
# 1. Enable the EPEL repository to get access to the zbar package
amazon-linux-extras install -y epel
# 2. Install all system-level dependencies
yum install -y \
zbar \
poppler-utils \
gcc make autoconf automake libtool pkgconfig libpng-devel zip
# 3. Compile Zbar from source (The most reliable method we found)
echo "Downloading and compiling zbar from source..."
cd /tmp
curl -L -o zbar.tar.bz2 "https://sourceforge.net/projects/zbar/files/zbar/0.10/zbar-0.10.tar.bz2/download"
tar -xjf zbar.tar.bz2
cd zbar-0.10
./configure --disable-video --without-imagemagick --without-gtk --without-qt --without-python --without-x
make && make install DESTDIR=/tmp/zbar_compiled
# 4. Create the required directory structure for the layer
mkdir -p /var/task/build/python/lib/python3.9/site-packages
mkdir -p /var/task/build/lib
mkdir -p /var/task/build/bin
# 5. Install Python packages
pip install -r /var/task/requirements.txt -t /var/task/build/python/lib/python3.9/site-packages
# 6. Copy our compiled zbar libs and poppler executables
echo "Copying executables and zbar libraries..."
cp /usr/bin/pdfinfo /usr/bin/pdftoppm /usr/bin/pdftocairo /var/task/build/bin/
cp -L /tmp/zbar_compiled/usr/local/lib/libzbar.so* /var/task/build/lib/
# 7. The Masterstroke: Find and copy ALL Poppler dependencies at once using ldd
echo "Finding all shared library dependencies for Poppler tools via ldd..."
ALL_DEPS=$(ldd /usr/bin/pdfinfo /usr/bin/pdftoppm | grep "=> /" | awk "{print \$3}" | sort -u)
echo "Copying all discovered dependencies: $ALL_DEPS"
for dep in $ALL_DEPS; do
cp -L "$dep" "/var/task/build/lib/"
done
# 8. Create the final zip file
cd /var/task/build
zip -r9 ../'${LAYER_NAME}'.zip .
'
echo "Build complete! Your layer is ready in ${LAYER_NAME}.zip"
Run this script with ./build_layer.sh. It will produce a lambda_complete_layer.zip file.
The Final Step: Configuring Your Lambda Function
After you upload the .zip file as a new Lambda Layer and attach it to your function, you must configure the environment variables. This is the step that tells Lambda how to use the layer.
- Go to your Lambda function’s Configuration -> Environment variables.
- Add the following two variables:
Key Value
LD_LIBRARY_PATH = /opt/lib
PATH = /opt/bin
And that’s it. The LD_LIBRARY_PATH tells the system where to find libzbar.so and all of Poppler's .so dependencies. The PATH tells the system where to find the pdfinfo program itself.
Lessons Learned from the Trenches
- “File not found” is a PATH problem, not a permissions problem. Don’t reach for
chmod 777. - A library’s dependencies have their own dependencies. The reason we had to keep adding libraries (
liblcms2,libopenjpeg) is that they were dependencies of Poppler's libraries. - Use
lddto end the madness. Thelddcommand is your best friend for uncovering the entire dependency chain of an executable. It stops the frustrating cycle of deploying, failing, and adding one library at a time. - When in doubt, compile from source. When package managers fail or have inconsistent versions (as we saw with
zbar), compiling from source gives you full control.
This journey through dependency hell was tough, but the result is a robust, self-contained deployment that will work every time. Hopefully, this map saves you from getting lost on your own adventure.
Happy coding!
메타데이터
- post_id
- 4d7ca3e3d3f9
- slug
- from-library-not-found-to-lambda-hero-a-deep-dive-into-zbar-poppler-and-shared-libraries-4d7ca3e3d3f9
- url
- https://medium.com/@svallamsetti/from-library-not-found-to-lambda-hero-a-deep-dive-into-zbar-poppler-and-shared-libraries-4d7ca3e3d3f9
- canonical_url
- https://medium.com/@svallamsetti/from-library-not-found-to-lambda-hero-a-deep-dive-into-zbar-poppler-and-shared-libraries-4d7ca3e3d3f9
- author_url
- https://medium.com/@svallamsetti
- status
- ok
- fetched_at
- 2026-07-19 05:28:52