openwrt創建應用軟件包和內核軟件包 Makefile的講解

不是我寫的,是官網的內容,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種選擇,

  1. 編譯進內核;
  2. 編譯成可加載的內核模塊;
  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))
發佈了26 篇原創文章 · 獲贊 39 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章