什么是Makefile?
Makefile 可以简单的认为是一个工程文件的编译规则,描述了整个工程的编译和链接等规则。其中包含了那些文件需要编译,那些文件不需要编译,那些文件需要先编译,那些文件需要后编译,那些文件需要重建等等。编译整个工程需要涉及到的,在 Makefile 中都可以进行描述。换句话说,Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数。
以 Linux 下的C语言开发为例来具体说明一下,多文件编译生成一个文件,编译的命令如下所示:gcc -o outfile name1.c name2.c ... outfile
要生成的可执行程序的名字,nameN.c 是源文件的名字。这是我们在 Linux 下使用 gcc 编译器编译 C 文件的例子。如果我们遇到的源文件的数量不是很多的话,可以选择这样的编译方式。如果源文件非常的多的话,就会遇到下面的这些问题。
1) 编译的时候需要链接库的的问题。拿C语言来说,编译的时候 gcc 只会默认链接一些基本的C语言标准库,很多源文件依赖的标准库都需要我们手动链接。
下面列举了一些需要我们手动链接的标准库:
name1.c 用到了数学计算库 math 中的函数,我们得手动添加参数 -Im;
name4.c 用到了小型数据库 SQLite 中的函数,我们得手动添加参数 -lsqlite3;
name5.c 使用到了线程,我们需要去手动添加参数 -lpthread。
因为有很多的文件,还要去链接很多的第三方库。所以在编译的时候命令会很长,并且在编译的时候我们可能会涉及到文件链接的顺序问题,所以手动编译会很麻烦。
如果我们学会使用 Makefile 就不一样了,它会彻底简化编译的操作。把要链接的库文件放在 Makefile 中,制定相应的规则和对应的链接顺序。这样只需要执行 make 命令,工程就会自动编译。每次想要编译工程的时候就执行 make ,省略掉手动编译中的参数选项和命令,非常的方便。2) 编译大的工程会花费很长的时间。
如果我们去做项目开发,免不了要去修改工程项目的源文件,每次修改后都要去重新编译。一个大的工程项目可不止有几个的源文件,里面的源文件个数可能有成百上千个。例如一个内核,或者是一个软件的源码包。这些都是我们做开发经常会遇到的。要完成这样的文件的编译,我们消耗的时间可不是一点点。如果文件特别大的话我们可能要花上半天的时间。
对于这样的问题我们 Makefile 可以解决吗?当然是可以的,Makefile 支持多线程并发操作,会极大的缩短我们的编译时间,并且当我们修改了源文件之后,编译整个工程的时候,make 命令只会编译我们修改过的文件,没有修改的文件不用重新编译,也极大的解决了我们耗费时间的问题。
这其实是我们遇到的比较常见的问题,当然可能遇到的问题还会有很多,比如:工程文件中的源文件的类型很多,编译的话需要选择的编译器;文件可能会分布在不同的目录中,使用时需要调价路径。这些问题都可以通过 Makefile 解决。并且文件中的 Makefile 只需要完成一次,一般我们只要不增加或者是删除工程中的文件,Makefile 基本上不用去修改,编译时只用一个 make 命令。为我们提供了极大的便利,很大程度上提高编译的效率。
Makefile结构说明
Makefile里主要包含了五个东西:变量定义、显式规则、隐晦规则、文件指示和注释。
1、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
2、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 刚才写的疑似shell脚本的Makefile全部都是显示规则。
3、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样。
5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符。
Makefile的优点
- 管理代码的编译,决定该编译什么文件,编译顺序,以及是否需要重新编译;
- 节省编译时间。如果文件有更改,只需重新编译此文件即可,无需重新编译整个工程;
- 一劳永逸。Makefile通常只需编写一次,后期就不用过多更改。
Makefile的工作流程
我们推荐使用 Makefile(一般在工程中都这么写,大写的会比较的规范)。如果文件不存在,make 就会给我们报错,提示:
make:***
没有明确目标并且找不到 makefile。停止
Makefile的工流程
Makefile 的具体工作流程可以通过例子来看一下:创建一个包含有多个源文件和 Makefile 的目录文件,源文件之间相互关联。在 Makefile 中添加下面的代码:
main:main.o test1.o test2.o gcc main.o test1.o test2.o -o main main.o:main.c test.h gcc -c main.c -o main.o test1.o:test1.c test.h gcc -c test1.c -o test1.o test2.o:test2.c test.h gcc -c test2.c -o test2.o
在我们编译项目文件的时候,默认情况下,make 执行的是 Makefile 中的第一规则(Makefile 中出现的第一个依赖关系),此规则的第一目标称之为“最终目标”或者是“终极目标”。
在 shell 命令行执行的 make 命令,就可以得到可执行文件 main 和中间文件 main.o、test1.o 和 test2.o,main 就是我们要生成的最终文件。通过 Makefile 我们可以发现,目标 main"在 Makefile 中是第一个目标,因此它就是 make 的终极目标,当修改过任何 C 文件后,执行 make 将会重建终极目标 main。
它的具体工作顺序是:当在 shell 提示符下输入 make 命令以后。 make 读取当前目录下的 Makefile 文件,并将 Makefile 文件中的第一个目标作为其执行的“终极目标”,开始处理第一个规则(终极目标所在的规则)。在我们的例子中,第一个规则就是目标 “main” 所在的规则。规则描述了 “main” 的依赖关系,并定义了链接 “.o” 文件生成目标 “main” 的命令;make 在执行这个规则所定义的命令之前,首先处理目标 “main” 的所有的依赖文件(例子中的那些 “.o” 文件)的更新规则(以这些 “.o” 文件为目标的规则)。
对这些 “.o” 文件为目标的规则处理有下列三种情况:
目标 “.o” 文件不存在,使用其描述规则创建它;
目标 “.o” 文件存在,目标 “.o” 文件所依赖的 “.c” 源文件 “.h” 文件中的任何一个比目标 “.o” 文件“更新”(在上一次 make 之后被修改)。则根据规则重新编译生成它;
目标 “.o” 文件存在,目标 “.o” 文件比它的任何一个依赖文件(“.c” 源文件、“.h” 文件)“更新”(它的依赖文件在上一次 make 之后没有被修改),则什么也不做。
通过上面的更新规则我们可以了解到中间文件的作用,也就是编译时生成的 “.o” 文件。作用是检查某个源文件是不是进行过修改,最终目标文件是不是需要重建。我们执行 make 命令时,只有修改过的源文件或者是不存在的目标文件会进行重建,而那些没有改变的文件不用重新编译,这样在很大程度上节省时间,提高编程效率。小的工程项目可能体会不到,项目工程文件越大,效果才越明显。
当然 make 命令能否顺利的执行,还在于我们是否制定了正确的的依赖规则,当前目录下是不是存在需要的依赖文件,只要任意一点不满足,我们在执行 make 的时候就会出错。所以完成一个正确的 Makefile 不是一件简单的事情。
Makefile基本语法
target(目标文件) ...: prerequisites(依赖的文件) ... command(命令) ... ... 指令:屏蔽指令 #定义变量(变量大写) 变量名=值1 值2 ... #使用变量 $(变量名)
Makefile中CFLAGS,LDFLAGS,LIBS的说明
CFLAGS:
C编译器选项,而CPPFLAG/CXXFLAGS表示C++编译器的选项.
目的:输出文件名称,可调试,编译告警,指定头文件目录.LDFLAGS:
链接器从哪里寻找库文件,围绕着编译时使用的库文件,添加库文件的路径
LIBS:
告诉链接器要链接哪些库文件,如LIBS = -lpthread,-lm(链接线程库和数学库)
有关具体参数可查看gcc编译选项
Makefile中的缩进
makefile中有两种不同的语言,shell语法(recipe)和makefile语法(non-recipe),为了区分这两种语言所以使用tab。以tab开头的是shell(recipe)。
- 在写makefile语法,非recipe的时候,缩进应该使用空格。
- 在写shell语法,recipe时,缩进使用TAB。因为实际上我们写的是希望shell执行的语句,所以使用的是shell syntax。而make识别recipe的方式就是。
Makefile 静态模式 %.o:%.c
静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。
语法:
<targets ...>: <target-pattern>: <prereq-patterns ...> <commands> ...
如果我们的定义成“%.o”,意思是我们的集合中都是以“.o”结尾的,而如果我们的定义成“%.c”,
意思是对所形成的目标集进行二次定义,其计算方法是,取模式中的“%”(也就是去掉了[.o]这个结尾),
并为其加上[.c]这个结尾,形成的新集合。所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符。
Makefile 赋值语句 =,:=,?=,+= 符号的含义
=
最简单的赋值.用=赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以你看变量引用的值时不能只往前面看,还要往后面看。:=
最简单的赋值.用:=来赋值的,则是就地直接解析 ,只用往前看即可。?=
?=如果变量前面并没有赋值过则执行这条赋值,如果前面已经赋值过了则本行被忽略 。(实验可以看出:所谓的没有赋值过其实就是这个变量没有被定义过)+=
+=用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面 ,有点类似于strcat。(在shell makefile等文件中,可以认为所有变量都是字符串,+=就相当于给字符串stcat接续内容)(注意一个细节,+=续接的内容和原来的内容之间会自动加一个空格隔开)
Makefile 符号@ - $ $$含义
@
(用于静默执行)
#示例 DIR_OBJ=./obj CMD_MKOBJDIR=if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi mkobjdir: @${CMD_MKOBJDIR} #命令行执行如下: make mkobjdir #此时不会显示在命令行不会显示出if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi, #但如果规则行的TAB后没有以@开头,则会显示
-
这个符串通常用在“规则”行中,表示不显示命令本身,而只显示它的结果-rm dir; -mkdir aaadir;
$
美元符号$,主要扩展打开makefile中定义的变量$$
$$ 符号主要扩展打开makefile中定义的shell变量
Makefile ifeq、ifneq、ifdef和ifndef(条件判断)
关键字 | 功能 |
ifeq | 判断参数是否相等,相等为 true,不相等为 false。 |
ifneq | 判断参数是否不相等,不相等为 true,相等为 false。 |
ifdef | 判断是否有值,有值为 true,没有值为 false。 |
ifndef | 判断是否有值,没有值为 true,有值为 false。 |
#ifeq 表示如果比较相等,语法如下: ifeq(<参数 1>, <参数 2>) #ifneq 表示如果不相等,语法如下: ifneq(<参数 1>, <参数 2>) #ifdef 表示如果定义了变量,语法如下: ifdef <变量名> #ifndef 表示如果没有定义变量,语法如下: ifndef <变量名>
Makefile 通配符
$* #不包含扩展名的目标文件名称。 $+ #所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。 $< #第一个依赖文件的名称。 $? #所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。 $@ #目标的完整名称。 $^ #所有的依赖文件,以空格分开,不包含重复的依赖文件。 $% #如果目标是归档成员,则该变量表示目标的归档成员名称。
Makefile 内嵌变量 $(CURDIR) $0 $1 $2 $#
$(CURDIR) # CURDIR是make的内嵌变量, 为当前目录 SRCTREE := $(CURDIR) *$(CURDIR)为当前目录,相当于SRCTREE=./ MKCONFIG := $(SRCTREE)/mkconfig *相当于MKCONFIG=./mkconfig $0 # Shell本身的文件名 $1 #添加到Shell的第一个参数 $2 #添加到Shell的第二个参数 $# #添加到Shell的总参数个数
Makefile中的常见自动变量$@, $^, $< , $?, $%, $+, $*
Makefile用一些特殊的符号来替代符合某种条件的文件集,这就形成了自动变量。
自动变量的含义:预定义的特殊意义的符号。就类似于C语言编译器中预制的那些宏__FILE__一样。
$@ #表示目标文件,表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。 $^ #表示所有的依赖文件 #所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。 $< #表示第一个依赖文件,依赖目标中的第一个目标名字。 #如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。 $? #表示比目标还要新的依赖文件列表/集合,以空格分隔。 $% #仅当目标是函数库文件中,表示规则中的目标成员名。 #例如,如果一个目标是“foo.a(bar.o)”,那么,“$%”就是“bar.o”,“$@”就是“foo.a”。 #如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。 $+ #这个变量很像“$^”,也是所有依赖目标的集合。只是它不去除重复的依赖目标。 $* #这个变量表示目标模式中“%”及其之前的部分。 #如果目标是“dir/a.foo.b”,并且目标的模式是“a.%.b”,那么,“$*”的值就是“dir/a.foo”。 #这个变量对于构造有关联的文件名是比较有较 #。如果目标中没有模式的定义,那么“$*”也就不能被推导出,但是, #如果目标文件的后缀是make所识别的,那么“$*”就是除了后缀的那一部分。 #例如:如果目标是“foo.c”,因为“.c”是make所能识别的后缀名,所以,“$*”的值就是“foo”。 #这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用“$*”,除非是在隐含规则或是静态模式中。 #如果目标中的后缀是make所不能识别的,那么“$*”就是空值。
Makefile常用标识(CROSS_COMPILE和ARCH)
- CROSS_COMPILE
即交叉编译器的前缀(prefix),也就是选择将代码编译成目标cpu的指令的工具,如指定make CROSS_COMPILE=arm-none-linux-gnueabi-就是使用arm-none-linux-gnueabi-gcc, arm-none-linux-gnueabi-ld等工具将代码编译成arm的可执行指令。
如果不指定CROSS_COMPILE参数,make时将认为prefix为空,即使用gcc来编译。
这里cross_compile的设置,是假定所用的交叉工具链的gcc程序名称为arm-linux-gcc。
如果实际使用的gcc名称是some-thing-else-gcc,则这里填some-thing-else-即可。总之,要省去名称中最后的gcc那3个字母。- ARCH
即architecture,就是选择编译哪一种cpu architecture,也就是编译arch/目录下的哪一个子目录。
如指定make ARCH=arm就是编译arch/arm下的代码。如果不指定,make将使用本机(用什么机器编译就是什么)的cpu作为缺省ARCH.
注意:arch/arm下不但有arm体系架构特有的代码,还有arm特有的kconfig,也就是配置选项,所以在make menuconfig,make xxxx_defconfig的时候也必须指定ARCH=arm。
Makefile唯一的循环控制结构foreach 命令
foreach
是 GNU make 的一个功能强大的函数,它允许你在 Makefile 中进行列表的迭代操作。
foreach
函数的基本语法如下:
$(foreach var, list, text)
这里的参数有三个:
var
:这是循环变量的名称,在text
中引用。list
:这是一个由空格分隔的值列表,foreach
函数会遍历这个列表。text
:这是在每次迭代中执行的文本或表达式,其中可以使用$(var)
来引用当前的列表元素。例如,假设我们有一个源文件列表
srcs
,我们想要生成相应的目标文件列表objs
,可以使用foreach
函数来完成:
srcs := a.c b.c c.c objs := $(foreach src, $(srcs), $(src:.c=.o))
这段代码将
objs
设置为a.o b.o c.o
。总的来说,
foreach
函数为在 Makefile 中处理列表提供了强大的功能,使得我们可以更方便地处理复杂的构建任务。
foreach
是一个非常强大的函数,除了基本的列表遍历之外,它还可以配合其他函数来实现更复杂的逻辑。以下是一些foreach
的高级用法:
- 嵌套使用
foreach
:foreach
可以嵌套使用来处理更复杂的列表结构。例如,假设我们有一个二维的源文件列表,我们可以使用嵌套的foreach
来生成所有的目标文件列表:
src_lists := list1:a.c b.c list2:c.c d.c objs := $(foreach src_list, $(src_lists), \ $(foreach src, $(wordlist 2, $(words $(src_list)), $(src_list)), \ $(src:.c=.o)))
- 这段代码将
objs
设置为a.o b.o c.o d.o
。- 结合
call
函数:foreach
可以结合call
函数来调用用户自定义的函数。例如,假设我们定义了一个函数compile
来编译源文件,我们可以使用foreach
和call
来编译所有的源文件:
define compile $(1:.c=.o): $(1) $(CC) -c $(CFLAGS) $< -o $@ endef srcs := a.c b.c $(foreach src, $(srcs), $(eval $(call compile, $(src))))
- 这段代码将为
a.c
和b.c
生成对应的编译规则。- 生成规则:
foreach
可以用于生成 Makefile 规则。例如,假设我们有多个目标需要生成,我们可以使用foreach
来生成这些目标的规则:
targets := a b c define rule $(1): @echo Building $(1) endef $(foreach target, $(targets), $(eval $(call rule, $(target))))
- 这段代码将为
a
、b
和c
生成对应的构建规则。这些只是
foreach
函数的一部分高级用法,实际上foreach
的可能用法有很多,只要结合其他函数,你可以实现各种复杂的逻辑。
Makefile中$(eval …) 和include的用法和区别
$(eval ...)
和include
都可以在 Makefile 中用于包含和执行其他 Makefile 文件的内容,但它们的工作方式和用途有些区别。1.
include
:在处理 Makefile 时,Make 会在当前的上下文中直接包含include
指定的文件。被包含的文件中的所有规则、变量定义等都将被加入到当前 Makefile 中。如果被包含的文件不存在,Make 会尝试查找隐含规则来创建它,如果仍然找不到,那么 Make 将会报错。2.
$(eval ...)
:eval
函数会将其参数解析为 Makefile 语法,并执行。与include
不同,eval
可以处理动态生成的 Makefile 代码。比如,可以先定义一个变量,然后使用eval
来解析和执行这个变量的值。总结一下,
include
更常用于包含静态的 Makefile 文件,而$(eval ...)
更适合处理动态生成的 Makefile 代码。如果你需要在 Makefile 中处理复杂的逻辑,可能需要用到$(eval ...)
。
比较项 | include |
$(eval ...) |
目的 | 用于包含静态的 Makefile 文件,这些文件中的所有规则、变量定义等都将被加入到当前 Makefile 中。 | 用于解析和执行 Makefile 语法。更适合处理动态生成的 Makefile 代码。 |
处理方式 | 在处理 Makefile 时,直接在当前的上下文中包含 include 指定的文件。 |
会将其参数解析为 Makefile 语法,并执行。 |
错误处理 | 如果被包含的文件不存在,Make 会尝试查找隐含规则来创建它。如果仍然找不到,那么 Make 将会报错。 | eval 不会处理文件的存在性。如果 eval 的参数不能被正确解析为 Makefile 语法,那么会导致错误。 |
使用场景 | 当你有一些公共的规则或变量定义,需要在多个 Makefile 中共享时,可以使用 include 。 |
当你需要在 Makefile 中处理复杂的逻辑,可能需要用到 $(eval ...) 。比如,先定义一个变量,然后使用 eval 来解析和执行这个变量的值。 |
灵活性 | 对于静态的 Makefile 文件,include 是一个简单而直接的解决方案。 |
$(eval ...) 提供了更高的灵活性,可以处理动态生成的 Makefile 代码,但同时也更复杂。 |
请注意,这个对比表格并不是绝对的,使用 include
还是 $(eval ...)
取决于具体的应用场景。
Makefile中.PHONY和.SUFFIXES的含义
- 内容过长,放链接:Makefile中.SUFFIXES的含义
- 内容过长,放链接:Makefile中.PHONY的含义
Makefile中文件读写 file命令
file
是 GNU make 4.2 版本引入的一个新函数,用于在 Makefile 中进行文件读写操作。它的语法如下:
$(file op filename[,text])
在这个函数中,
op
是操作符,filename
是要操作的文件的名称,text
是可选的文本参数。这个函数的返回值是空字符串。操作符
op
可以是以下的一个:
<
:读取文件。这个操作符会读取指定文件的内容,并返回。例如,$(file <filename)
会读取filename
文件的内容。这个文件的内容会作为函数的返回值。>
:写入文件。这个操作符会将text
参数写入到filename
文件中,覆盖文件中原有的内容。例如,$(file >filename,text)
会将text
写入到filename
文件中。>>
:追加到文件。这个操作符会将text
参数追加到filename
文件的末尾。例如,$(file >>filename,text)
会将text
追加到filename
文件的末尾。这个函数可以用于在 Makefile 中直接进行文件操作,而无需调用 shell 命令。但请注意,这个函数只在 GNU make 4.2 及更高版本中可用。
这是一个简单的例子:
all: $(file >output.txt,This is some text.)
这个 Makefile 会创建一个名为
output.txt
的文件,并写入文本 “This is some text.”。在 GNU make 中,
file
函数的高级用法主要涉及到它与其他 Makefile 特性的结合使用,以实现更复杂的文件操作。下面是一些可能的高级用法:
- 动态生成 Makefile 规则
有时,你可能希望在运行 make 命令时动态地生成一些 Makefile 规则。这可以通过将规则写入一个临时文件,然后使用include
指令将其包含到当前 Makefile 中来实现。
generate-rules: $(file >rules.mk,$(foreach obj,$(OBJECTS),$(obj): $(obj:.o=.c)\n\t$(CC) -c $< -o $@\n\n)) include rules.mk
- 在这个例子中,
file
函数用于生成一个名为rules.mk
的文件,该文件中包含了一组编译规则。然后,include
指令用于将这些规则包含到当前的 Makefile 中。- 在文件中存储中间结果
在某些情况下,你可能希望在 Makefile 中存储一些中间结果,以便在后续的规则中使用。这可以通过file
函数来实现:
intermediate: @echo "Generating intermediate results..." @$(file >$@,$(shell ./generate-results)) final: intermediate @echo "Generating final results based on intermediate results..." @$(file >$@,$(shell ./generate-final $(shell cat intermediate)))
- 在这个例子中,
file
函数用于将一个中间结果存储到一个文件中。然后,这个文件在后续的规则中被读取,并用于生成最终的结果。注意,以上示例为简化展示并未包含完整的错误处理和清理代码,在实际使用中需要进行相应的处理。
Makefile中patsubst(扩展通配符)的含义
内容过长,放链接:Makefile中patsubst(扩展通配符)的含义
最基本的Makefile示例
SRCS = $(wildcard *.c) OBJS = $(patsubst %c, %o, $(Message_SRCS)) # wildcard 扩展通配符,指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开 # patsubst 替换通配符 # $^ 代表所有依赖文件 # $@ 代表所有目标文件 # $< 代表第一个依赖文件 # % 代表通配符 CFLAGS/CXXFLAGS: #编译器会用到的一些优化参数 , 并指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include。 LDFLAGS:#指定库文件的位置。 LIBS: #告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv $(CC) $(CFLAGS) $(LDFLAGS) main.c gfifo.c queue.c usbmonitor.c socket_rcv_360_server.c ./lib/srs_librtmp.a ./lib/libcrypto.a ./lib/libssl.a ./lib/libtinyalsa.a -o media_record -static -ldl -lstdc++ -lm -lpthread #使用定的编译器、编译选项参数、链接选项参数,编译.c文件,并使用静态方式链接制定的库文件,以及编译器目录下的libdl.a、libstdc++.a、libm.a、libpthread.a库文件生成media_record 可执行目标文件。
Makefile模版
提供一个模版,里面内容按需修改.
############################################################# # Generic Makefile for C/C++ Program # # License: GPL (General Public License) # Description: # ------------ # This is an easily customizable makefile template. The purpose is to # provide an instant building environment for C/C++ programs. # # It searches all the C/C++ source files in the specified directories, # makes dependencies, compiles and links to form an executable. # # Besides its default ability to build C/C++ programs which use only # standard C/C++ libraries, you can customize the Makefile to build # those using other libraries. Once done, without any changes you can # then build programs using the same or less libraries, even if source # files are renamed, added or removed. Therefore, it is particularly # convenient to use it to build codes for experimental or study use. # # GNU make is expected to use the Makefile. Other versions of makes # may or may not work. # # Usage: # ------ # 1. Copy the Makefile to your program directory. # 2. Customize in the "Customizable Section" only if necessary: # * to use non-standard C/C++ libraries, set pre-processor or compiler # options to <MY_CFLAGS> and linker ones to <MY_LIBS> # (See Makefile.gtk+-2.0 for an example) # * to search sources in more directories, set to <SRCDIRS> # * to specify your favorite program name, set to <PROGRAM> # 3. Type make to start building your program. # # Make Target: # ------------ # The Makefile provides the following targets to make: # $ make compile and link # $ make NODEP=yes compile and link without generating dependencies # $ make objs compile only (no linking) # $ make tags create tags for Emacs editor # $ make ctags create ctags for VI editor # $ make clean clean objects and the executable file # $ make cleanall clean objects, the executable, TAGS and dependencies # $ make help get the usage of the makefile # #=========================================================================== ## Customizable Section: adapt those variables to suit your program. ##========================================================================== # The pre-processor and compiler options. MY_CFLAGS = -I/usr/include # The linker options. MY_LIBS = -lpthread -Wl,-rpath-link= -Wl,-rpath=/usr/lib # The pre-processor options used by the cpp (man cpp for more). CPPFLAGS = -Wall # The options used in linking as well as in any direct use of ld. LDFLAGS = # The directories in which source files reside. # If not specified, only the current directory will be serached. SRCDIRS = . # The executable file name. # If not specified, current directory name or `a.out' will be used. PROGRAM = name_app ## Implicit Section: change the following only when necessary. ##========================================================================== # The source file types (headers excluded). # .c indicates C source files, and others C++ ones. SRCEXTS = .c .C .cc .cpp .CPP .c++ .cxx .cp # The header file types. HDREXTS = .h .H .hh .hpp .HPP .h++ .hxx .hp # The pre-processor and compiler options. # Users can override those variables from the command line. # The GCC default, if no C language dialect options are given, is -std=gnu17. # The GCC default, if no C++ language dialect options are given, is -std=gnu++17. CFLAGS = -O3 -std=gnu11 CXXFLAGS= -O3 -std=gnu++14 # The C program compiler. CC = /usr/bin/gcc # The C++ program compiler. CXX = /usr/bin/g++ # Un-comment the following line to compile C programs as C++ ones. #CC = $(CXX) # The command used to delete file. RM = rm -f ETAGS = etags ETAGSFLAGS = CTAGS = ctags CTAGSFLAGS = ## Stable Section: usually no need to be changed. But you can add more. ##========================================================================== SHELL = /bin/sh EMPTY = SPACE = $(EMPTY) $(EMPTY) ifeq ($(PROGRAM),) CUR_PATH_NAMES = $(subst /,$(SPACE),$(subst $(SPACE),_,$(CURDIR))) PROGRAM = $(word $(words $(CUR_PATH_NAMES)),$(CUR_PATH_NAMES)) ifeq ($(PROGRAM),) PROGRAM = a.out endif endif ifeq ($(SRCDIRS),) SRCDIRS = . endif SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS)))) HEADERS = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(HDREXTS)))) SRC_CXX = $(filter-out %.c,$(SOURCES)) OBJS = $(addsuffix .o, $(basename $(SOURCES))) DEPS = $(OBJS:.o=.d) ## Define some useful variables. DEP_OPT = $(shell if `$(CC) --version | grep "GCC" >/dev/null`; then \ echo "-MM -MP"; else echo "-M"; fi ) DEPEND = $(CC) $(DEP_OPT) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS) DEPEND.d = $(subst -g ,,$(DEPEND)) COMPILE.c = $(CC) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS) -c COMPILE.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c LINK.c = $(CC) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) LINK.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) .PHONY: all objs tags ctags clean cleanall help show # Delete the default suffixes .SUFFIXES: all: $(PROGRAM) # Rules for creating dependency files (.d). #------------------------------------------ %.d:%.c @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ %.d:%.C @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ %.d:%.cc @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ %.d:%.cpp @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ %.d:%.CPP @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ %.d:%.c++ @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ %.d:%.cp @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ %.d:%.cxx @echo -n $(dir $<) > $@ @$(DEPEND.d) $< >> $@ # Rules for generating object files (.o). #---------------------------------------- objs:$(OBJS) %.o:%.c $(COMPILE.c) $< -o $@ %.o:%.C $(COMPILE.cxx) $< -o $@ %.o:%.cc $(COMPILE.cxx) $< -o $@ %.o:%.cpp $(COMPILE.cxx) $< -o $@ %.o:%.CPP $(COMPILE.cxx) $< -o $@ %.o:%.c++ $(COMPILE.cxx) $< -o $@ %.o:%.cp $(COMPILE.cxx) $< -o $@ %.o:%.cxx $(COMPILE.cxx) $< -o $@ # Rules for generating the tags. #------------------------------------- tags: $(HEADERS) $(SOURCES) $(ETAGS) $(ETAGSFLAGS) $(HEADERS) $(SOURCES) ctags: $(HEADERS) $(SOURCES) $(CTAGS) $(CTAGSFLAGS) $(HEADERS) $(SOURCES) # Rules for generating the executable. #------------------------------------- $(PROGRAM):$(OBJS) ifeq ($(SRC_CXX),) # C program $(LINK.c) $(OBJS) $(MY_LIBS) -o $@ @echo Type ./$@ to execute the program. else # C++ program $(LINK.cxx) $(OBJS) $(MY_LIBS) -o $@ @echo Type ./$@ to execute the program. endif ifndef NODEP ifneq ($(DEPS),) sinclude $(DEPS) endif endif # Commands to clean and help etc. #------------------------------------- .PHONY: clean clean: $(RM) $(OBJS) $(PROGRAM) .PHONY: cleanall cleanall: $(RM) $(DEPS) $(OBJS) TAGS $(PROGRAM) # Show help. .PHONY: help help: @echo 'Usage: make [TARGET]' @echo 'TARGETS:' @echo ' all (=make) compile and link.' @echo ' NODEP=yes make without generating dependencies.' @echo ' objs compile only (no linking).' @echo ' tags create tags for Emacs editor.' @echo ' ctags create ctags for VI editor.' @echo ' clean clean objects and the executable file.' @echo ' distclean clean objects, the executable and dependencies.' @echo ' show show variables (for debug use only).' @echo ' help print this message.' @echo @echo 'Report bugs to <whyglinux AT gmail DOT com>.' # Show variables (for debug use only.) .PHONY: show show: @echo 'PROGRAM :' $(PROGRAM) @echo 'SRCDIRS :' $(SRCDIRS) @echo 'HEADERS :' $(HEADERS) @echo 'SOURCES :' $(SOURCES) @echo 'SRC_CXX :' $(SRC_CXX) @echo 'OBJS :' $(OBJS) @echo 'DEPS :' $(DEPS) @echo 'DEPEND :' $(DEPEND) @echo 'COMPILE.c :' $(COMPILE.c) @echo 'COMPILE.cxx :' $(COMPILE.cxx) @echo 'link.c :' $(LINK.c) @echo 'link.cxx :' $(LINK.cxx) ## End of the Makefile ## Suggestions are welcome ## All rights reserved ## ##############################################################