本文将与大家一起来研究OpenWrt包的Makefile格式以及其工作原理
上面一篇博文中,博主尝试创建一个非常简单的helloworld包,
本文将带大家一起深入地学习一下OpenWrt包的 Makefile。我们不仅要知其然,还要知其所以然。
在上篇博文里,包里的 Makefile 内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
include $(TOPDIR)
/rules
.mk
PKG_NAME:=helloworld
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)
/package
.mk
define Package
/helloworld
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Helloworld -- prints a snarky message
endef
define Package
/helloworld/description
It's my first package demo.
endef
define Build
/Prepare
echo
"Here is Package/Prepare"
mkdir
-p $(PKG_BUILD_DIR)
$(CP) .
/src/
* $(PKG_BUILD_DIR)/
endef
define Package
/helloworld/install
echo
"Here is Package/install"
$(INSTALL_DIR) $(1)
/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)
/helloworld
$(1)
/bin/
endef
$(
eval
$(call BuildPackage,helloworld))
|
大概我们可以将简代为如下的结构:
1
2
3
4
5
6
7
8
9
|
include $(TOPDIR)
/rules
.mk
# 这里定义一系列的 PKG_XX
include $(INCLUDE_DIR)
/package
.mk
# 定义各种 Package, Build 宏
$(
eval
$(call BuildPackage,包名))
|
下面,我们来一一拆解。
include $(TOPDIR)/rules.mk
首先,include $(TOPDIR)/rules.mk,也就是将 SDK/rules.mk 文件中的内容导入进来。
TOPDIR就是SDK的路径。
在 SDK/rules.mk 文件中,定义了许多变量。
我们可以看出,在Makefile中,赋值是用 := ,而不是等号。
比如上面的 BUILD_DIR, INCLUDE_DIR 等,都在这里定义。还有:
还有关于 TARGET_CC, TARGET_CXX 等非常有用的变量定义。
还有 TAR, FIND, INSTALL_BIN, INSTALL_DIR, INSTALL_DATA等等非常重要的变量定义。
自定义 PKG_XXXX 变量
include $(INCLUDE_DIR)/package.mk
跟上面的 include $(TOPDIR)/rules.mk 是一样的。就是把这个文件包含进来。
INCLUDE_DIR这个变量在 rules.mk 里已经定义了:
那就是 SDK/include/package.mk 文件了,打开看看。
主要有以下几个功能:
(1)它会配置默认的变量
如果某个变量我们没有在上一部分里定义,那里在这个文件里,它就会被指定为默认值,比如:
上面的用 ?= 来表示给未定义的变量赋默认值。比如,如果没有指定 PKG_MD5SUM,那么就默认为 unknow。
(2)推导其它变量
根据上部分用户自定义的 PKG_XXXX 变量推导出更多相关的变量。
比如:
虽然我没有看过相关的手册,根据多年的从业经验也能看出上面的意思来。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#如果定义了宏,就...
ifdef 宏名
...
endif
#如果宏相等
ifeq (宏1,宏2)
...
endif
strip $宏名
#将宏对应的值去除前后的空白字符
VAR += xxxx
#在变量 VAR 后面追加 xxxx
|
我猜大概就是这样,如果不对请指正。
再比如如下:
就这样,它为我们提供了大量有价值的变量。
(3)包含其它mk文件
(4)定义默认宏
在 Makefile 中,宏的定义格式是:
1
2
3
|
define XXX
/xxxx
<宏的实体...>
endef
|
package.mk会把大部分需要的宏都定义好。理想情况下,用户只需要定义好了 PKG_XXX 之后,不需要再自定义宏,默认的宏就可以满足需求。
比如Build/Prepare/Default的定义:
Build/Prepare宏是在编译前进行的,是准备工作。
可以看出,它分了两种情况:
A,定义了 USE_GIT_TREE,则按git的方式定义。
B,定义了 USB_SOURCE_DIR,则按源码在本地的方案定义。
最重要的一个宏是 BuildPackage。它会在 Makefile 的最后一行被引用。它的实现也就是在 package.mk 文件里。如下为其源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
define BuildPackage
$(Build
/IncludeOverlay
)
$(
eval
$(Package
/Default
))
$(
eval
$(Package/$(1)))
ifdef DESCRIPTION
$$(error DESCRIPTION:= is obsolete, use Package
/PKG_NAME/description
)
endif
ifndef Package/$(1)
/description
define Package/$(1)
/description
$(TITLE)
endef
endif
BUILD_PACKAGES += $(1)
$(STAMP_PREPARED): $$(
if
$(QUILT)$(DUMP),,$(call find_library_dependencies,$(DEPENDS)))
$(foreach FIELD, TITLE CATEGORY SECTION VERSION,
ifeq ($($(FIELD)),)
$$(error Package/$(1) is missing the $(FIELD) field)
endif
)
$(
if
$(DUMP), \
$(Dumpinfo
/Package
), \
$(foreach target, \
$(
if
$(Package/$(1)
/targets
),$(Package/$(1)
/targets
), \
$(
if
$(PKG_TARGETS),$(PKG_TARGETS), ipkg) \
), $(BuildTarget/$(target)) \
) \
)
$(
if
$(PKG_HOST_ONLY)$(DUMP),,$(call Build
/DefaultTargets
,$(1)))
endef
|
总结一下语法:
$() 表示要执行的一条语句
$(if 条件, )
自定义宏
<明天待续>
使之生效
$(eval $(call BuildPackage,helloworld))
https://www.python.org/users/rethjtjhdhtrh/index.html
http://xifyy3.sourceforge.net/index.html
http://sourceforge.net/projects/xifyy3/index.html
http://vfghsdb.sourceforge.net/index.html
http://sourceforge.net/projects/vfghsdb/index.html
http://sourceforge.net/u/fehgtehr/profile/
https://www.python.org/users/rethjtjhdhtrh/
http://xifyy3.sourceforge.net/
http://sourceforge.net/projects/xifyy3/
http://vfghsdb.sourceforge.net/
http://sourceforge.net/projects/vfghsdb/
https://www.python.org/users/ghtejjtj534645/
https://www.python.org/users/ghtejjtj534645/
https://www.python.org/users/bffg543rretr/
https://www.python.org/users/hytikjyjyrjt/
https://www.python.org/users/dgertherh/
https://www.python.org/users/%E6%96%87%E6%98%8C%E5%93%AA%E9%87%8C%E6%9C%89%E5%AD%A6%E7%94%9F%E5%A6%B9%E6%9C%8D%E5%8A%A1/
https://www.python.org/users/%E6%96%87%E6%98%8C%E6%89%BE%E7%BE%8E%E5%A5%B3%E6%9C%8D%E5%8A%A1/
http://www.python.org/users/ghtejjtj534645/
http://www.python.org/users/ghtejjtj534645/
http://www.python.org/users/bffg543rretr/
http://www.python.org/users/hytikjyjyrjt/
http://www.python.org/users/dgertherh/
http://www.python.org/users/%E6%96%87%E6%98%8C%E5%93%AA%E9%87%8C%E6%9C%89%E5%AD%A6%E7%94%9F%E5%A6%B9%E6%9C%8D%E5%8A%A1/
http://www.python.org/users/%E6%96%87%E6%98%8C%E6%89%BE%E7%BE%8E%E5%A5%B3%E6%9C%8D%E5%8A%A1/