openwrt - makefile¶
概述¶
详细看英文原文
类似linux Kernel有自己的makefile体系,openwrt对于自己的package也有自己的编译脚本结构,这个是在openwrt植入自己的代码,或者将第三方的代码移植到openwrt的基础。
一个package下面一般有三个文件:
things | remark |
---|---|
Makefile | 这个文件是必须要的 这个Makefile指定了如下获取到源码,如果编译代码和安装文件 |
patches | 这个是补丁所在目录,可选的 如果该package是第三方提供的,为了不影响原来的仓库,可以通过打补丁的方式来修复bug或者适配目标设备 |
files | 这个文件是可选的,用来包含一些默认配置或者其他文件 |
src | 不是必须的 有些package不是从第三方下载代码的,代码是直接从该目录下获取 |
Makefile¶
An OpenWrt source package Makefile contains a series of header variable assignments, action recipes and one or multiple OpenWrt specific signature footer lines identifying it as OpenWrt specific package Makefile.
The patches directory¶
The
patches
directory must be placed in the same parent directory as theMakefile
file and may only contain patch files used to modify the source code being packaged.Patch files must be in unified diff format and carry the extension
.patch
. The file names must also carry a numerical prefix to denote the order in which the patch files must be applied. Patch file names should be concise and avoid characters other than ASCII alphanumerics and hyphens.Suitable patch file names could look like:
000-patch-makefile.patch
010-backport-frobnicate-crash-fix.patch
999-add-local-hack-for-openwrt-compatibility.patch
It is recommended to use Quilt to manage source package patch collections.
The files directory¶
Static files accompanying a source package, such as OpenWrt specific init scripts or configuration files, must be placed inside a directory called
files
, residing within the same subdirectory as theMakefile
. There are no strict rules on how such static files are to be named and organized within thefiles
directory but by convention, the extension.conf
is used for OpenWrt UCI configration files and the extension.init
is used to denote OpenWrt specific init scripts.The actual placement and naming of the resources within the
files
directory on the target system is controlled by the source package Makefile and unrelated to the structure and naming within thefiles
directory.
The src directory¶
Some packages do not actually fetch their program code from an external source but bundle the code to be compiled and packages directly within the package feed. This is usually done for packages which are specific to OpenWrt and do not exist outside of their respective package feed.
Sometimes the
src
directory may also be used to supply additional code to the compilation process, in addition to the program code fetched from external sources.If present, the OpenWrt build system will automatically copy the contents of the
src
directory verbatim to the compilation scratch directory (build directory) of the package, retaining the structure and naming of the files.
例子¶
helloworld¶
更详细直接看原文
- 在目录
/home/buildbot/helloworld
(或者其他目录)下创建一个helloworld.c文件, hellowold.c写入
在linux下直接运行gcc命令,可以编译出在本地linux的可执行文件
- 编写与openwrt兼容的Makefile
新建{openwrt根目录}/package/helloworld目录,在该目录新建Makefile文件
include $(TOPDIR)/rules.mk
# Name, version and release number
# The name and version of your package are used to define the variable to point to the build directory of your package: $(PKG_BUILD_DIR)
PKG_NAME:=helloworld
PKG_VERSION:=1.0
PKG_RELEASE:=1
# Source settings (i.e. where to find the source codes)
# This is a custom variable, used below
SOURCE_DIR:=/home/buildbot/helloworld
include $(INCLUDE_DIR)/package.mk
# Package definition; instructs on how and where our package will appear in the overall configuration menu ('make menuconfig')
define Package/helloworld
SECTION:=examples
CATEGORY:=Examples
TITLE:=Hello, World!
endef
# Package description; a more verbose description on what our package does
define Package/helloworld/description
A simple "Hello, world!" -application.
endef
# Package preparation instructions; create the build directory and copy the source code.
# The last command is necessary to ensure our preparation instructions remain compatible with the patching system.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
$(Build/Patch)
endef
# Package build instructions; invoke the target-specific compiler to first compile the source file, and then to link the file into the final executable
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/helloworld.o -c $(PKG_BUILD_DIR)/helloworld.c
$(TARGET_CC) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/$1 $(PKG_BUILD_DIR)/helloworld.o
endef
# Package install instructions; create a directory inside the package to hold our executable, and then copy the executable we built previously into the folder
define Package/helloworld/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin
endef
# This command is always the last, it uses the definitions and variables we give above in order to get the job done
$(eval $(call BuildPackage,helloworld))
- 执行make menuconfig 可以在上面找到helloworld的配置,勾选helloworld package,保存并退出
make package/helloworld/compile V=s # 单独编译helloworld
make package/helloworld/{clean,compile} V=s # 先清除再重新编译
cmake-based package¶
更多示例,自行在openwrt根目录下搜索,找到该种类型的package
下面以公司的主程序(pubmsg)进行展示。
pubmsg是cmake-based的package
如下所示,文件结构如下
{openwrt}/package/pubmsg
|-----files
|-----pubmsg.conf
|-----pubmsg.init
|-----src
|-----pubmsg.c
|-----CMakeLists.txt (pubmsg代码通过cmake来编译)
|-----Config.in (make menuconfig中看到的选项)
|-----Makefile (openwrt的Makefile)
CMakefiles.txt¶
该CMakefiles.txt会在openwrt的Makefile调用该cmake文件进行编译
cmake_minimum_required(VERSION 2.6)
PROJECT(pubmsg C)
INCLUDE(CheckFunctionExists)
FIND_PATH(uci_include_dir uci.h)
FIND_PATH(LIBEVENT_INCLUDE_DIR NAMES event.h)
FIND_LIBRARY(udev NAMES udev)
FIND_LIBRARY(evdev NAMES evdev)
FIND_LIBRARY(lzo2 NAMES lzo2)
FIND_LIBRARY(mosquitto NAMES mosquitto)
FIND_LIBRARY(urcu-cds NAMES urcu-cds)
FIND_LIBRARY(urcu-common NAMES urcu-common)
FIND_LIBRARY(urcu-memb NAMES urcu-memb)
FIND_LIBRARY(urcu NAMES urcu)
FIND_LIBRARY(curl NAMES curl)
FIND_LIBRARY(uci NAMES uci)
FIND_LIBRARY(mbedtls NAMES mbedtls)
FIND_LIBRARY(mbedx509 NAMES mbedx509)
FIND_LIBRARY(mbedcrypto NAMES mbedcrypto)
FIND_LIBRARY(ssl NAMES ssl)
FIND_LIBRARY(pthread NAMES pthread)
FIND_LIBRARY(ubox NAMES ubox)
FIND_LIBRARY(crypto NAMES crypto)
FIND_LIBRARY(event NAMES event)
FIND_LIBRARY(event_pthreads NAMES event_pthreads)
INCLUDE_DIRECTORIES(${uci_include_dir})
ADD_DEFINITIONS(-Os -Wall --std=gnu99 -g3)
# 声明宏的默认值
OPTION(CONFIG_PUBMSG_G1_E_GRAPES "Yancy ESL PUBMSG_G1_E_GRAPES" 0)
OPTION(CONFIG_PUBMSG_G1_D_PRO_ADVANCED "Yancy ESL PUBMSG_G1_D_PRO_ADVANCED" 0)
# 该宏定义是从openwrt的Makefile文件传递进来的,需要在cmake中赋值定义才生效
add_compile_definitions(CONFIG_PUBMSG_G1_E_GRAPES=${CONFIG_PUBMSG_G1_E_GRAPES})
add_compile_definitions(CONFIG_PUBMSG_G1_D_PRO_ADVANCED=${CONFIG_PUBMSG_G1_D_PRO_ADVANCED})
message(STATUS "CONFIG_PUBMSG_G1_E_GRAPES = ${CONFIG_PUBMSG_G1_E_GRAPES}")
message(STATUS "CONFIG_PUBMSG_G1_D_PRO_ADVANCED = ${CONFIG_PUBMSG_G1_D_PRO_ADVANCED}")
set(CMAKE_VERBOSE_MAKEFILE ON)
aux_source_directory(. CURRENT_SRC)
aux_source_directory(./libdict/src DICT_SRC)
aux_source_directory(./libdfu DFU_SRC)
aux_source_directory(./libbase BASE_SRC)
aux_source_directory(./libradio RADIO_SRC)
message(STATUS "CURRENT_SRC = ${CURRENT_SRC}")
message(STATUS "DICT_SRC = ${DICT_SRC}")
message(STATUS "DFU_SRC = ${DFU_SRC}")
message(STATUS "BASE_SRC = ${BASE_SRC}")
message(STATUS "RADIO_SRC = ${RADIO_SRC}")
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
IF(APPLE)
INCLUDE_DIRECTORIES(/opt/local/include)
LINK_DIRECTORIES(/opt/local/lib)
ENDIF()
include_directories(./
./libdict/include
./libbase
./libdfu
./libradio
)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -std=gnu99")
# 重新定义__FILE__, 防止打印日志时,把绝对路径也打印出来,仅仅截取相对路径
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
ADD_EXECUTABLE(${PROJECT_NAME} ${CURRENT_SRC} ${DFU_SRC} ${DICT_SRC} ${BASE_SRC} ${RADIO_SRC} )
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${urcu} ${pthread} ${ssl} ${lzo2} ${urcu-common} ${urcu-cds} ${urcu-memb} ${mbedtls} ${mbedx509} ${mbedcrypto}
${mosquitto} ${udev} ${evdev} ${crypto} ${ubox} ${curl} ${uci} ${event} ${event_pthreads})
INSTALL(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION sbin)
Config.in¶
该文件需要在openwrt的Makefile中调用才会生效
该配置文件用于定义一些宏定义,用于配置该package的属性
if PACKAGE_pubmsg-g1-e-grapes
config PUBMSG_G1_E_GRAPES_DEBUG
bool "Enable debug version build."
default n
help
This option enables assert and gdb symbol.
Disabled by default.
choice
prompt "Firmware model selection"
default PUBMSG_G1_E_GRAPES
help
Select the firmware model.
config PUBMSG_G1_E_GRAPES
bool "Yancy ESL g1-e-grapes"
config PUBMSG_G1_D_PRO_ADVANCED
bool "Yancy ESL g1-d-pro-advanced"
endchoice
endif
Makefile¶
#
# Copyright (C) 2015 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=pubmsg-g1-e-grapes
PKG_RELEASE:=1.0
PKG_LICENSE:=GPLv3
PKG_MAINTAINER:=Yancy
include $(INCLUDE_DIR)/package.mk
# 对于cmake-based的package,必须include cmake.mk,里面事先定义了一些函数
include $(INCLUDE_DIR)/cmake.mk
define Package/$(PKG_NAME)
CATEGORY:=Thingoo
DEPENDS:=+libmosquitto +liburcu +libcurl +libuci +libudev-fbsd +kmod-drv_regopt +liblzo +libevent2 +libevent2-pthreads
TITLE:=Main program $(PKG_NAME)
MENU:=1
SUBMENU:=Grapes
endef
define Package/$(PKG_NAME)/description
This package contains an main program to handle upstream and downstream
endef
# 调用上面提到的Config.in
define Package/$(PKG_NAME)/config
source "$(SOURCE)/Config.in"
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
$(CP) ./files/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += $(if $(CONFIG_PUBMSG_G1_E_GRAPES_DEBUG), -ggdb3)
CMAKE_OPTIONS += $(if $(CONFIG_PUBMSG_G1_E_GRAPES_DEBUG),-DCMAKE_BUILD_TYPE=Debug)
# 如果在make menuconfig勾选相应的选项,追加到CMAKE_OPTIONS变量中
CMAKE_OPTIONS += $(if $(CONFIG_PUBMSG_G1_E_GRAPES),-DCONFIG_PUBMSG_G1_E_GRAPES=1)
CMAKE_OPTIONS += $(if $(CONFIG_PUBMSG_G1_D_PRO_ADVANCED),-DCONFIG_PUBMSG_G1_D_PRO_ADVANCED=1)
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/pubmsg $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/usr/bin/autopubmsg $(1)/usr/bin
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/etc/init.d/pubmsg $(1)/etc/init.d
endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
# check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then
echo "Enabling rc.d symlink for pubmsg"
chmod 777 /etc/init.d/pubmsg
/etc/init.d/pubmsg enable
fi
exit 0
endef
define Package/$(PKG_NAME)/prerm
#!/bin/sh
# check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then
echo "Removing rc.d symlink for pubMessage"
/etc/init.d/pubmsg disable
fi
exit 0
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
automake-based package¶
对于第三方package需要使用automake来编译的, 运行如下命令搜索,可以直接找到相关的例子
比如: tcpdump的例子就比较典型
# vi package/network/utils/tcpdump/Makefile
#
# Copyright (C) 2007-2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=tcpdump
PKG_VERSION:=4.9.3
PKG_RELEASE:=3
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://www.tcpdump.org/release/
PKG_HASH:=2cd47cb3d460b6ff75f4a9940f594317ad456cfbf2bd2c8e5151e16559db6410
PKG_BUILD_PARALLEL:=1
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=BSD-3-Clause
PKG_CPE_ID:=cpe:/a:tcpdump:tcpdump
PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
define Package/tcpdump/default
SECTION:=net
CATEGORY:=Network
DEPENDS:=+libpcap
TITLE:=Network monitoring and data acquisition tool
URL:=http://www.tcpdump.org/
endef
define Package/tcpdump
$(Package/tcpdump/default)
VARIANT:=full
# 全功能版
endef
define Package/tcpdump-mini
$(Package/tcpdump/default)
TITLE+= (minimal version)
VARIANT:=mini
# 阉割版
endef
# CONFIGURE_ARGS变量是运行.configure传递进去的参数,你需要添加什么参数,直接在这个变量追加即可
CONFIGURE_ARGS += \
--without-cap-ng \
--without-crypto
ifeq ($(CONFIG_IPV6),y)
# 如果选择配置了IPV6,则在编译时使能ipv6
CONFIGURE_ARGS += \
--enable-ipv6
endif
TARGET_CFLAGS += -ffunction-sections -fdata-sections
TARGET_LDFLAGS += -Wl,--gc-sections
CONFIGURE_VARS += \
BUILD_CC="$(TARGET_CC)" \
HOSTCC="$(HOSTCC)" \
td_cv_buggygetaddrinfo="no" \
ac_cv_linux_vers=$(LINUX_VERSION) \
ac_cv_header_rpc_rpcent_h=no \
ac_cv_lib_rpc_main=no \
ac_cv_path_PCAP_CONFIG=""
MAKE_FLAGS :=
ifeq ($(BUILD_VARIANT),mini)
# 对于阉割版追加的变量
TARGET_CFLAGS += -DTCPDUMP_MINI
CONFIGURE_ARGS += --disable-smb
MAKE_FLAGS += TCPDUMP_MINI=1
endif
MAKE_FLAGS += \
CCOPT="$(TARGET_CFLAGS)" INCLS="-I. $(TARGET_CPPFLAGS)"
define Package/tcpdump/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/tcpdump $(1)/usr/sbin/
endef
Package/tcpdump-mini/install = $(Package/tcpdump/install)
$(eval $(call BuildPackage,tcpdump))
$(eval $(call BuildPackage,tcpdump-mini))
general package¶
普通使用原始Makefile的package
以下以maccal为例子
#
# Copyright (C) 2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=maccalc
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/maccalc
SECTION:=utils
CATEGORY:=Utilities
TITLE:=MAC address calculation
endef
define Package/maccalc/description
This package contains a MAC address manipulation utility.
endef
define Build/Configure
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS) -Wall" \
LDFLAGS="$(TARGET_LDFLAGS)"
endef
define Package/maccalc/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/maccalc $(1)/usr/sbin/
endef
$(eval $(call BuildPackage,maccalc))