linux系统Makefile解析

系统的Makefile文件

本文以某一类linux系统为例,分析该类linux系统中make的流程和原理。
打开makefile文件,在文件头部包含了变量定义和头文件包含,如下所示;

TOPDIR := ${shell pwd | sed -e 's/ /\\ /g'}
MEMSTATS =
-include $(TOPDIR)/.config
include $(TOPDIR)/tools/Config.mk
-include $(TOPDIR)/Make.defs

TOPDIR := ${shell pwd | sed -e 's/ /\\ /g'}:定义一个TOPDIR 的变量,该变量的值为{shell pwd | sed -e 's/ /\\ /g'}的执行结果,sed -e 's/ /\\ /g'该表达式为sed流编辑器的表达式,意思是跳过pwd执行后字符串里的空格;

sed替换命令格式为sed -i  "s/oldstring/goalstring/g" file, -i为直接修改源文件,如果被替换的字符里包含有特殊字符,比如“/”、“\”等,这种情况下可以将sed语句里的分隔符‘/’换成‘#’,比如:sed -i 's#/#$(DELIM)#g' test;或者是在特殊符号之前加上转义字符‘\’,例如sed -i 's/\//\\/g' test;

关于sed流编辑器的详细用法,可参考http://www.cnblogs.com/cbscan/articles/2277351.html

2-5行为当前Makefile所依赖的头文件,这里需要说明下include和-include的区别;

使用“include FILENAMES...”,make程序处理时,如果“FILENAMES”列表中的任何一个文件不能正常读取而且不存在一个创建此文件的规则时make程序将会提示错误并退出。

使用“-include FILENAMES...”的情况是,当所包含的文件不存在或者不存在一个规则去创建它,make程序会继续执行,只有真正由于不能正确完成终极目标的重建时(某些必需的目标无法在当前已读取的makefile文件内容中找到正确的重建规则),才会提示致命错误并退出。

(TOPDIR)/.config文件定义了一些系统和CPU等的宏定义和开关,比如;

CONFIG_HOST_LINUX=y

CONFIG_ARCH_ARM=y
CONFIG_ARCH="arm"

CONFIG_ARCH_CORTEXR4=y
CONFIG_ARCH_FAMILY="armv7-r"
CONFIG_ARCH_CHIP="s5j"
CONFIG_ARCH_HAVE_FPU=y

打开(TOPDIR)/tools/Config.mk文件,可以看到里面定义的东西;

OBJEXT ?= .o
LIBEXT ?= .a

此处需要强调一下Makefile文件里=, :=, ?=, +=的区别:

= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值

define COMPILEXX
@echo "CXX: $1"
$(Q) $(CXX) -c $(CXXFLAGS) $1 -o $2
endef

define COMPILE
@echo "CC: $1"
$(Q) $(CC) -c $(CFLAGS) $1 -o $2
endef

定义c++和c交叉编译工具,通过CXX变量将CXXFLAGS的文件编译生成对应的.0文件;通过CC变量将CFLAGS的文件编译生成对应的.0文件;

$(TOPDIR)/Make.defs文件除了定义一些OS配置相关的变量外,还定义了交叉编译类型;

CC = $(CROSSDEV)gcc
CXX = $(CROSSDEV)g++
CPP = $(CROSSDEV)gcc -E
LD = $(CROSSDEV)ld
AR = $(CROSSDEV)ar rcs
NM = $(CROSSDEV)nm
OBJCOPY = $(CROSSDEV)objcopy
OBJDUMP = $(CROSSDEV)objdump

同时还定义了各个交叉编译类型的条件,比如是否使用内建函数,对编译警告的处理,对编译优化的处理等等;

CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES)                           $(ARCHDEFINES) $(EXTRADEFINES) -pipe -ffunction-sections -fda    ta-sections
CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS)
CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHWARNINGSXX) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe
CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS)
CPPFLAGS = $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES)
AFLAGS = $(CFLAGS) -D__ASSEMBLY__

all:所有需要生成的最终文件;memstat为查看共享库的内存占用;

.PHONY:目标并非实际的文件名:只是在显式请求时执行命令的名字。有两种理由需要使用PHONY 目标:避免和同名文件冲突,改善性能。phony 目标并非是由其它文件生成的实际文件,make 会跳过隐含规则搜索;这就是声明phony 目标会改善性能的原因,即使你并不担心实际文件存在与否。

关于PHONY的更多知识,可以参考http://blog.chinaunix.net/uid-28458801-id-3452277.html

# This is the name of the final target (relative to the top level directorty)
BIN_EXE = tinyara$(EXEEXT)
BIN = $(BIN_DIR)/$(BIN_EXE)
all: $(BIN) memstat
.PHONY: context clean_context check_context export subdir_clean clean subdir_distclean distclean apps_clean apps_distclean force_build

此处是对库文件的替换,如果CONFIG_ARCH_FLOAT_H=y,则用include/tinyara/float.h替换掉include/float.h;

ifeq ($(CONFIG_ARCH_FLOAT_H),y)
include/float.h: include/tinyara/float.h
$(Q) cp -f include/tinyara/float.h include/float.h
else
include/float.h:
endif

