学写makefile

在做服务器开发的时候,需要用到gcc编译各种文件,如果文件多了,要做大量的重复工作。

这时候你需要make工具,写上一个makefile文件,就能轻松解决问题。

一 规则

makefile的编写规则如下:
target:components
    command


target目标名
components 依赖的文件或者目标
command 编译命令,前面必须有1个tab键,

运行:
make [-f filename] [target]
如果不指定filename和target,默认执行文件makefile的第一个target

二 单文件编译

假如有如下程序:
[cpp]  view plain  copy
  1. // main.c  
  2. #include <stdio.h>  
  3.   
  4.   
  5. int main() {  
  6.     printf("hello world\n");  
  7.     return 0;  
  8. }  

用gcc编译:
gcc -o main main.c

对应的makefile:
main:main.c
    gcc -o main main.c

三 多文件编译

假如有如下几个程序:
[cpp]  view plain  copy
  1. // add.h  
  2. int add(int a, int b);  

[cpp]  view plain  copy
  1. // add.c  
  2. #include "add.h"  
  3. int add(int a, int b) {  
  4.     return a + b;  
  5. }  


[cpp]  view plain  copy
  1. // sub.h  
  2. int sub(int a, int b);  


[cpp]  view plain  copy
  1. // sub.c  
  2. int sub(int a, int b) {  
  3.     return a - b;  
  4. }  

[cpp]  view plain  copy
  1. // main.c  
  2. #include <stdio.h>  
  3. #include "add.h"  
  4. #include "sub.h"  
  5.   
  6. int main() {  
  7.     printf("%d + %d = %d\n", a, b, add(a, b));  
  8.     printf("%d - %d = %d\n", a, b, sub(a, b));  
  9.     return 0;  
  10. }  

用gcc编译:
gcc -c add.c

生成add.o


gcc -c sub.c

生成sub.o


gcc -c main.c

生成main.o


gcc -o main main.o add.o sub.o
生成main

对应的makefile:
[plain]  view plain  copy
  1. main:main.o add.o sub.o  
  2.     gcc -o main main.o add.o sub.o  
  3. main.o:main.c  
  4.     gcc -c main.c  
  5. add.o:add.c add.h  
  6.     gcc -c add.c  
  7. sub.o:sub.c sub.h  
  8.     gcc -c sub.c  
  9. clean:  
  10.     rm -f *.o main  

四 makefile优化

1 常量和变量间接
makefile中预定义了一些变量
$* 不包含扩展名的目标文件名称,常用的如下:
$@ target目标名
$< 第一个依赖文件的名称
$^ 所有的依赖文件,以空格分开,不包含重复的依赖文件

C语言相关:
CC C编译器的名称,默认值为 cc
CFLAGS C编译器的选项
CPP C预编译器的名称,默认值为 $(CC) -E
CPPFLAGS CFLAGS C预编译的选项

C++语言相关:
CXX C++编译器的名称,默认值为 g++
CXXFLAGS C++编译器的选项

另外也可以自定变量,如:
BIN=main
定义了变量BIN,值为main

变量的引用方式:$(ValueName),如$(CC)
2 单文件编译优化
优化单文件编译的makefile文件如下:
[plain]  view plain  copy
  1. CC=gcc  
  2. CFLAGS=-Wall -g  
  3. BIN=main  
  4. $(BIN):main.c  
  5.     $(CC) $(CFLAGS) -o $@ $^  

3 多文件编译优化
看上去好像反而变复杂了,再看优化之后的多文件编译的makefile:
[plain]  view plain  copy
  1. CC=gcc  
  2. CFLAGS=-Wall -g  
  3. BIN=main  
  4. OBJ=main.o add.o sub.o  
  5. main:$(OBJ)  
  6.     $(CC) $(CFLAGS) -o $@ $^  
  7. main.o:main.c  
  8.     $(CC) -c $^  
  9. add.o:add.c add.h  
  10.     $(CC) -c $^  
  11. sub.o:sub.c sub.h  
  12.     $(CC) -c $^  

五 自动推导

看之前的makefile文件大量相似的规则如下:
[plain]  view plain  copy
  1. main.o:main.c  
  2.     $(CC) -c $^  
  3. add.o:add.c add.h  
  4.     $(CC) -c $^  
  5. sub.o:sub.c sub.h  
  6.     $(CC) -c $^  
其中有大段[.o]依赖[.c]和[.h]的文件,我们可以这样优化:
[plain]  view plain  copy
  1. .o:  
  2.     $(CC) -c $^  
make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系
同时将[.c]文件中包含的[.h]也加到依赖中

六 添加clean

为了方便,我们需要方便的清理编译过程中产生的中间文件,
我们可以加上一个清理目标clean,内容如下:
[plain]  view plain  copy
  1. clean:  
  2.     rm -f *.o $(BIN)  
执行:
make clean
就能清除中间过程产生的.o和可执行文件


因为"rm"命令并不产生"clean"文件,则每次执行"make clean"的时候,该命令都会执行。
如果目录中出现了"clean"文件,则规则失效了:没有依赖文件,文件"clean"始终是最新的,命令永远不会 执行;
为避免这个问题,可使用".PHONY"指明该目标。如:
[plain]  view plain  copy
  1. .PHONY:clean  
  2. clean:  
  3.     rm -f *.o $(BIN)  
这样执行"make clean"会无视"clean"文件存在与否。

.PHONY 目标并非实际的文件名:只是在显式请求时执行命令的名字。
有两种理由需要使用PHONY 目标:避免和同名文件冲突,改善性能。
.PHONY 目标并非是由其它文件生成的实际文件,make 会跳过隐含规则搜索,因此可以改善性能。

最终我们得到多文件编译的makefile文件如下:
[plain]  view plain  copy
  1. CC=gcc  
  2. CFLAGS=-Wall -g  
  3. BIN=main  
  4. OBJ=main.o add.o sub.o  
  5. main:$(OBJ)  
  6.     $(CC) $(CFLAGS) -o $@ $^  
  7. .o:  
  8.     $(CC) -c $^  
  9.   
  10.   
  11. .PHONY:clean  
  12. clean:  
  13.     rm -f *.o $(BIN)  


好了,makefile常用的就是这样子了。如果在命令行下面开发,makefile是必不可少的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值