OpenWrt: Add Static Library
This document describes how to create a custom static library (.a) in the
OpenWrt build system and how to build a separate application that links
against that library using the OpenWrt cross-compilation toolchain.
In this section, you are going to learn
How to create and package a static library in OpenWrt?
How to export static library headers and archives to both staging_dir and rootfs?
How to build a separate application that links against the static library using the OpenWrt toolchain?
How to install and run the resulting application inside an OpenWrt VM?
Topics in this section,
OpenWrt packages must follow OpenWrt’s standard build workflow. A static library must:
build with OpenWrt’s cross-toolchain
export both header file and
.aarchive into the staging directoryinstall artifacts into the root filesystem package output
Example layout:
openwrt/
└── package/
└── custom-staticlib/
├── Makefile
└── src/
├── custommath.c
└── custommath.h
custommath.c
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
custommath.h
int add(int a, int b);
int sub(int a, int b);
custommath.cprovides implementation logic compiled into an object file.custommath.hexposes the interface for downstream users.Files must be copied to
$(PKG_BUILD_DIR)to follow OpenWrt’s clean build model.Building in
$(PKG_BUILD_DIR)avoids modifying the originalsrc/tree.
package/custom-staticlib/Makefile
include $(TOPDIR)/rules.mk
PKG_NAME:=custom-staticlib
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
define Package/custom-staticlib
SECTION:=libs
CATEGORY:=Libraries
TITLE:=Custom sample static library
endef
define Package/custom-staticlib/description
A simple custom static library exporting add/sub functions.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) -c \
$(PKG_BUILD_DIR)/custommath.c \
-o $(PKG_BUILD_DIR)/custommath.o
$(AR) rcs $(PKG_BUILD_DIR)/libcustommath.a \
$(PKG_BUILD_DIR)/custommath.o
endef
define Package/custom-staticlib/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DATA) $(PKG_BUILD_DIR)/libcustommath.a $(1)/usr/lib/
$(INSTALL_DIR) $(1)/usr/include/custommath
$(INSTALL_DATA) $(PKG_BUILD_DIR)/custommath.h $(1)/usr/include/custommath/
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DATA) $(PKG_BUILD_DIR)/libcustommath.a $(1)/usr/lib/
$(INSTALL_DIR) $(1)/usr/include/custommath
$(INSTALL_DATA) $(PKG_BUILD_DIR)/custommath.h $(1)/usr/include/custommath/
endef
$(eval $(call BuildPackage,custom-staticlib))
define Package/custom-staticlib
Defines metadata for OpenWrt’s package manager and
menuconfig.Affects how the library appears in configuration menus, not how it builds.
define Package/custom-staticlib/description
Provides help text in
menuconfig.Useful for documenting library purpose and behavior.
define Build/Prepare
Creates the private build directory used for all compilation.
Copies source code into the build directory.
This isolation is critical for reproducible builds.
define Build/Compile
$(TARGET_CC)ensures cross-compilation for the target CPU.Produces
custommath.o.$(AR) rcsarchives the object file into the static librarylibcustommath.a.
define Package/custom-staticlib/install
Installs deliverables into the final root filesystem:
/usr/lib/libcustommath.a/usr/include/custommath/custommath.h
These files appear on the target OpenWrt device after installation.
define Build/InstallDev
Installs files into the staging directory, used only at build time by other packages:
staging_dir/.../usr/include/custommath/custommath.hstaging_dir/.../usr/lib/libcustommath.a
This enables dependent packages to compile successfully.
Run:
make package/custom-staticlib/{clean,compile} V=sc
The resulting package appears in:
bin/packages/x86_64/base/custom-staticlib-1.apk
cleandeletes the build directory, forcing a full rebuild.compileautomatically triggers:Prepare → copy sources
Compile → cross-compile and archive
InstallDev → populate
staging_dirfor downstream buildsInstall → populate the target root filesystem layout
The produced
.apkincludes only whatPackage/custom-staticlib/installdefines.The staging_dir version of this library is not in the
.apkbut is essential for the next step (compiling the test application).
This package demonstrates linking against the previously built custom static library. It verifies:
header export
library export
cross-linking
correct execution
Layout:
package/
└── custom-staticlib-test/
├── Makefile
└── src/
└── test.c
test.c
#include "custommath.h"
#include <stdio.h>
int main() {
int result = add(3, 5);
printf("Result from static library: %d\n", result);
return 0;
}
Including
custommath.hconfirms header export tostaging_dir.Final binary will statically pull
add(and possiblysub) fromlibcustommath.a.No shared libraries are needed at runtime; all code is embedded.
package/custom-staticlib-test/Makefile
include $(TOPDIR)/rules.mk
PKG_NAME:=custom-staticlib-test
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
define Package/custom-staticlib-test
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Test app using custom static library
DEPENDS:=+custom-staticlib
endef
define Package/custom-staticlib-test/description
A simple test program that links against custom-staticlib.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(TARGET_CC) \
$(TARGET_CFLAGS) \
-I$(STAGING_DIR)/usr/include \
-I$(STAGING_DIR)/usr/include/custommath \
-L$(STAGING_DIR)/usr/lib \
-o $(PKG_BUILD_DIR)/customtest \
$(PKG_BUILD_DIR)/src/test.c \
-lcustommath
endef
define Package/custom-staticlib-test/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/customtest $(1)/usr/bin/
endef
$(eval $(call BuildPackage,custom-staticlib-test))
DEPENDS:=+custom-staticlibensures the library builds first and is available in staging_dir.-I$(STAGING_DIR)/usr/includeand-I$(STAGING_DIR)/usr/include/custommathensure headers are found.-L$(STAGING_DIR)/usr/liband-lcustommathresolve the static library at link time.The resulting binary
customtestis installed into/usr/binon the target rootfs.
Run:
make package/custom-staticlib-test/{clean,compile} V=sc
Result:
bin/packages/x86_64/base/custom-staticlib-test-1.apk
During this build:
Header Resolution
$(STAGING_DIR)/usr/include/custommath/custommath.hprovides the function declarations. The compiler checks API correctness.Library Resolution
$(STAGING_DIR)/usr/lib/libcustommath.ais passed via-lcustommath. The linker extracts only needed object code.Static Linking The resulting binary contains all required library code internally; no dynamic libraries are needed at runtime.
RootFS Packaging The APK contains only:
/usr/bin/customtest
The static library is not included in the test APK.
Copy the packages into OpenWrt:
scp -P <QEMU_PORT> bin/packages/x86_64/base/custom-staticlib*.apk \
root@127.0.0.1:/tmp/
scp -P <QEMU_PORT> bin/packages/x86_64/base/custom-staticlib-test*.apk \
root@127.0.0.1:/tmp/
Install them:
apk add --allow-untrusted /tmp/custom-staticlib*.apk
apk add --allow-untrusted /tmp/custom-staticlib-test*.apk
Installing the static library first ensures headers and archive are present on the target if needed for local builds.
The test application installs into
/usr/bin/customtest.--allow-untrustedbypasses signature checks and is expected for developer-built packages.
Execute:
root@OpenWrt:~# customtest
Result from static library: 8
This proves:
the static library compiled correctly
staging_dir export worked
the test package successfully linked against the library
the application executed correctly on OpenWrt