一步一步学写makefile

来源:互联网 发布:php正则验证身份证 编辑:程序博客网 时间:2024/05/08 20:27


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

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

一 规则

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


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

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

二 单文件编译

假如有如下程序:
// main.c#include <stdio.h>int main() {    printf("hello world\n");    return 0;}

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

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

三 多文件编译

假如有如下几个程序:
// add.hint add(int a, int b);

// add.c#include "add.h"int add(int a, int b) {    return a + b;}


// sub.hint sub(int a, int b);


// sub.cint sub(int a, int b) {    return a - b;}

// main.c#include <stdio.h>#include "add.h"#include "sub.h"int main() {    printf("%d + %d = %d\n", a, b, add(a, b));    printf("%d - %d = %d\n", a, b, sub(a, b));    return 0;}

用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:
main:main.o add.o sub.o    gcc -o main main.o add.o sub.omain.o:main.c    gcc -c main.cadd.o:add.c add.h    gcc -c add.csub.o:sub.c sub.h    gcc -c sub.cclean:    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文件如下:
CC=gccCFLAGS=-Wall -gBIN=main$(BIN):main.c    $(CC) $(CFLAGS) -o $@ $^

3 多文件编译优化

看上去好像反而变复杂了,再看优化之后的多文件编译的makefile:
CC=gccCFLAGS=-Wall -gBIN=mainOBJ=main.o add.o sub.omain:$(OBJ)    $(CC) $(CFLAGS) -o $@ $^main.o:main.c    $(CC) -c $^add.o:add.c add.h    $(CC) -c $^sub.o:sub.c sub.h    $(CC) -c $^

五 自动推导

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

六 添加clean

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


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

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

最终我们得到多文件编译的makefile文件如下:
CC=gccCFLAGS=-Wall -gBIN=mainOBJ=main.o add.o sub.omain:$(OBJ)    $(CC) $(CFLAGS) -o $@ $^.o:    $(CC) -c $^.PHONY:cleanclean:    rm -f *.o $(BIN)


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



0 0
原创粉丝点击