一個(gè)實(shí)際的Makefile
include $(TOPDIR)/rules.mk
PKG_NAME:=capture-data
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/capture-data
SECTION:=utils
CATEGORY:=Utilities
TITLE:=capture-data -- prints a snarky message
DEPENDS:=+libxxx +xxlib +libxxx +libxxx # 需要的庫(kù)
endef
define Package/capture-data/description
If you can't figure out what this program does, you're probably
brain-dead and need immediate medical attention.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/capture-data/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/capture-data $(1)/bin/
endef
$(eval $(call BuildPackage,capture-data))
引入文件
OpenWrt 使用三個(gè) makefile 的子文件,分別為:
- include $(TOPDIR)/rules.mk
- $(TOPDIR)/rules.mk 一般在 Makefile 的開(kāi)頭,
- include $(INCLUDE_DIR)/kernel.mk
- $(INCLUDE_DIR)/kernel.mk 文件對(duì)于軟件包為內(nèi)核時(shí)是不可缺少,
- include $(INCLUDE_DIR)/package.mk
- $(INCLUDE_DIR)/package.mk 一般在軟件包的基本信息完成后再引入。
由 這 些 makefile 子 文 件 確 立 軟 件 包 加 入 OpenWrt 的 方 式 和 方 法 。
編寫(xiě)軟件包的基本信息
軟件包的信息均以 PKG_開(kāi)頭,其意思和作用如下:
- PKG_NAME 表示軟件包名稱,將在 menuconfig 和 ipkg 可以看到。
- PKG_VERSION 表示軟件包版本號(hào)。
- PKG_RELEASE 表示 Makefile 的版本號(hào)。
- PKG_SOURCE 表示源代碼的文件名。
- PKG_SOURCE_URL 表示源代碼的下載網(wǎng)站位置。
- @SF 表示在 sourceforge 網(wǎng)站,
- @GNU 表示在 GNU 網(wǎng)站,
- @GNOME、 @KERNEL。
- PKG_MD5SUM 表示源代碼文件的效驗(yàn)碼。用于核對(duì)軟件包是否正確下載。
- PKG_CAT 表示源代碼文件的解壓方法。包括 zcat, bzcat, unzip 等。
- PKG_BUILD_DIR 表示軟件包編譯目錄。它的父目錄為$(BUILD_DIR)。如果不指定,
默認(rèn)為$(BUILD_DIR)/$( PKG_NAME)/$( PKG_VERSION)。
- 編譯包定義
應(yīng)用程序和內(nèi)核驅(qū)動(dòng)模塊的定義不一樣。- 應(yīng)用程序軟件包使用 Package,
- 內(nèi)核驅(qū)動(dòng)模塊使用 KernelPackage。
應(yīng)用程序編譯包定義
應(yīng)用程序的編譯包以 Package/開(kāi)頭,然后接著軟件名,在 Package 定義中的軟件名
可以與軟件包名不一樣,而且可以多個(gè)定義。
下面使用$(PKG_NAME)只是做一個(gè)標(biāo)示,并非真正使用$(PKG_NAME),如 Package/$(PKG_NAME)。
1. SECTION 表示包的類型,預(yù)留。
2. CATEGORY 表示分類,在 make menuconfig 的菜單下將可以找到。
3. TITLE 用于軟件包的簡(jiǎn)短描述。
4. DESCRIPTION 用于軟件包的詳細(xì)描述,已放棄使用。
如果使用 DESCRIPTION 將會(huì)提示“ error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description”。URL 表示軟件包的下載位置。
5. MAINTAINER 表示維護(hù)者,選項(xiàng)。
6. DEPENDS 表示與其他軟件的依賴。即如編譯或安裝需要其他軟件時(shí)需要說(shuō)明。
如果存在多個(gè)依賴,則每個(gè)依賴需要用空格分開(kāi)。
依賴前使用+號(hào)表示默認(rèn)為顯示,即對(duì)象沒(méi)有選中時(shí)也會(huì)顯示,使用@則默認(rèn)為不顯示,即當(dāng)依賴對(duì)象選中后才顯示。
在用戶空間的應(yīng)用程序軟件包中沒(méi)有內(nèi)核驅(qū)動(dòng)模塊的 AUTOLOAD 參數(shù)。
如果應(yīng)用軟件需要在 boot 時(shí)自動(dòng)運(yùn)行,則需要在/etc/init.d 中增加相應(yīng)的腳本文件。
腳本文件需要START 參數(shù),說(shuō)明在 boot 時(shí)的優(yōu)先級(jí), 如果在 boot 過(guò)程啟動(dòng)后再關(guān)閉,則需要進(jìn)一步設(shè)置 STOP 參數(shù)。
如果 STOP 參數(shù)存在, 其值必須大于 START。
腳本文件需要 start()和 stop()兩個(gè)函數(shù), start()是執(zhí)行程序, stop()是關(guān)閉程序。
關(guān)閉程序一般需要執(zhí)行 killall 命令。
由/etc/rc.d/S10boot 知道,裝載內(nèi)核驅(qū)動(dòng)模塊的優(yōu)先級(jí)為 10,
需要使用自己設(shè)計(jì)的內(nèi)核驅(qū)動(dòng)模塊的程序其 START 的值必須大于 10。
同樣由/etc/rc.d/S40network 知道, 使用網(wǎng)絡(luò)通信的程序其 START 的值必須大于 40。
Package/$(PKG_NAME)/conffiles
本包安裝的配置文件,一行一個(gè)。如果文件結(jié)尾使用/,則表示為目錄。
用于備份配置文件說(shuō)明,在 sysupgrade 命令執(zhí)行時(shí)將會(huì)用到。
Package/$(PKG_NAME)/description
軟件包的詳細(xì)描述,取代前面提到的 DESCRIPTION 詳細(xì)描述。
Build/Prepare
編譯準(zhǔn)備方法,對(duì)于網(wǎng)上下載的軟件包不需要再描述。對(duì)于非網(wǎng)上下載或自行開(kāi)發(fā)的軟
件包必須說(shuō)明編譯準(zhǔn)備方法。一般的準(zhǔn)備方法為:
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
按 OpenWrt 的習(xí)慣,一般把自己設(shè)計(jì)的程序全部放在 src 目錄下。
Build/Configure
在 Automake 中需要進(jìn)行./configure,所以本配置方法主要針對(duì)需要配置的軟件包而設(shè)計(jì),
一般自行開(kāi)發(fā)的軟件包可以不在這里說(shuō)明。需要使用本定義的情況,可參考dropbear。
Build/Compile 編譯方法,沒(méi)有特別說(shuō)明的可以不予以定義。
如果不定義將使用默認(rèn)的編譯方法 Build/Compile/Default。
自行開(kāi)發(fā)的軟件包可以考慮使用下面的定義。
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) CFLAGS="$(TARGET_CFLAGS)
-I$(LINUX_DIR)/include"
endef
Package/$(PKG_NAME)/install
軟件包的安裝方法,包括一系列拷貝編譯好的文件到指定位置。
調(diào)用時(shí)會(huì)帶一個(gè)參數(shù),就是嵌入系統(tǒng)的鏡像文件系統(tǒng)目錄,因此$(1)表示嵌入系統(tǒng)的鏡像目錄。
一般可以采用下面的方法:
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ $(PKG_NAME) $(1)/usr/bin/
endef
INSTALL_DIR、 INSTALL_BIN 在$(TOPDIR)/rules.mk 文件定義,所以本 Makefile
必須引入$(TOPDIR)/rules.mk 文件。
INSTALL_DIR :=install -d -m0755 意思是創(chuàng)建所屬用戶可讀寫(xiě)和執(zhí)行,其他用戶可讀可執(zhí)行的目錄。
INSTALL_BIN:=install -m0755 意思編譯好的文件存放到鏡像文件目錄。
如果用戶空間的應(yīng)用軟件在 boot 時(shí)要自動(dòng)運(yùn)行,
則需要在安裝方法說(shuō)明中增加自動(dòng)運(yùn)行的腳本文件安裝和配置文件安裝方法。 例如:
define Package/mountd/install
$(INSTALL_DIR) $(1)/sbin/ $(1)/etc/config/ $(1)/etc/init.d/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mountd $(1)/sbin/
$(INSTALL_DATA) ./files/mountd.config $(1)/etc/config/mountd
$(INSTALL_BIN) ./files/mountd.init $(1)/etc/init.d/mountd
endef
安裝文件放在 files 子目錄下,不要與源代碼文件目錄 src 混在一起,以提高可讀性。
使用清晰的文件擴(kuò)展名,更方便安裝識(shí)別文件。
Package/$(PKG_NAME)/preinst
軟件包安裝前處理方法,使用腳本語(yǔ)言,因此定義的第一行需要下面的格式
#!/bin/sh
調(diào)用時(shí)帶入的參數(shù)為嵌入式系統(tǒng)的鏡像目錄。
Package/$(PKG_NAME)/postinst
軟件包安裝后處理方法,使用腳本語(yǔ)言。
Package/$(PKG_NAME)/prerm
軟件包刪除前處理方法,使用腳本語(yǔ)言。
Package/$(PKG_NAME)/postrm
軟件包刪除后處理方法,使用腳本語(yǔ)言。
內(nèi)核驅(qū)動(dòng)模塊包定義
Linux 分為內(nèi)核空間和用戶空間。
開(kāi)發(fā)者開(kāi)發(fā)的內(nèi)核部分可以直接加入 Linux 的 Kernel 程序,也可以生成內(nèi)核模塊以便需要時(shí)裝入內(nèi)核。
OpenWrt 一般希望開(kāi)發(fā)者生成內(nèi)核模塊,在 Linux 啟動(dòng)后自動(dòng)裝載或手工使用 insmod 命令裝載。
內(nèi)核模塊使用KernelPackage 開(kāi)頭,其他與一般應(yīng)用軟件包基本相同。
在內(nèi)核驅(qū)動(dòng)模塊定義中增加了:
SUBMENU 表示子菜單位置 ,在 $(INCLUDE)/kernel.mk對(duì)內(nèi)核模塊定義了
CATEGORY 為 kernel modules,所以內(nèi)核模塊在 menuconfig 中的主菜單為 kernel
modules , 然 后 有 下 一 級(jí) 子 菜 單 $(SUBMENU) 。 在子菜單下可以看到以
kmod-$(PKG_NAME)項(xiàng)目。
DEFAULT 表示直接編入內(nèi)核或產(chǎn)生內(nèi)核模塊,y 表示直接編入內(nèi)核,m 表示產(chǎn)生內(nèi)核模塊。
AUTOLOAD 表示自動(dòng)裝入內(nèi)核,一般表示方法為:
AUTOLOAD:=$(call AutoLoad, $(PRIORITY),$(AUTOLOAD_MODS))
AutoLoad 的第一個(gè)參數(shù)$(PRIORITY)為優(yōu)先級(jí),01 為最優(yōu)先,99 為最后裝載。有
關(guān)自動(dòng)裝載可以在/etc/modules.d 目錄下看到,第二個(gè)參數(shù)$(AUTOLOAD_MODS)模塊
名,每個(gè)模塊名以空格符分隔。即可同時(shí)裝載多個(gè)內(nèi)核模塊。
在開(kāi)發(fā)過(guò)程最好不要使用自動(dòng)裝載,經(jīng)過(guò)嚴(yán)格調(diào)試后再使用,可以減輕調(diào)試的工作量。
使用定義
完成前面定義后,必須使用 eval 函數(shù)實(shí)現(xiàn)各種定義。
其格式為:
- 對(duì)于一般應(yīng)用軟件包
$(eval $(call Package,$(PKG_NAME))) - 內(nèi)核驅(qū)動(dòng)模塊
$(eval $(call KernelPackage,$(PKG_NAME)))
如果一個(gè)軟件包有多個(gè)程序,例如:一個(gè)應(yīng)用程序有自己的內(nèi)核驅(qū)動(dòng)模塊,上面使用的PKG_NAME 需要靈活變通。
eval 函數(shù)可以設(shè)計(jì)多個(gè)。也可以當(dāng)成多個(gè)軟件包處理。