7、RK3399J通用的Makefile语法和解析

    科技2022-07-10  142

    目录

    1、各级子目录的Makefile:2、顶层目录的Makefile:3、Makefile.build:4、怎么使用这套Makefile:(1)、把顶层Makefile, Makefile.build放入程序的顶层目录(2)、确定编译哪些源文件(2)、. 确定编译选项、链接选项(3)、 使用哪个编译器?(4)、确定应用程序的名字:(5)、 执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除 5、通用 Makefile 的解析(1) make 命令的使用:(2)即时变量、延时变量:(3) 变量的导出(export):(4) Makefile 中可以使用 shell 命令:(5)假想目标:(6)常用的函数:i. $(foreach var,list,text)ii. $(wildcard pattern) iii. $(filter pattern...,text)iv. $(filter-out pattern...,text)vi. $(patsubst pattern , replacement , text ) 6、通用 Makefile 的设计思想(1)、在 Makefile 文件中确定要编译的文件、目录,比如:(2)、 在 Makefile.build 中设置编译规则,有 3 条编译规则:(3)、 怎么编译当前目录中的文件?(4)、当前目录下的.o 和子目录下的 built-in.o 要打包起来:(5)、顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP: 7、情景演绎

    1、各级子目录的Makefile:

    它最简单,形式如下:

    EXTRA_CFLAGS := CFLAGS_file.o := obj-y += file.o obj-y += subdir/

    “obj-y += file.o” 表示把当前目录下的file.c编进程序里, “obj-y += subdir/” 表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。 “EXTRA_CFLAGS”, 它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置 “CFLAGS_xxx.o”, 它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置

    注意: 1. "subdir/"中的斜杠"/"不可省略 2. 顶层Makefile中的CFLAGS在编译任意一个.c文件时都会使用 3. CFLAGS EXTRA_CFLAGS CFLAGS_xxx.o 三者组成xxx.c的编译选项

    2、顶层目录的Makefile:

    它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外, 主要是定义工具链前缀CROSS_COMPILE, 定义编译参数CFLAGS, 定义链接参数LDFLAGS, 这些参数就是文件中用export导出的各变量。

    3、Makefile.build:

    这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o

    4、怎么使用这套Makefile:

    (1)、把顶层Makefile, Makefile.build放入程序的顶层目录

    在各自子目录创建一个空白的Makefile

    (2)、确定编译哪些源文件

    修改顶层目录和各自子目录Makefile的obj-y : obj-y += xxx.o obj-y += yyy/ 这表示要编译当前目录下的xxx.c, 要编译当前目录下的yyy子目录

    (2)、. 确定编译选项、链接选项

    修改顶层目录Makefile的CFLAGS,这是编译所有.c文件时都要用的编译选项; 修改顶层目录Makefile的LDFLAGS,这是链接最后的应用程序时的链接选项;

    修改各自子目录下的Makefile: “EXTRA_CFLAGS”, 它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置 “CFLAGS_xxx.o”, 它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置

    (3)、 使用哪个编译器?

    修改顶层目录Makefile的CROSS_COMPILE, 用来指定工具链的前缀(比如arm-linux-)

    (4)、确定应用程序的名字:

    修改顶层目录Makefile的TARGET, 这是用来指定编译出来的程序的名字

    (5)、 执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除

    5、通用 Makefile 的解析

    (1) make 命令的使用:

    执行 make 命令时,它会去当前目录下查找名为“Makefile”的文件,并根据它的指示去执行操作,生 成第一个目标。 我们可以使用“-f”选项指定文件,不再使用名为“Makefile”的文件,比如:

    make -f Makefile.build

    我们可以使用“-C”选项指定目录,切换到其他目录里去,比如:

    make -C a/ -f Makefile.build

    我们可以指定目标,不再默认生成第一个目标:

    make -C a/ -f Makefile.build other_target

    (2)即时变量、延时变量:

    变量的定义语法形式如下:

    A = xxx // 延时变量 B ?= xxx // 延时变量,只有第一次定义时赋值才成功;如果曾定义过,此赋值无效 C := xxx // 立即变量 D += yyy // 如果 D 在前面是延时变量,那么现在它还是延时变量;

    // 如果 D 在前面是立即变量,那么现在它还是立即变量 在 GNU make 中对变量的赋值有两种方式:延时变量、立即变量。

    上图中,变量 A 是延时变量,它的值在使用时才展开、才确定。比如:

    A = $@ test: @echo $A

    上述 Makefile 中,变量 A 的值在执行时才确定,它等于 test,是延时变量。 如果使用“A := @ ” , 这 是 立 即 变 量 , 这 时 @”,这是立即变量,这时 @@为空,所以 A 的值就是空。

    (3) 变量的导出(export):

    在编译程序时,我们会不断地使用“make -C dir”切换到其他目录,执行其他目录里的 Makefile。如 果想让某个变量的值在所有目录中都可见,要把它 export 出来。 比如“CC = $(CROSS_COMPILE)gcc”,这个 CC 变量表示编译器,在整个过程中都是一样的。定 义它之后,要使用“export CC”把它导出来。

    (4) Makefile 中可以使用 shell 命令:

    比如:

    TOPDIR := $(shell pwd)

    这是个立即变量,TOPDIR 等于 shell 命令 pwd 的结果。

    (5)假想目标:

    我们的 Makefile 中有这样的目标:

    clean: rm -f $(shell find -name "*.o") rm -f $(TARGET)

    如果当前目录下恰好有名为“clean”的文件,那么执行“make clean”时它就不会执行那些删除命令。 这时我们需要把“clean”这个目标,设置为“假想目标”,这样可以确保执行“make clean”时那些删 除命令肯定可以得到执行。 使用下面的语句把“clean”设置为假想目标:

    .PHONY : clean

    (6)常用的函数:

    i. $(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

    ii. $(wildcard pattern)

    pattern 所列出的文件是否存在,把存在的文件都列出来。 例子:

    src_files := $( wildcard *.c) // 最终 src_files 中列出了当前目录下的所有.c 文件 iii. $(filter pattern...,text)

    iii. $(filter pattern…,text)

    把 text 中符合 pattern 格式的内容,filter(过滤)出来、留下来。 例子:

    obj-y := a.o b.o c/ d/ DIR := $(filter %/, $(obj-y)) //结果为:c/ d/

    iv. $(filter-out pattern…,text)

    把 text 中符合 pattern 格式的内容,filter-out(过滤)出来、扔掉。 例子:

    obj-y := a.o b.o c/ d/ DIR := $(filter-out %/, $(obj-y)) //结果为:a.o b.o

    vi. $(patsubst pattern , replacement , text )

    寻找text’中符合格式pattern’的字,用replacement’替换它们。pattern’和`replacement’ 中可以使用通配符。 比如:

    subdir-y := c/ d/ subdir-y := $(patsubst %/, %, $(subdir-y)) // 结果为:c d

    6、通用 Makefile 的设计思想

    (1)、在 Makefile 文件中确定要编译的文件、目录,比如:

    obj-y += main.o obj-y += a/

    “Makefile”文件总是被“Makefile.build”包含的。

    (2)、 在 Makefile.build 中设置编译规则,有 3 条编译规则:

    i. 怎么编译子目录? 进入子目录编译:

    $(subdir-y): make -C $@ -f $(TOPDIR)/Makefile.build

    (3)、 怎么编译当前目录中的文件?

    %.o : %.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<

    (4)、当前目录下的.o 和子目录下的 built-in.o 要打包起来:

    built-in.o : $(cur_objs) $(subdir_objs) $(LD) -r -o $@ $^

    (5)、顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP:

    $(TARGET) : built-in.o $(CC) $(LDFLAGS) -o $(TARGET) built-in.o

    7、情景演绎

    Processed: 0.043, SQL: 8