Makefile语法
C语言编译过程
预处理:将.h和.c文件处理为.i文件
编译:将.i文件编译为.s文件(汇编文件)
汇编:将.s文件编译为.o文件(二进制文件)
链接:将.o文件链接为.out文件(可执行文件)
GCC编译器参数
gcc -E hello.c > a.txt 只激活预处理,把程序重定向到a.txt文件。
gcc -S hello.c 只激活预处理和编译,把程序编译成汇编文件。
gcc -c hello.c 只激活预处理,编译和汇编,把程序编译成obj文件。
gcc -o hello.exe hello.c 指定输出文件名称,默认为a.out。
gcc -O0 -O1 -O2 -O3 编译器4个优化等级,-O0表示不优化;-O1表示默认值,-O3优化等级最高。
GNU 的 make 工作时的执行步骤
1、读入所有的 Makefile。
2、读入被 include 的其它 Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。
make参数
-C <dir> 读取指定makefile目录,当使用-C参数时,-w会自动被打开。
-I <dir> 指定一个包含makefile的目录
--include-dir=<dir> 指定一个包含makefile的目录
-j <jobsnum> 指同时运行命令的个数
-r 禁止make使用任何隐含规则
-R 禁止make使用任何作用于变量上的隐含规则
-w/--print-directory 进入和退出目录时,会输出Entering directory和Leaving directory。
-s/--slient/--quiet 进入和退出目录时,不会输出Entering directory和Leaving directory,-w总是失效的。
--no-print-directory 进入和退出目录时,不会输出Entering directory和Leaving directory,-w总是失效的。
Makefile文件包含
include 如果找不到包含文件,make就停止。
sinclude 如果找不到包含文件,忽略该错误,继续执行。
Makefile文件注释
#这是一行注释
Makefile格式
目标文件 : 依赖文件
(Tab)命令
核心:依赖文件中有一个文件比目标文件新,或者目标文件不存在,就要执行命令。
通配符
*
?
[]
"%" 的意思是表示一个或多个任意字符。
make变量
SHELL
MAKEFLAGS (该变量定义了make参数)
注意:除非使用unexport声明,否则这两个变量都将传递给下级Makefile。
传递变量
export 变量名 (传递变量到下级Makefile)
export (传递所有变量到下级Makefile)
unexport 变量名 (不传递变量到下级Makefile)
环境变量
KBUILD_EXTMOD //编译外部模块,设置源码路径
内置变量
CURDIR := /home/zht # 记录当前路径
SHELL = /bin/sh
MAKEFILE_LIST := Makefile
.DEFAULT_GOAL := all
MAKEFLAGS = p
HOSTARCH := x86_64
CC = cc # C语言编译器的名称
CPP = $(CC) -E # C语言预处理器的名称 $(CC) -E
CXX = g++ # C++语言的编译器名称
RM = rm -f # 删除文件程序的名称
CFLAGS # C语言编译器的编译选项,无默认值
CPPFLAGS # C语言预处理器的编译选项,无默认值
CXXFLAGS # C++语言编译器的编译选项,无默认值
......
自动化变量
$@:目标文件集合
规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模式中定义的目标集合。
$%
当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件,那么其值为空。
$<:第一个依赖文件
依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么“$<”就是符合模式的一系列的文件集合。
$?
所有比目标新的依赖目标集合,以空格分开。
$^:依赖文件集合
所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,“$^”会去除重复的依赖文件,值保留一份。$+ 和“$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。
$*
这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模式为 a.%.c,那么“$*”就是 test/a.test。
变量赋值
定义变量 objects = main.o kbd.o command.o display.o
$() 引用变量 $(objects)
= 变量的值是整个makefile文件中最后被指定的值,最后展开变量。
:= 定义的变量不能使用后面定义的变量,只能使用前面定义好的变量。
?= 变量是否被定义过,未定义则赋值,定义过则什么也不做。
+= 追加变量值
文件搜索
VPATH变量
VPATH变量=src:../headers
设置VPATH变量目录为src和../headers,其中目录名用:隔开。
make默认会在当前目录寻找依赖和目标文件,如果找不到,才会到指定的目录中去寻找文件。
vpath关键字
显示命令 @
echo:在shell中显示echo这条命令和这条命令的输出结果。
@echo:不会在shell中显示echo这条命令,但是会显示命令的输出结果。
执行命令 连续执行
如果你要让上一条命令的结果应用在下一条命令时,应该使用分号分隔这两条命令。
exec:
cd /home/hchen; pwd
命令出错 在命令行前加-
clean:
rm -f *.o //如果出错,不再执行。
-rm -f *.o //不管是否出错,都执行。
伪目标 .PHONY
all clean install print tar dist TAGS check test
清理工程
make clean //清除编译的可执行文件和配置文件。
make distclean //清除所有生成的文件。
条件编译
ifeq(a,b) else endif //判断a和b是否相等
ifneq(a,b) else endif //判断a和b是否不等
ifdef(a) else endif //判断a是否被定义
ifndef(a) else endif //判断a是否未被定义
shell函数
格式:name := $(shell 命令)
shell函数把执行操作系统命令后的输出作为函数返回。我们可以用操作系统命令以及字符串处理命令awk,sed等命令来生成一个变量。
contents := $(shell cat foo)
files := $(shell echo *.c)
函数调用
函数调用格式:
$(<function> <arguments>)
字符串处理函数
$(subst <from>,<to>,<text>)
$(patsubst <pattern>,<replacement>,<text>)
$(strip <string>)
$(findstring <find>,<in>)
$(filter <pattern...>,<text>)
$(filter-out <pattern...>,<text>)
$(sort <list>)
$(word <n>,<text>)
$(wordlist <s>,<e>,<text>)
$(words <text>)
$(firstword <text>)
文件名操作函数
$(dir <names...>)
$(notdir <names...>)
$(suffix <names...>)
$(basename <names...>)
$(addsuffix <suffix>,<names...>)
$(addprefix <prefix>,<names...>)
$(join <list1>,<list2>)
$(foreach <var>,<list>,<text>)
$(if <condition>,<then-part>)
$(call <expression>,<parm1>,<parm2>,<parm3>...)
$(origin <variable>) //查看变量的来源
函数返回值:
undefined //variable变量未定义,返回undefined。
default //variable是一个环境变量,并且当Makefile被执行时,-e参数没有被打开。
file //variable变量被定义在Makefile中,返回file。
command line //variable变量被命令行定义。
override //被override指示符重新定义。
automatic //是一个命令运行中的自动化变量。
C程序的隐含规则
“<n>.o”的目标的依赖目标会自动推导为“<n>.c”,并且其生成命令是“$(CC) –c $(CPPFLAGS) $(CFLAGS)”
Makefile代码分析
make (不带参数) 当make后不带参数时,默认执行第一个伪目标的操作。
make clean 清楚操作
make copy 复制操作
make install 安装操作
KERNELDIR := /home/chen/Linux/linux_kernel/linux_kernel
CURRENT_PATH := $(shell pwd)
obj-m := helloworld.o
obj-y +=xxx.o 该模块编译进内核文件。
obj-m +=xxx.o 该模块不会编译成可加载模块。
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
install:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules_install
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
copy:
sudo cp *.ko /home/chen/Linux/nfs/buildroot-rootfs/lib/modules/4.1.15 -f