不是我寫的,是官網的內容,https://wiki.openwrt.org/zh-cn/doc/devel/packages
目的是爲了自己查閱
我們已經嘗試做的一件事情,是讓移植軟件到OpenWrt的操作變得非常容易。如果打開OpenWrt裏的一個軟件包的目錄(OpenWrt/Package/* 或 OpenWrt/feeds/packages/*/*),通常會發現幾樣東西:
-
package/Makefile [必備]
-
package/patches/ [可選]
-
package/files/ [可選]
patches目錄和files目錄都是可選的,pactches目錄通常包括bug修復和對可執行文件體積的優化,files目錄通常包括配置文件。你也可能看到其它目錄,因爲只要在Makefile文件中指明,目錄名字是可以任取的。前面兩個是約定俗成的做法,強烈建議你也這麼做。
Makefile文件最關鍵,一般來說它提供了下載、編譯、安裝這個軟件包的步驟。
當我們打開這裏的Makefile文件,很難認出這是一個Makefile。它的格式跟一般的Makefile不一樣,因爲它的功能跟普通Makefile就是不一樣的。它是一種編寫方便的模板。
這裏,以package/bridge/Makefile文件爲例:
include $(TOPDIR)/rules.mk PKG_NAME:=bridge PKG_VERSION:=1.0.6 PKG_RELEASE:=1 PKG_BUILD_DIR:=$(BUILD_DIR)/bridge-utils-$(PKG_VERSION) PKG_SOURCE:=bridge-utils-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=@SF/bridge PKG_MD5SUM:=9b7dc52656f5cbec846a7ba3299f73bd PKG_CAT:=zcat include $(INCLUDE_DIR)/package.mk define Package/bridge SECTION:=base CATEGORY:=Network TITLE:=Ethernet bridging configuration utility #DESCRIPTION:=This variable is obsolete. use the Package/name/description define instead! URL:=http://bridge.sourceforge.net/ endef define Package/bridge/description Ethernet bridging configuration utility Manage ethernet bridging; a way to connect networks together to form a larger network. endef define Build/Configure $(call Build/Configure/Default,--with-linux-headers=$(LINUX_DIR)) endef define Package/bridge/install $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/brctl/brctl $(1)/usr/sbin/ endef $(eval $(call BuildPackage,bridge))
軟件包變量
建立一個軟件包不需要太多工作;大部分工作都隱藏在其它的 makefiles 中,編寫工作被抽象成對幾個變量的賦值。
-
PKG_NAME -軟件包的名字, 在 menuconfig 和 ipkg 顯示
-
PKG_VERSION -軟件包的版本,主幹分支的版本正是我們要下載的
-
PKG_RELEASE -這個 makefile 的版本
-
PKG_BUILD_DIR -編譯軟件包的目錄
-
PKG_SOURCE -要下載的軟件包的名字,一般是由 PKG_NAME 和 PKG_VERSION 組成
-
PKG_SOURCE_URL -下載這個軟件包的鏈接
-
PKG_MD5SUM -軟件包的 MD5 值
-
PKG_CAT -解壓軟件包的方法 (zcat, bzcat, unzip)
-
PKG_BUILD_DEPENDS -需要預先構建的軟件包,但只是在構建本軟件包時,而不是運行的時候。它的語法和下面的DEPENDS一樣。
PKG_*變量定義了從何處下載這個軟件包;@SF是表示從sourceforge網站下載的一個特殊關鍵字。md5sum用來檢查從網上下載的軟件包是否完好無損。PKG_BUILD_DIR定義了軟件包源代碼的解壓路徑。
注意到上面示例文件底部的最後一行嗎?這是最爲關鍵的BuildPackage宏。它是在$(INCLUDE_DIR)/package.mk文件裏定義的。BuildPackage宏只要求一個參數,即要編譯的軟件包名,在本例中是"bridge"。所有其他信息都通過宏來獲得,這提供了一種內在的簡潔性。比如BuildPackage需要軟件包的一大串描述信息,我們並不要向它傳遞冗長的參數,因爲我們已經約定描述信息定義在DESCRIPTION宏,BuildPackage從裏面讀取就可以了。
BuildPackage相關的宏
Package/
描述軟件包在menuconfig和ipkg中的信息,可以定義如下變量:
-
SECTION - 軟件包類型 (尚未使用)
-
CATEGORY - menuconfig中軟件包所屬的一級目錄,如Network
-
SUBMENU - menuconfig中軟件包所屬的二級目錄,如dial-in/up
-
TITLE - 軟件包標題
-
DESCRIPTION - 軟件包的詳細說明
-
URL - 軟件的原始位置,一般是軟件作者的主頁
-
MAINTAINER - (optional) 軟件包維護人員
-
DEPENDS - (optional) 依賴項,運行本軟件依賴的其他包
Package/conffiles (可選)
軟件包需要複製的配置文件列表,一個文件佔一行
Build/Prepare (可選)
一組解包源代碼和打補丁的命令,一般不需要。
Build/Configure (可選)
如果源代碼編譯前需要configure且指定一些參數,就把這些參數放在這兒。否則可以不定義。
Build/Compile (可選)
編譯源代碼命令。
Package/install
軟件安裝命令,主要是把相關文件拷貝到指定目錄,如配置文件。
Package/preinst
軟件安裝之前被執行的腳本,別忘了在第一句加上#!/bin/sh。如果腳本執行完畢要取消安裝過程,直接讓它返回false即可。
Package/postinst
軟件安裝之後被執行的腳本,別忘了在第一句加上#!/bin/sh。
Package/prerm
軟件刪除之前被執行的腳本,別忘了在第一句加上#!/bin/sh。如果腳本執行完畢要取消刪除過程,直接讓它返回false即可。
Package/postrm
軟件刪除之後被執行的腳本,別忘了在第一句加上#!/bin/sh。
爲什麼一些定義是"Package/"前綴,另一些定義卻是"Build"前綴?這是因爲我們支持一個特性:從單個源代碼構建多個軟件包。OpenWrt工作在一個Makefile對應一個源代碼的假設之上,但是你可以把編譯生成的程序分割成任意多個軟件包。因爲編譯只要一次,所以使用全局的"Build"定義是最合適的。然後你可以增加很多“Package/"定義,爲各軟件包分別指定安裝方法。建議你去看看dropbear包,這是一個很好的示範。
提示:對於所有在pre/post, install/removal腳本中使用的變量,都應該使用"$$"代替"$"。這是告訴make暫時不要解析這個變量,而是把它當成普通字符串以及用"$"代替"$$"。 – 更多信息
在編輯好Makefile文件,並放到指定目錄後,這個新的軟件包將在下次執行make menuconfig時出現,你可以選擇這個軟件包,保存退出,用make編譯。現在就把一個軟件成功移植到OpenWrt中了!
創建內核模塊軟件包
內核模塊是一類擴展Linux內核功能的可安裝程序。內核模塊的加載發生在內核加載之後,(比如使用insmod命令)。
Linux源代碼包含了很多內核應用程序。在menuconfig時有3種選擇,
-
編譯進內核;
-
編譯成可加載的內核模塊;
-
不編譯。
參看FIX:Customizingthekerneloptions customizing the kernel options
要包含這些內核模塊,只要make menuconfig選擇相應的內核模塊選項。(參看Build Configuration)。如果在make menuconfig時沒有發現想要的內核模塊,必須添加一個stanza到package/kernel/modules目錄的一個文件中。下面是一個從package/kernel/modules/other.mk提取出來的例子。
define KernelPackage/loop TITLE:=Loopback device support DESCRIPTION:=Kernel module for loopback device support KCONFIG:=$(CONFIG_BLK_DEV_LOOP) SUBMENU:=$(EMENU) AUTOLOAD:=$(call AutoLoad,30,loop) FILES:=$(MODULES_DIR)/kernel/drivers/block/loop.$(LINUX_KMOD_SUFFIX) endef $(eval $(call KernelPackage,loop))
此外,你還可以添加不屬於Linux源碼包的內核模塊。在這種情況下,內核模塊放在package/目錄,跟通常的軟件包是一樣的。package/Makefile文件使用KernelPackage/xxx定義代替Package/xxx。
這是package/madwifi/Makefile的例子:
# # Copyright (C) 2006 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # # $Id$ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=madwifi PKG_VERSION:=0.9.2 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=@SF/$(PKG_NAME) PKG_MD5SUM:=a75baacbe07085ddc5cb28e1fb43edbb PKG_CAT:=bzcat PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) include $(INCLUDE_DIR)/package.mk RATE_CONTROL:=sample ifeq ($(ARCH),mips) HAL_TARGET:=mips-be-elf endif ifeq ($(ARCH),mipsel) HAL_TARGET:=mips-le-elf endif ifeq ($(ARCH),i386) HAL_TARGET:=i386-elf endif ifeq ($(ARCH),armeb) HAL_TARGET:=xscale-be-elf endif ifeq ($(ARCH),powerpc) HAL_TARGET:=powerpc-be-elf endif BUS:=PCI ifneq ($(CONFIG_LINUX_2_4_AR531X),) BUS:=AHB endif ifneq ($(CONFIG_LINUX_2_6_ARUBA),) BUS:=PCI AHB # no suitable HAL for AHB yet. endif BUS_MODULES:= ifeq ($(findstring AHB,$(BUS)),AHB) BUS_MODULES+=$(PKG_BUILD_DIR)/ath/ath_ahb.$(LINUX_KMOD_SUFFIX) endif ifeq ($(findstring PCI,$(BUS)),PCI) BUS_MODULES+=$(PKG_BUILD_DIR)/ath/ath_pci.$(LINUX_KMOD_SUFFIX) endif MADWIFI_AUTOLOAD:= \ wlan \ wlan_scan_ap \ wlan_scan_sta \ ath_hal \ ath_rate_$(RATE_CONTROL) \ wlan_acl \ wlan_ccmp \ wlan_tkip \ wlan_wep \ wlan_xauth ifeq ($(findstring AHB,$(BUS)),AHB) MADWIFI_AUTOLOAD += ath_ahb endif ifeq ($(findstring PCI,$(BUS)),PCI) MADWIFI_AUTOLOAD += ath_pci endif define KernelPackage/madwifi SUBMENU:=Wireless Drivers DEFAULT:=y if LINUX_2_6_BRCM | LINUX_2_6_ARUBA | LINUX_2_4_AR531X | LINUX_2_6_XSCALE, m if ALL TITLE:=Driver for Atheros wireless chipsets DESCRIPTION:=\ This package contains a driver for Atheros 802.11a/b/g chipsets. URL:=http://madwifi.org/ VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(BOARD)-$(PKG_RELEASE) FILES:= \ $(PKG_BUILD_DIR)/ath/ath_hal.$(LINUX_KMOD_SUFFIX) \ $(BUS_MODULES) \ $(PKG_BUILD_DIR)/ath_rate/$(RATE_CONTROL)/ath_rate_$(RATE_CONTROL).$(LINUX_KMOD_SUFFIX) \ $(PKG_BUILD_DIR)/net80211/wlan*.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,$(MADWIFI_AUTOLOAD)) endef MADWIFI_MAKEOPTS= -C $(PKG_BUILD_DIR) \ PATH="$(TARGET_PATH)" \ ARCH="$(LINUX_KARCH)" \ CROSS_COMPILE="$(TARGET_CROSS)" \ TARGET="$(HAL_TARGET)" \ TOOLPREFIX="$(KERNEL_CROSS)" \ TOOLPATH="$(KERNEL_CROSS)" \ KERNELPATH="$(LINUX_DIR)" \ LDOPTS=" " \ ATH_RATE="ath_rate/$(RATE_CONTROL)" \ DOMULTI=1 ifeq ($(findstring AHB,$(BUS)),AHB) define Build/Compile/ahb $(MAKE) $(MADWIFI_MAKEOPTS) BUS="AHB" all endef endif ifeq ($(findstring PCI,$(BUS)),PCI) define Build/Compile/pci $(MAKE) $(MADWIFI_MAKEOPTS) BUS="PCI" all endef endif define Build/Compile $(call Build/Compile/ahb) $(call Build/Compile/pci) endef define Build/InstallDev $(INSTALL_DIR) $(STAGING_DIR)/usr/include/madwifi $(CP) $(PKG_BUILD_DIR)/include $(STAGING_DIR)/usr/include/madwifi/ $(INSTALL_DIR) $(STAGING_DIR)/usr/include/madwifi/net80211 $(CP) $(PKG_BUILD_DIR)/net80211/*.h $(STAGING_DIR)/usr/include/madwifi/net80211/ endef define KernelPackage/madwifi/install $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/lib/modules/$(LINUX_VERSION) $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) ./files/madwifi.init $(1)/etc/init.d/madwifi $(CP) $(PKG_BUILD_DIR)/tools/{madwifi_multi,80211debug,80211stats,athchans,athctrl,athdebug,athkey,athstats,wlanconfig} $(1)/usr/sbin/ endef $(eval $(call KernelPackage,madwifi))