一。 make工程管理器简介
工程管理器是指管理较多的文件。如果有一个上百个文件的代码构成的项目,
如果其中只有一个或少数几个文件进行了修改,按照之前所学的Gcc编译工具,就不得不把这所有的文件重新编译一遍,
因为编译器并不知道哪些文件是最近更新的,而只知道需要包含这些文件才能把源代码编译成可执行文件,
于是,程序员就不能不再重新输入数目如此庞大的文件名以完成最后的编译工作。
编译过程是分为编译、汇编、链接不同阶段的,其中编译阶段仅检查语法错误以及函数与变量的声明是否正确声明了,
在链接阶段则主要完成是函数链接和全局变量的链接。因此,那些没有改动的源代码根本不需要重新编译,而只要把它们重新链接进去就可以了。所以,人们就希望有一个工程管理器能够自动识别更新了的文件代码,同时又不需要重复输入冗长的命令行,这样,Make工程管理器也就应运而生了。
实际上,Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作。用户只需编写一次简单的编译语句就可以了。它大大提高了实际项目的工作效率,而且几乎所有Linux下的项目编程均会涉及到它
1》makefile文件
Make在执行时,需要一个命名为Makefile或者makefile的文件。Makefile文件描述了整个工程的编译,链接等规则。
其中包括:1.工程中的哪些源文件需要编译以及如何编译;
2需要创建哪些库文件以及如何创建这些库文件、
3如何最后产生我们想要的可执行文件。
2》makefile语法
make通过定义规则来决定如何生成文件
规则:用于说明如何生成一个或者多个目标文件,规则格式如下:
目标:依赖目标
(以tab空格)命令
比如
a:hello.c
gcc hello.c -o hello
a就是一个目标名称:hello.c就是目标依赖的文件 这里如果没有依赖其他目标可以放置依赖的文件
gcc hello.c -o hello 就是执行这个目标的命令 tab间隔隔开
在源代码目录新建makefile
a:hello.c
gcc hello.c -o hello
make编译
[root@localhost vc]# make
gcc hello.c -o hello
3》多文件的makefile依赖
假设有如下案例:
存在一个公用的头文件 a.h(用于定义全局变量和 方法定义)
#include <stdio.h>
#include <stdlib.h>
int add(int p1,int p2); //该方法在mmath.c中实现
void syso(char* c); //该方法在syso.c中实现
mmath.c实现add方法 内容如下:
#include "a.h"
int add(int p1,int p2){
return p1+p2;
}
syso.c实现syso方法
#include "a.h"
void syso(char* c){
printf(c);
}
main.c提供main方法入口 并且通过头文件调用add方法获取结果 调用syso输出结果
#include "a.h"
void main(){
int number=add(111,333);
char str[25];
sprintf(str, "%d", number);
syso(str);
}
我们知道main.c就是将来运行的程序的入口 如果直接编译 main.c会出现没有找到两个方法实现错误
因为需要先生成mmath.o,syso.o,main.o 在进行链接生成最后的文件
[root@localhost rule]# gcc main.c -o main
/tmp/ccowuqtm.o:在函数‘main’中:
main.c:(.text+0x13):对‘add’未定义的引用
main.c:(.text+0x3b):对‘syso’未定义的引用
collect2: 错误:ld 返回 1
需要使用makefile文件定义最后生成的程序目标需要依赖生成三个.o文件的目标
注意 make命令永远只执行第一个目标 如果这个目标依赖其他目录 依赖的目标先被执行
m:a b c
gcc mmath.o syso.o main.o -o main
a:
gcc -c main.c -o main.o
b:
gcc -c mmath.c -o mmath.o
c:
gcc -c syso.c -o syso.o
clean:
rm -rf *.o
运行(clean目标没有被执行因为 不是第一个目标 第一个目标也没有引用它 这种目标可以使用 make 目标名称运行):
[root@localhost rule]# make
gcc -c main.c -o main.o
gcc -c mmath.c -o mmath.o
gcc -c syso.c -o syso.o
gcc mmath.o syso.o main.o -o main
运行 clean目标
[root@localhost rule]# make clean
rm -rf *.o
为了让makefile文件可读性更好 建议目标 定义成生成的文件 如果是编译成目标文件依赖目标写成 源文件 比如
main:main.o mmath.o syso.o
gcc mmath.o syso.o main.o -o main
main.o:main.c
gcc -c main.c -o main.o
mmath.o:mmath.c
gcc -c mmath.c -o mmath.o
syso.o:syso.c
gcc -c syso.c -o syso.o
.PHONY:clean #将“clean”目标声称为伪目标 不声明也可以 make clean
clean:
rm -rf *.o
这样做的好处就是 目标如何和命令输出的文件名一致 在执行这个目标之前 判断是否有这个文件 有这个文件 提示 不需要创建目标 比如 执行过一次 第二次执行
[root@localhost rule]# make
make: “main”是最新的。
makefile中可以定义变量 也可以使用系统变量 常用系统变量
$^ :代表所有的依赖
$*:代表所有的依赖 自动去掉后缀名
$@ :代表目标
$< :代表第一个依赖
在每个目标中 命令中可以使用这三个变量 可以通过封装的特点 减少重复代码
main:main.o mmath.o syso.o
gcc $^ -o $@ #$^代表所有依赖也就是上面的main.o mmath.o syso.o $@代表目标也就是上面main
main.o:main.c
gcc -c $^ -o $@
mmath.o:mmath.c
gcc -c $< -o $@ #$<代表第一个依赖 mmath.c 当然这里就一个依赖
syso.o:syso.c
gcc -c $^ -o $@
clean:
rm -rf *.o
上面的make中 gcc一旦修改 很多地方跟着修改 还可以定义一些自定义参数等 可以通过变量来定义 让程序更优雅
CC=gcc
INCLIDE=.
CFLAGS=-g -Wall -ansi -I$(INCLIDE)
main:main.o mmath.o syso.o
$(CC) $(CFLAGS) $^ -o $@
main.o:main.c
$(CC) $(CFLAGS) -c $^ -o $@
mmath.o:mmath.c
$(CC) $(CFLAGS) -c $< -o $@
syso.o:syso.c
$(CC) $(CFLAGS) -c $^ -o $@
clean:
rm -rf *.o
在其他目录 如果想直接某个目录下的make文件 可以使用 -C命令
表示进入 当前的hello目录下 执行makefile 执行目标clean
[root@localhost vc]# make -C ./hello clean
make: 进入目录“/root/vc/hello”
rm -rf hello
make: 离开目录“/root/vc/hello”