Skip to main content
Every OpenWrt package is a directory containing a Makefile that describes how to download, build, and install the software. The build system reads this Makefile and handles cross-compilation, dependency resolution, and .ipk package generation automatically.

Package directory structure

Packages live under package/<category>/<name>/ in the OpenWrt source tree, or in a feed repository. The typical layout is:
package/utils/mypackage/
├── Makefile          # Package definition (required)
├── files/            # Config files and init scripts to install
│   ├── mypackage.init
│   └── mypackage.conf
└── patches/          # Patches applied to upstream source
    └── 001-fix-build.patch
  • Makefile — the only required file. Defines source location, build instructions, and installed files.
  • files/ — static files that are copied into the package during Package/<name>/install. Useful for UCI defaults, init scripts, and default configs.
  • patches/ — quilt-managed patches applied to the upstream source after unpacking. Patches are applied in filename order.

Creating a minimal package

The following walkthrough creates a simple package for a hypothetical C program called hello.
1

Create the package directory

Create a directory under the appropriate category. Use utils for general utilities:
mkdir -p package/utils/hello
2

Write the Makefile

Create package/utils/hello/Makefile with the following content:
include $(TOPDIR)/rules.mk

PKG_NAME:=hello
PKG_VERSION:=2.12.1
PKG_RELEASE:=1

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://ftp.gnu.org/gnu/hello/
PKG_HASH:=8d99142afd92576f30b0cd7cb42a8dc6809998bc5d607d88761f512e26c7db20

PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=COPYING
PKG_MAINTAINER:=Your Name <you@example.com>

include $(INCLUDE_DIR)/package.mk

define Package/hello
  SECTION:=utils
  CATEGORY:=Utilities
  TITLE:=The GNU Hello World program
  URL:=https://www.gnu.org/software/hello/
endef

define Package/hello/description
  GNU Hello prints a friendly greeting. It serves as a reference
  for best practices in GNU packaging.
endef

define Build/Configure
  $(call Build/Configure/Default)
endef

define Build/Compile
  $(call Build/Compile/Default)
endef

define Package/hello/install
  $(INSTALL_DIR) $(1)/usr/bin
  $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/hello $(1)/usr/bin/
endef

$(eval $(call BuildPackage,hello))
The last line, $(eval $(call BuildPackage,hello)), registers the package with the build system. Every package Makefile must end with one or more of these calls.
3

Understand the key variables

VariablePurpose
PKG_NAMEPackage name, also used as the build directory name
PKG_VERSIONUpstream version string
PKG_RELEASEOpenWrt packaging revision (increment when the Makefile changes without a version bump)
PKG_SOURCETarball filename to download
PKG_SOURCE_URLURL(s) to download the tarball from (space-separated, tried in order)
PKG_HASHSHA-256 hash of the downloaded source tarball
PKG_LICENSESPDX license identifier
PKG_LICENSE_FILESPath(s) to license file(s) inside the source tree
4

Define the package metadata

The define Package/<name> block sets the metadata visible in make menuconfig:
define Package/hello
  SECTION:=utils
  CATEGORY:=Utilities
  TITLE:=The GNU Hello World program
  DEPENDS:=+libpthread
  URL:=https://www.gnu.org/software/hello/
endef
  • SECTION — opkg section (e.g., base, libs, utils, net).
  • CATEGORY — top-level menuconfig category (e.g., Base system, Utilities, Network).
  • TITLE — short one-line description shown in menuconfig.
  • DEPENDS — space-separated list of package dependencies. Prefix with + for runtime deps and @ for config symbol conditions.
5

Define the install step

The Package/<name>/install block is called when assembling the .ipk. The argument $(1) is the staging directory that maps to the root filesystem:
define Package/hello/install
  $(INSTALL_DIR) $(1)/usr/bin
  $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/hello $(1)/usr/bin/
endef
Common install helpers:
MacroUsage
$(INSTALL_DIR)Create a directory (with parents)
$(INSTALL_BIN)Install an executable file (mode 0755)
$(INSTALL_DATA)Install a data file (mode 0644)
$(INSTALL_CONF)Install a config file (mode 0600)
$(CP)Copy files or directories recursively
6

Add config files (optional)

Static files in the files/ directory are available during the install step. A common pattern for init scripts:
define Package/hello/install
  $(INSTALL_DIR) $(1)/usr/bin
  $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/hello $(1)/usr/bin/
  $(INSTALL_DIR) $(1)/etc/init.d
  $(INSTALL_BIN) ./files/hello.init $(1)/etc/init.d/hello
endef
The path ./files/ is relative to the package Makefile directory.
7

Build and test the package

From the OpenWrt source root, build only your package:
make package/hello/compile V=s
The V=s flag enables verbose output. If the build succeeds, the .ipk file is placed in bin/packages/<arch>/<feed>/.To also run the pack step and produce the installable archive:
make package/hello/{compile,pack} V=s
To clean and rebuild from scratch:
make package/hello/clean
make package/hello/compile V=s

Using a git source instead of a tarball

For packages that track a git repository, replace the tarball variables with:
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/example/mypackage.git
PKG_SOURCE_DATE:=2025-01-15
PKG_SOURCE_VERSION:=abc1234def5678abc1234def5678abc1234def56
PKG_MIRROR_HASH:=<sha256 of the generated tarball>
When PKG_SOURCE_VERSION is set, PKG_VERSION is derived automatically from PKG_SOURCE_DATE and an abbreviated commit hash.
Always set PKG_MIRROR_HASH for git sources. This is the SHA-256 of the generated .tar.zst archive, not the git commit. Generate it by running the download step once: make package/mypackage/download V=s and then hashing the file in dl/.

Adding patches

Patches are stored in patches/ and managed with quilt. They are applied automatically during the prepare step.
# Enter the package build directory and add a patch
make package/hello/prepare V=s QUILT=1
cd build_dir/target-*/hello-*/
quilt new 010-fix-build.patch
quilt add src/hello.c
# edit src/hello.c ...
quilt refresh
# copy patches back
cd <openwrt root>
make package/hello/update QUILT=1
Patch filenames should be numbered to control application order (e.g., 010-description.patch).

Build system helpers

For packages that use autoconf or CMake, include the appropriate helper instead of writing manual Build/Configure and Build/Compile blocks:
include $(INCLUDE_DIR)/package.mk
# autotools.mk is included by package.mk automatically

# Override configure arguments if needed
CONFIGURE_ARGS += --disable-debug

# Build/Configure and Build/Compile use defaults
# No explicit definitions needed for standard autotools packages