Adding a Custom Package to the OpenWrt Build System
Background
OpenWrt provides a well-structured build framework. To add a custom package, place a standard Makefile in the designated directory, and the build system will automatically parse it and compile the source using the appropriate toolchains.
Custom packages reside under the SDK root at the path openwrt/package.
The directory layout for each package follows a consistent pattern:
package
├── files
├── Makefile
└── src
├── main.c
└── Makefile
This article focuses on the top-level Makefile.
Examples
You can compile both userspace applications and kernel modules. The sections below provide practical examples.
Userspace Application
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=data-logger
PKG_VERSION:=1.0
include $(INCLUDE_DIR)/package.mk
define Package/data-logger
SECTION:=utils
CATEGORY:=Custom Utilities
MAINTAINER:=Developer Team
DEPENDS:=
TITLE:=Data Logger Utility
endef
define Package/data-logger/Description
A simple data logging utility for embedded devices.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) -u ./src/* $(PKG_BUILD_DIR)/
endef
define Package/data-logger/install
$(INSTALL_DIR) $(1)/etc
$(INSTALL_DATA) ./filesystem/etc/data-logger.config $(1)/etc
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/data-logger $(1)/usr/bin
endef
$(eval $(call BuildPackage,data-logger))
Kernel Module
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=data-logger
PKG_VERSION:=0.1
define KernelPackage/data-logger
SECTION:=kernel
CATEGORY:=Kernel Modules
MAINTAINER:=Developer Team
DEPENDS:=
TITLE:=Data Logger Kernel Module
FILES:=$(PKG_BUILD_DIR)/data_logger.ko
AUTOLOAD:=$(call AutoLoad,99,data_logger)
endef
define KernelPackage/data-logger/description
Kernel module that intercepts and logs network data.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) -u ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(LINUX_DIR) M=$(PKG_BUILD_DIR) $(strip $(MAKE_OPTS))
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include
$(CP) $(PKG_BUILD_DIR)/data_logger.h $(1)/usr/include
endef
define KernelPackage/data-logger/install
$(INSTALL_DIR) $(1)/etc
endef
$(eval $(call KernelPackage,$(PKG_NAME)))
Combined Package (Userspace + Kernel)
It is possible to define both a userspace aplication and a kernel module within the same package. The crucial difference lies in invoking both BuildPackage and KernelPackage at the end.
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=data-guard
PKG_VERSION:=1.0
include $(INCLUDE_DIR)/package.mk
define KernelPackage/$(PKG_NAME)
SECTION:=kernel
CATEGORY:=Custom Security Modules
MAINTAINER:=Security Team
DEPENDS:=
TITLE:=Data Guard Kernel Engine
FILES:=$(PKG_BUILD_DIR)/ipt/data-guard.ko
AUTOLOAD:=$(call AutoLoad,99,data-guard)
endef
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
TARGET_LDFLAGS += -L$(STAGING_DIR)/usr/lib
TARGET_LDFLAGS += -L$(STAGING_DIR)/lib
CORE_DEPENDS:=+libc
GUARD_MAKE_OPTS:=
ifeq ($(CONFIG_CUSTOM_FEATURE), y)
EXTRA_CFLAGS += -I$(LINUX_DIR)/../bcmkernel/include
EXTRA_CFLAGS += -DCONFIG_CUSTOM_FEATURE=1
endif
TARGET_LDFLAGS += -L$(STAGING_DIR)/usr/lib
GUARD_MAKE_OPTS+= \
CROSS_COMPILE=$(KERNEL_CROSS) \
ARCH=$(LINUX_KARCH) \
KERNELPATH="$(LINUX_SRC_DIR)" \
KBUILDPATH=$(LINUX_DIR) \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
SUBDIRS=$(PKG_BUILD_DIR)
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Custom Security Modules
TITLE:=Data Guard Management Utility
MAINTAINER:=Security Team
DEPENDS:=$(CORE_DEPENDS)
endef
define KernelPackage/$(PKG_NAME)/description
In-kernel filtering engine for the Data Guard framework.
endef
define Package/$(PKG_NAME)/Description
Userspace configuration and logging tool for Data Guard.
endef
define Package/$(PKG_NAME)/config
config PACKAGE_GUARD_VENDOR
string "vendor identifier (required)"
default security_vendor
config PACKAGE_GUARD_VERSION
string "guard version (required)"
default A.B.C
config PACKAGE_GUARD_USE_NF
bool "Use Netfilter queue for packet inspection"
default n
endef
CONFIG_PACKAGE_GUARD_USE_NF ?= y
ifeq ($(CONFIG_PACKAGE_GUARD_USE_NF), y)
SRC_PATH:=nf
CORE_DEPENDS+=+libnetfilter-queue +libpcap
else #CONFIG_PACKAGE_GUARD_USE_NF
SRC_PATH:=ipt
CORE_DEPENDS+=+iptables
endif #CONFIG_PACKAGE_GUARD_USE_NF
GUARD_VENDOR ?= $(CONFIG_PACKAGE_GUARD_VENDOR)
GUARD_VERSION ?= $(CONFIG_PACKAGE_GUARD_VERSION)
GUARD_USE_NF ?= $(CONFIG_PACKAGE_GUARD_USE_NF)
$(info $$GUARD_VENDOR is [${GUARD_VENDOR}])
$(info $$GUARD_VERSION is [${GUARD_VERSION}])
$(info $$GUARD_USE_NF is [${GUARD_USE_NF}])
INSTALL_BIN:=$(SRC_PATH)/data-guard
INSTALL_LIB:=$(SRC_PATH)/libxt_guard.so
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) -u ./src-$(GUARD_VENDOR)/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)/$(SRC_PATH) \
$(TARGET_CONFIGURE_OPTS) \
TARGET_LDFLAGS="$(TARGET_LDFLAGS)" \
TARGET_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
GUARD_VERSION="$(GUARD_VERSION)" \
CC="$(TARGET_CC)"
$(MAKE) -C $(LINUX_DIR) M=$(PKG_BUILD_DIR)/$(SRC_PATH) GUARD_VERSION=$(GUARD_VERSION) $(strip $(GUARD_MAKE_OPTS))
endef
define Package/$(PKG_NAME)/install
$(CP) -rf ./filesystem/* $(1)/
$(INSTALL_DIR) $(1)/usr/lib/guard/
$(CP) $(PKG_BUILD_DIR)/sdk-$(GUARD_VERSION)/lib/* $(1)/usr/lib/guard/
$(INSTALL_DIR) $(1)/usr/bin
$(if $(INSTALL_BIN),$(CP) $(foreach bin,$(INSTALL_BIN),$(PKG_BUILD_DIR)/$(bin)) $(1)/usr/bin/)
$(INSTALL_DIR) $(1)/usr/lib/iptables
$(if $(INSTALL_LIB),$(CP) $(foreach lib,$(INSTALL_LIB),$(PKG_BUILD_DIR)/$(lib)) $(1)/usr/lib/iptables/)
endef
define Build/InstallDev
endef
define KernelPackage/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc
endef
$(eval $(call KernelPackage,$(PKG_NAME)))
$(eval $(call BuildPackage,$(PKG_NAME)))
Inside the src directory, the userspace application still uses a regular Makefile, while the kernel module relies on the Kbuild system:
MODULE_NAME = data-guard
$(MODULE_NAME)-objs := data-guard-kmod.o component.o
obj-m += $(MODULE_NAME).o