最近编译项目动不动就make或者makefile一下,这里简单总结一下;
基础概念:
make,makefile简单来说就是系统脚本来实现批量和自动化编译的一种形式;
对于gcc下常见的编译,采用单文件编译;
例如:
有三个文件:
hellomake.c源文件:
// hellomake.c
#include <hellomake.h>
int main() {
// call a function in another file
myPrintHelloMake();
return(0);
}
hellofunc.c源文件:
// hellofunc.c
#include <stdio.h>
#include <hellomake.h>
void myPrintHelloMake(void) {
printf("Hello makefiles!\n");
return;
}
hellomake.h源文件:
/*
example include file
*/
void myPrintHelloMake(void);
因此,可以通过命令行+gcc进行处理;
gcc -o hellomake hellomake.c hellofunc.c -I.
这里注意下基本的语法形式;
- gcc代表使用c编译;
- -o代表输出到哪里;
- hellomake这里代表生成的最终执行文件;
- hellomake.c,hellofunc.c为编译的源文件;
- -I代表在当前目录下寻找头文件;
这里还需要注意下,gcc的编译顺序;
对于之前学过的系统结构和编译原理来讲,编译的过程应该分为四个阶段;
- 预处理:将头文件以及宏定义拓展到代码中,这里由hello.c->hello.i文件;
- 编译:将.i的与处理文件编译为汇编程序,这里由hello.i->hello.s;
- 汇编:将.s汇编文件转化为目标文件,目标文件为二进制格式,这里由hello-.s->hello.o;
- 链接:将多个目标文件链接为一个最终的可执行文件,这里由hello.o->hello;
所以按照流程上来讲,gcc应该顺序执行四步,才能得到最终的执行文件;
但是gcc可以偷懒,直接利用-o加上源文件,一步得到最终的可执行文件;
但是如果是多文件,或者进行修改,亦或是编译命令丢失,都有可能要重新编译;
因此为了简便make/makefile应运而生;
说白了就是通过一个脚简化编译流程;
具体形式:
makefile的具体形式如下所示:
目标文件:依赖文件
命令1
命令2
...
命令n
目标文件是指,我们期望获得的文件;
依赖文件则是指,我们期望获得文件需要从什么地方来;
而命令则是指我们如何将依赖文件转化为目标文件;
例如,对于上述gcc指令,我们就可以写为:
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c -I.
大意为,我们需要hellomake执行文件,来源为hellomake.c以及hellofunc.c;
生成的指令为:
gcc -o hellomake hellomake.c hellofunc.c -I.
但是上述并不会之编译更改后的文件;
对于上述可以有以下拓展:
CC=gcc
CFLAGS=-I.
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
这里前两行可以视为cpp内的宏定义;
注意一下目标和依赖形式;
这里不再采用.c的源文件格式,而是直接依赖于.o目标文件;
这里意为,如果要执行文件hellomake,则必须要先编译生成.o目标文件;
因此,执行语句为连接语句,将.o模块链接即可;
但是这里还是要加上头文件,不然会编译报错,相当于指定编译目标文件的时候,哪些源文件依赖哪些头文件;
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
上述DEPS宏定义标记了源文件;
其中%.o以及%.c类似于通配符,代表某个或者某些以后缀名为结束的文件;
也声明了.o文件应该由哪个.c文件而来,头文件是谁;
参数 -c 指示编译器产生 .o 目标文件;
参数 $@ 和 $^ 分别指代规则第一行中的冒号的左右两边的内容;
所以可以拼成一条完整的编译目标模块的语句;
因此,利用宏定义,也可以改写成如下,更方便:
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
OBJ = hellomake.o hellofunc.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)