force_build为一个伪目标,其作用是保证伪目标的执行命令执行;然后进入tools/mkversion$(HOSTEXEEXT)下执行make指令;然后进入$(TOPDIR)/.version路径下,常见.version文件,写入版本号,修改文件权限;

force_build:

tools/mkversion$(HOSTEXEEXT):
$(Q) $(MAKE) -C tools -f Makefile.host TOPDIR="$(TOPDIR)"  mkversion$(HOSTEXEEXT)

$(TOPDIR)/.version: force_build
echo "create .version file"; \
tools/version.sh -v 1.0 .version; \
chmod 755 .version

include/apps: Make.defs包含apps路径下的Make.defs文件,如果APPDIR不为空,log输出相关的include路径;

include/apps: Make.defs
ifneq ($(APPDIR),)
@echo "LN: include/apps to $(APPDIR)/include"
$(Q) if [ -d $(TOPDIR)/$(APPDIR)/include ]; then \
$(DIRLINK) $(TOPDIR)/$(APPDIR)/include include/apps; \
fi
endif

context:上下文目标和目标库文件;if语句的意思是如果BIN目标文件存在,则删除;for语句为对CONTEXTDIRS变量的值(路径)开始逐一进行$(MAKE) -C $$dir TOPDIR="$(TOPDIR)" context语句;即在TOPDIR路径下执行make命令,context为所依赖的上下文文件;最后通过$(call DELFILE, $(APPDIR)/builtin/registry/*.?dat)删除临时文件;

context: check_context iotivity_context include/tinyara/config.h include/tinyara/version.h include/math.h include/float.h include/stdarg.h dirlinks
$(Q)if [ -e ${BIN} ]; then \
echo "Previous Build Outputs - $(BIN_DIR) - are deleted"; \
rm -rf ${BIN_DIR}/*; \
fi
$(Q) for dir in $(CONTEXTDIRS) ; do \
$(MAKE) -C $$dir TOPDIR="$(TOPDIR)" context; \
done
$(call DELFILE, $(APPDIR)/builtin/registry/*.?dat)

clean:当执行makefile clean的时候,会执行clean伪指令下的语句,call函数是唯一一个可以创建定制参数化的函数的引用函数。我们可以将一个变量定义为一个复杂的表达式,用“call”函数根据不同的参数对它进行展开来获得不同的结果,这里是指删除与后面的表达式相关的文件;

clean: subdir_clean
$(call DELFILE, $(BIN_DIR)/*)
$(call DELFILE, _SAVED_APPS_config)
$(call DELFILE, tinyara-export*)
$(call DELFILE, tinyara_user*)
$(call CLEAN)


系统makefile所包含的makefile

LibTargets.mk为系统makefile所include的一个makefile文件之一,该文件定义了生成APP所依赖的驱动文件和顶层库文件,此处列举一个驱动为例;当执行系统makefile文件时,运行到“include LibTargets.mk”语句,此时会进入LibTargets.mk文件进行语句展开和执行; 如果此时定义了CONFIG_ZIGBEE宏定义,则会进入到与该驱动相关的路径下执行“$(Q) $(MAKE) -C drivers$(DELIM)zigbee TOPDIR="$(TOPDIR)" libzigbee$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE)”语句,即运行该驱动路劲下的makefile文件;

include LibTargets.mk

展开后为:

ifeq ($(CONFIG_ZIGBEE),y)
os$(DELIM)drivers$(DELIM)zigbee$(DELIM)libzigbee$(LIBEXT): context
$(Q) $(MAKE) -C drivers$(DELIM)zigbee TOPDIR="$(TOPDIR)" libzigbee$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE)

进入drivers/zigbee路径下的makefile之后,可以看到include src$(DELIM)components$(DELIM)Make.defs,查看对应路径的Make.defs文件;

CSRCS 为系统定义的源文件变量,此处将需要编译的.c文件添加到CSRCS 变量即可;下面是对编译库变量的添加,只需要添加当前路径就OK了;

CSRCS += af.c
CSRCS += af_ep.c
CSRCS += af_tx.c

# Include zigbee devices build support

DEPPATH += --dep-path src$(DELIM)components$(DELIM)stack$(DELIM)af
VPATH += :src$(DELIM)components$(DELIM)stack$(DELIM)af
CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)zigbee$(DELIM)src$(DELIM)components$(DELIM)stack$(DELIM)af}

回归到driver/zigbee下的makefile文件;all为目标文件,depend后为需要编译的源文件,$(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep 为编译当前路径下所链接到的所有的C文件,将结果输出到对应的Make.dep文件里。

all: $(BIN)

$(AOBJS): %$(OBJEXT): %.S
 $(call ASSEMBLE, $<, $@)

$(COBJS): %$(OBJEXT): %.c
 $(call COMPILE, $<, $@)

$(BIN): $(OBJS)
 $(call ARCHIVE, $@, $(OBJS))

.depend: Makefile $(SRCS)
 $(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
 $(Q) touch $@

depend: .depend

clean:
 $(call DELFILE, $(BIN))
 $(call CLEAN)

distclean: clean
 $(call DELFILE, Make.dep)
 $(call DELFILE, .depend)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容