Simplifying OpenOCD Deployment with a Debian Package
Instead of manually copying binaries and dependencies across machines, you can package OpenOCD into a Debian .deb archive. This post walks through creating a custom package to simplify installation and distribution.

In the last two posts (1, 2), we looked into compiling OpenOCD from source and how to run the resulting binaries. While that works, I was not a fan of manually copying files between machines and juggling all the dependencies. There has to be an easier way, right? Of course, by packaging everything into a Debian .deb
file. With these packages, installation becomes clean and repeatable. Let’s go ahead and create our own openocd.deb
package for the ARM64 platforms.
Building the Package
First, install the required tools for working with Debian packages:
sudo apt install -y dpkg-dev debhelper devscripts
Next we set up the package directory structure. Our package will be called pxg-openocd, with the following structure:
DEBIAN
contains package metadata files/usr/bin
contains the compiled binary file/usr/share/openocd/scripts
contains the OpenOCD scripts
mkdir -p pxg-openocd/DEBIAN
mkdir -p pxg-openocd/usr/bin
mkdir -p pxg-openocd/usr/share/openocd/scripts
Now copy the binary and script files from the OpenOCD repository:
cp openocd/src/openocd pxg-openocd/usr/bin/
cp -r openocd/tcl/* pxg-openocd/usr/share/openocd/scripts/
For the control
file, which defines package metadata and installation requirements, we need to specify package metadata and dependencies. Last time, we used objdump
to list the required libraries (see the Installing Needed Libraries in the last post). Create the control
file inside the DEBIAN
directory and add the dependencies and other metadata as shown below:
Package: pxg-openocd
Version: 0.12.0+dev-g66ea46184
Section: embedded
Priority: optional
Architecture: arm64
Depends: libc6 (>= 2.29), libusb-1.0-0, libhidapi-hidraw0, libjim0.81
Maintainer: Make Package <info@makeprogress.ee>
Description: OpenOCD for ARM64
A custom build of Open On-Chip Debugger (OpenOCD) for ARM64 systems.
Most of the fields are self-explanatory. The Package field, however, must have a unique name on our system and is ideally lowercase.
The Version field in a Debian package specifies the software's release number. It typically follows the format: [upstreamversion]-[debianrevision]
, where upstream_version
is the original software version, and debian_revision
(if present) indicates Debian-specific modifications. For our custom build, we can use a descriptive version like 0.12.0+dev-g[git_hash]
to indicate the source commit.
Our custom package is almost ready, but before we build it we need to ensure that the files have the correct permissions. Files are set to 644 (readable by all, writable only by the owner) to prevent unauthorized modifications, while directories use 755 (readable and executable by all, writable only by the owner) to ensure controlled access to their contents.
find pxg-openocd/ -type f -exec chmod 644 {} +
find pxg-openocd/ -type d -exec chmod 755 {} +
Finally, build the .deb
package:
dpkg-deb --root-owner-group --build pxg-openocd
--root-owner-group
makes dpkg-deb
set all files in the package to be owned by root:root
, regardless of the current user building the .deb. It’s necessary because Debian packages are expected to install files owned by root:root.
And that's it, we have a installable Debian package!

Validating the Package
Although we built the package without errors, we should somehow validate it. Luckily, there is a handy tool called lintian
which checks Debian packages against packaging rules and reports issues.
$ lintian pxg-openocd.deb
E: pxg-openocd: no-changelog usr/share/doc/pxg-openocd/changelog.Debian.gz (non-native package)
E: pxg-openocd: no-copyright-file
E: pxg-openocd: unstripped-binary-or-object [usr/bin/openocd]
W: pxg-openocd: no-manual-page [usr/bin/openocd]
It seems that we have some issues, errors marked as E
and warnings marked as W
. These errors should not affect our package’s installation and usage, but leaving them unfixed feels....wrong. Let's fix them!
Fixing Missing Files
The no-changelog
error means we’re missing a properly formatted changelog file. It must be named changelog.Debian
, compressed, and placed in pxg-openocd/usr/share/doc/pxg-openocd/
We start by creating a changelog.Debian
file:
cat > "pxg-openocd/usr/share/doc/pxg-openocd/changelog.Debian" <<EOF
pxg-openocd (0.12.0+dev-g66ea46184) unstable; urgency=medium
* Built from source, git HASH 66ea46184.
-- Make Progress <info@makeprogress.ee> $(date -R)
EOF
gzip -9 -n "pxg-openocd/usr/share/doc/pxg-openocd/changelog.Debian"
Next, we compress the change log:
gzip -9 -n "pxg-openocd/usr/share/doc/pxg-openocd/changelog.Debian"
For the missing copyright file we can reuse OpenOCD’s official copyright file and place it in the same directory.
Stripping Debug Symbols
The unstripped-binary-or-object
error means that we built the binary with debug information enabled. We do not need to rebuild the whole binary, we can just strip the debug symbols from the binary.
strip pxg-openocd/usr/bin/openocd
Don’t forget to re-apply file permissions afterward, as we did at the beginning. Once built we should now see only one warning, which we can ignore. ദ്ദി(ᵔᗜᵔ)
Installing and Running the Package
With the package built we can deploy it on the Raspberry Pi by copying the .deb
file to the target system and install it with:
sudo apt install ./pxg-openocd.deb
The tool is now available on our system. We can verify the installation with:
$ openocd --version
Open On-Chip Debugger 0.12.0+dev-02117-g66ea46184 (2025-08-05-18:02)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
To update the package, bump the Version field in the control
file, rebuild the package, and reinstall the new .deb
using the same command.
And when you no longer need the tool, uninstalling via apt
ensures all files are removed cleanly, avoiding orphaned files.
$ sudo apt remove pxg-openocd
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
.....
(Reading database ... 201412 files and directories currently installed.)
Removing pxg-openocd (0.12.0+dev-g66ea46184) ...
Whats Next?
We already have a nice setup for our tool, but there’s one more improvement we can make. Next time, we’ll look at publishing the package to our own hosted Debian registry, so we can install it on our target machines directly from our registry.
Enjoyed This Post?
Love tinkering with embedded systems and hands-on projects? Join our email list, and we’ll share our latest posts, tips, and discoveries with you - no spam, just the good stuff!

Including External Libraries in CMake Projects
Learn how to use CMake’s FetchContent module to automatically download and integrate libraries like CMSIS into your embedded projects, eliminating the hassle of manual copying and updates.

How to Find the Memory Address of a Symbol in an ELF File
A quick and useful tip for locating symbol memory addresses in ELF files using arm-none-eabi-nm combined with grep—perfect for embedded debugging scenarios like setting up SEGGER RTT or inspecting linker placements and runtime symbols.

Remote Debugging with OpenOCD on Raspberry Pi
Learn how to turn a Raspberry Pi into a remote debugging server for the RP2040 using OpenOCD, a complete with step-by-step setup and instructions for building OpenOCD from source to resolve hardware compatibility issues.
Whether you're building something new, fixing stability issues, or automating what slows your team down — we can help.