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?

OpenWrt packages must follow OpenWrt’s standard build workflow. A static library must:

  • build with OpenWrt’s cross-toolchain

  • export both header file and .a archive into the staging directory

  • install 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.c provides implementation logic compiled into an object file.

  • custommath.h exposes 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 original src/ 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) rcs archives the object file into the static library libcustommath.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.h

    • staging_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
  • clean deletes the build directory, forcing a full rebuild.

  • compile automatically triggers:

    • Prepare → copy sources

    • Compile → cross-compile and archive

    • InstallDev → populate staging_dir for downstream builds

    • Install → populate the target root filesystem layout

  • The produced .apk includes only what Package/custom-staticlib/install defines.

  • The staging_dir version of this library is not in the .apk but 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.h confirms header export to staging_dir.

  • Final binary will statically pull add (and possibly sub) from libcustommath.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-staticlib ensures the library builds first and is available in staging_dir.

  • -I$(STAGING_DIR)/usr/include and -I$(STAGING_DIR)/usr/include/custommath ensure headers are found.

  • -L$(STAGING_DIR)/usr/lib and -lcustommath resolve the static library at link time.

  • The resulting binary customtest is installed into /usr/bin on 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:

  1. Header Resolution $(STAGING_DIR)/usr/include/custommath/custommath.h provides the function declarations. The compiler checks API correctness.

  2. Library Resolution $(STAGING_DIR)/usr/lib/libcustommath.a is passed via -lcustommath. The linker extracts only needed object code.

  3. Static Linking The resulting binary contains all required library code internally; no dynamic libraries are needed at runtime.

  4. 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-untrusted bypasses 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