1.指定头文件目录
(1)系统目录
(2)可以指定 -i的大写
2.库文件在哪
(1)系统目录,工具链
(2)自已指定的库文件目录 -L
(3)指定库文件 -l
1.Makefile
规则:
目标文件:依赖文件(当依赖比目标新)
Test: a.o b.o
gcc -o test a.o b.o
a.o : a.c
gcc -c -o a.o a.c
b.o : b.c
gcc -c -o b.o b.c
Makefile其实挺简单
一个简单的Makefile文件包含一系列的“规则”,其样式如下:
目标(target)…: 依赖(prerequiries)…
<tab>命令(command)
如果“依赖文件”比“目标文件”更加新,那么执行“命令”来重新生成“目标文件”。
命令被执行的2个条件:依赖文件比目标文件新,或是 目标文件还没生成。
先介绍Makefile的2个函数
A. $(foreach var,list,text)
简单地说,就是 for each var in list, change it to text。
对list中的每一个元素,取出来赋给var,然后把var改为text所描述的形式。
例子:
objs := a.o b.o
dep_files := $(foreach f, $(objs), .$(f).d) // 最终 dep_files := .a.o.d .b.o.d
B. $(wildcard pattern)
pattern所列出的文件是否存在,把存在的文件都列出来。
例子:
src_files := $( wildcard *.c) // 最终 src_files中列出了当前目录下的所有.c文件
2.Makefile语法
A.通配符:%.o
$@ 表示目标
$< 表示第一个依赖
$^ 表示所有依赖文件
test: a.o b.o c.o
gcc -o test $^
%.o : %.c
gcc -c -o $@ $<
clean:
rm *.o test
.PHONY clean把clean设为假想目标
即时变量,延时变量,export
A := XXX #A的值即可确定
B = xxx #B的值使用才确定
?= 延时变量,只有第一次起效
+= #附加,它是即时还是附加取决前面的定义
A := $(C)
B = $(C)引用
C = 123
All:
@echo $(A) 引用
@echo $(B)
2.makefile函数
(1).
A = a b c
B = $(foreach f, $(A), $(f).o)
all:
@echo B = $(B)
(2).
$(filter pattern..,text) 在text中取出符合patten格式的值
$(filter-out pattern..,text) 在text中取出不符合patten格式的值
$(wildcard pattern) #pattern定义文件格式,wildcard取出其中存在文件
比如:
C =a b c d
D =$(filter %/,
(
c
)
)
E
=
(c)) E =
(c))E=(fileter-out %/, $©)从中取出
files = $(wildcard *.c)
all:
@echo B = $(B)
@echo D = $(D)
@ECHO E = $(E)
@echo files = $(files)
$(patsubst pattern, replacement, $(var))) 取出来做些替换
命令:
gcc -c -o c.o c.c -MD -MF c.d既生成C.O又生成依赖文件
objs = a.o b.o c.o
dep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))
CFLAGS = -Werror -Iinclude
test: $(objs)
gcc -o test $^
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc $(CFLAGS) -c -o $@
<
−
M
D
−
M
F
.
< -MD -MF .
<−MD−MF.@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean
编译驱动makefile示例:
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
#KERN_DIR = /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4
KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o oled_test oled_test.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order oled_test
# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o
obj-m += oled_drv.o
通用Makefile的使用
① 零星知识点
A. make命令的使用:
执行make命令时,它会去当前目录下查找名为“Makefile”的文件,并根据它的指示去执行操作,生成第一个目标。
我们可以使用“-f”选项指定文件,不再使用名为“Makefile”的文件,比如:
make -f Makefile.build
我们可以使用“-C”选项指定目录,切换到其他目录里去,比如:
make -C a/ -f Makefile.build
我们可以指定目标,不再默认生成第一个目标:
make -C a/ -f Makefile.build other_target
B. 即时变量、延时变量:
变量的定义语法形式如下:
A = xxx // 延时变量
B ?= xxx // 空赋值,只有第一次定义时赋值才成功;如果曾定义过,此赋值无效
C := xxx // 立即变量
D += yyy // 如果D在前面是延时变量,那么现在它还是延时变量;
// 如果D在前面是立即变量,那么现在它还是立即变量
在GNU make中对变量的赋值有两种方式:延时变量、立即变量。
上图中,变量A是延时变量,它的值在使用时才展开、才确定。比如:
A = $@
test:
@echo $A
上述Makefile中,变量A的值在执行时才确定,它等于test,是延时变量。
如果使用“A :=
@
”
,
这
是
立
即
变
量
,
这
时
@”,这是立即变量,这时
@”,这是立即变量,这时@为空,所以A的值就是空。
C. 变量的导出(export):
在编译程序时,我们会不断地使用“make -C dir”切换到其他目录,执行其他目录里的Makefile。如果想让某个变量的值在所有目录中都可见,要把它export出来。
比如“CC = $(CROSS_COMPILE)gcc”,这个CC变量表示编译器,在整个过程中都是一样的。定义它之后,要使用“export CC”把它导出来。
② 通用Makefile的设计思想
A. 在Makefile文件中确定要编译的文件、目录,比如:
obj-y += main.o
obj-y += a/
“Makefile”文件总是被“Makefile.build”包含的。
B. 在Makefile.build中设置编译规则,有3条编译规则:
i. 怎么编译子目录? 进入子目录编译:
$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build
ii. 怎么编译当前目录中的文件?
%.o : %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<
iii. 当前目录下的.o和子目录下的built-in.o要打包起来:
built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^
C. 顶层Makefile中把顶层目录的built-in.o链接成APP:
$(TARGET) : built-in.o
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o