文件版本说明
版本 | 颁布日期 | 修订章节 | 作者 |
---|---|---|---|
0.1 | 2017.02.26 | 撰写草稿 | 钟鑫 |
0.2 | 2017.02.27 | 添加Makefile简单工程 | 钟鑫 |
0.3 | 2017.03.02 | 添加Makefile标签描述 | 钟鑫 |
0.4 | 2017.03.05 | 添加Makefile头文件搜寻 | 钟鑫 |
0.5 | 2017.03.09 | 添加Makefile源码搜寻 | 钟鑫 |
0.6 | 2017.03.12 | 添加Makefile函数调用 | 钟鑫 |
0.7 | 2017.03.20 | 添加Makefile字符串处理函数 | 钟鑫 |
0.8 | 2017.04.05 | 添加Makefile嵌套编译 | 钟鑫 |
0.9 | 2017.04.10 | 添加Makefile编译库文件 | 钟鑫 |
1.0 | 2017.04.12 | 整理文档结构 | 钟鑫 |
1.1 | 2017.04.16 | 编译静态库文件 | 钟鑫 |
1.2 | 2016.04.19 | 编译动态库文件 | 钟鑫 |
1.3 | 2016.04.23 | 整理库文件的引用 | 钟鑫 |
1.3 | 2016.04.29 | 添加Makefile传参 | 钟鑫 |
1.4 | 2016.05.03 | 整理Makefile自动化变量 | 钟鑫 |
1.5 | 2016.05.07 | 添加Makefile传参 | 钟鑫 |
1.6 | 2016.05.09 | 添加Makefile嵌套功能 | 钟鑫 |
1.7 | 2016.05.10 | 整理Makefile标准格式 | 钟鑫 |
1.8 | 2016.05.14 | 整理文档 | 钟鑫 |
工程构建
在软件开发中,按系统不同的功能模块来分,源码成百上千,文件之间的管理和编译需要由特定的规则来创建。假如其中一个文件改变,从而需要编译整个源码,浪费了时间和精力。虽然通过软件IDE如Keil能够仅仅编译改动的文件,但在软件工程构建中,没有看得到软件的整个系统架构是如何关联的。在Linux中,通过Makefile自己定义的规则管理软件工程,从而掌握整个软件架构的设计。
工程构建的目标就是将源码编译能够运行,有嵌入式的Linux,编译后烧录到单板上运行,也有桌面级的软件,通过编译安装后即可在x86上的Linux系统运行,在一些发型版本的Linux中,通过系统自带的命令可以一键安装软件,也可以通过下载源码,通过make install命令编译安装软件。
Makefile实现目标
假如在一个文件夹中包含了整个工程,里面有一个Makefile文件。只要输入一个make命令即可完成
1、 如果这个工程没有编译过,make之后系统会自动编译整个工程;
2、 如果对工程的某几个文件进行修改,make之后系统会只编译改动的文件以及关联的文件,其他文件不会编译;
3、 如果对工程的某几个头文件进行修改,make之后系统会自动编译这几个头文件关联的.c文件;
4、 如果工程添加了几个模块,在简单修改Makefile文件后,make之后系统会自动将新加的模块进行编译;
5、 清除系统编译出来的文件,make clean之后系统会自动清理编译出来的目标文件,仅仅保留源码。
Makefile文件里面总揽了整个工程的编译规则。
make命令下支持Makefile与makefile两个文件名,但推荐使用Makefile来命令,大写显示与其他文件区别。
最简单的Makefile工程文件
1、在文件夹test_Makfile中有一个源文件:main.c
#include <stdio.h>
int main(int argc,char *argv[])
{
printf("test Makefile\n");
}
2、建立一个Makefile文件
命令:vim Makefile
输入以下内容:
all:
gcc main.c -o main.o
clean:
rm *.o
文件结构目录如下:
ghost@ghost-machine:~/workspace/testMakefile$ ls
Makefile main.c
3、运行Makefile文件编译源码并运行目标文件
命令:make以及./ main.o
ghost@ghost-machine:~/workspace/testMakefile$ make
gcc main.c -o main.o
ghost@ghost-machine:~/workspace/testMakefile$ ls
Makefile main.c main.o
ghost@ghost-machine:~/workspace/testMakefile$ ./main.o
test Makefile
4、清理编译出来的目标文件,保留源码
ghost@ghost-machine:~/workspace/testMakefile$ make clean
rm *.o
ghost@ghost-machine:~/workspace/testMakefile$ ls
Makefile main.c
以上的步骤即包含了Makefile的主要功能:编译源码;以及最常用到的Makefile命令:make、make clean
Makefile标签
all:
clean:
以上两个为Makefile的标签,在Makefile文件中会标注出特殊的颜色,Makefile关键字一定要顶格写!而且关键字要独占一行,结尾以英文的“:”结束。下一行紧跟着的为Makefile的命令。
字面解释:
all :下方的命令为make所执行的主体,为编译代码的功能;
clean :下方命令为清除目标文件的主体,功能是清除编译过程
中产生的目标文件以及机器二进制麻或者是镜像文件。
以上描述称之为为功能命令,如果将下方执行的命令调换过来,如下所示命令仍能执行,说明功能是认为定的编码规范,因此关键字只是个标签,具体功能由用户去定义。
修改功能的Makefile文件
all:
rm *.o
clean:
gcc main.c -o main.o
执行
ghost@ghost-machine:~/workspace/testMakefile$ make clean
gcc main.c -o main.o
ghost@ghost-machine:~/workspace/testMakefile$ ./test.o
test Makefile
ghost@ghost-machine:~/workspace/testMakefile$ make
rm *.o
Makefile执行语句
在Makefile中执行的语句,必须要以[Tab]键开始。
gcc main.c -o main.o
rm *.o
以上即为Makefile所执行的命令,由用户设定,简单的Makefile命令与shell脚本的命令是一样的。
注释、隐藏显示与输出文字描述
Makefile的注释一般前面带“#”来注释,隐藏显示则在命令前面带“@”
将make clean执行的信息隐藏,在执行make clean的时候这条被隐藏的命令就不会显示出来。
all:
gcc main.c -o main.o
clean:
@rm *.o
结果
ghost@ghost-machine:~/workspace/testMakefile$ make
gcc main.c -o main.o
ghost@ghost-machine:~/workspace/testMakefile$ make clean
ghost@ghost-machine:~/workspace/testMakefile$
多个文件编译成一个目标文件
通常的代码为多个文件(若干个功能模块函数和一个main),需要将这些源码编译成一个目标文件,可以采用以下方法
all:
gcc main.c module_func.c -o main.o
clean:
rm *.o
Makefile标签
在执行make时,执行make 和 make clean会分别执行不同的命令,那将这两个用其他命令替代效果如下。
project1:
gcc main.c module_func.c -o main.o
project2:
rm *.o
执行结果如下
ghost@ghost-machine:~/workspace/testMakefile$ make
gcc main.c module_func.c -o main.o
ghost@ghost-machine:~/workspace/testMakefile$ ./main.o
test Makefile
file=module_func.c,func=test_func1 is called.
ghost@ghost-machine:~/workspace/testMakefile$ make project2
rm *.o
ghost@ghost-machine:~/workspace/testMakefile$ make project1
gcc main.c module_func.c -o main.o
ghost@ghost-machine:~/workspace/testMakefile$
说明all和clean为人们约定俗成的标签,和本身功能无关,这样可以利用标签进行条件编译,通过执行make命令时传入不同的参数,来决定执行什么编译动作,编译那些文件。
标签的依赖
标签可以依赖标签,像条件编译一样,在目标标签中嵌入其他标签,达到条件联合编译的目的
书写格式,在标签“:”后面加上依赖标签,多标签以空格隔开
Makefile文件
all:project1 project2
@echo "this is all project"
project1:
gcc main.c module_func.c -o main.o
project2:project3
gcc test.c -o test.o
project3:
@echo "make project3"
clean:
rm *.o
执行结果
host@ghost-machine:~/workspace/testMakefile$ make
gcc main.c module_func.c -o main.o
make project3
gcc test.c -o test.o
this is all project
ghost@ghost-machine:~/workspace/testMakefile$
Makefile的编译顺序:先执行标签所依赖的标签文件,再执行该标签自身的命令。
Makefile的标签也可以称做Makefile中的伪目标,和目标变量用法一样,那这样就好引起名称冲突的问题,如果源码需要生成一个clean的目标文件,但这个又和标签冲突,因为这两个的写法是一样的。为了区分make标签中的clean功能和伪目标变量的clean文件,Makefile用前置.PHONY来限定clean的功能,这样目标文件就不会与Makefile标签冲突。
all:project1 project2
@echo "this is all project"
project1:
gcc main.c module_func.c -o main.o
project2:
gcc test.c -o test.o
.PHONY:chean
clean:
rm *.o
特殊标签
1、.c.o:
2、.cpp.o:
3、%o:%c
4、%o:%cpp
该类特殊标签就是将该Makefile文件下的所有源码文件(.c、.cpp)编译成目标文件(.o),使用该特殊标签时需要上一层的依赖,特殊标签在自动化变量$<有详细说明。
Makefile变量
变量的基本书写
基本的变量可以自定义命名,然后通过符号$(varname)来使用这个变量
例如:
source = main.c module_func.c
all:
gcc $(source) -o main.o
clean:
rm *.o
其中$(source)代表了test.c这个变量
变量里面的内容除了可以直接加在变量的后面外,还可以通过符号“+=”来添加新的内容
source = main.c
source += module_func.c
all:
gcc $(source) -o main.o
clean:
rm *.o
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
gcc main.c module_func.c -o main.o
ghost@ghost-machine:~/workspace/testMakefile$ ./main.o
test Makefile
file=module_func.c,func=test_func1 is called.
ghost@ghost-machine:~/workspace/testMakefile$ make clean
rm *.o
ghost@ghost-machine:~/workspace/testMakefile$
另外一种比较少用,因为符号“+=”更加简洁,执行的结果是一样的
source = main.c
source := $(source) module_func.c
all:
gcc $(source) -o main.o
clean:
rm *.o
自动化变量
自动化变量尽量少用,因为有可能不兼容其他版本的MakEFile。
目标文件名集合:$@
目标文件名,将编译出来的目标文件(.o文件)按照目标的名称命名,如果是多个目标,那么该符号“$@”则为多个目标中的集合,以下的目标文件名为project1
source = main.c
source += module_func.c
all:project1
@echo "this is all project"
project1:
gcc $(source) -o $@
clean:
rm *.o
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
gcc main.c module_func.c -o project1
this is all project
ghost@ghost-machine:~/workspace/testMakefile$