首页 > 代码库 > 学习写Makefile文件

学习写Makefile文件

Linux 环境下的程序员如果不会使用GNU make来构建和管理自己的工程,应该不能算是一个合格的专业程序员,至少不能称得上是 Unix程序员。。在 Linux(unix )环境下使用GNU 的make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile 文件的编写。

那么问题出来了,Makefile究竟应该怎么编写?

下面看下面程序(Test.c):

#include <stdio.h>

int main(int argc,char *argv[])
{
    printf("hello world\n");
    return 0;
}
初学者很多都直接在命令行编译链接:gcc–o Test Test.c

因此他们觉得用不用Makefile无所谓。其实不然,我们看下面程序:

程序有三个文件:Test.c、add.h 、add.c

Test.c 文件

#include <stdio.h>
#include"add.h"

int main(int argc,char *argv[])
{
    printf("%d \n",add(1,2));
    return 0;
}

add.h 文件

#ifndef ADD_H_
#define ADD_H_

int add(int a,int b);

#endif /* ADD_H_ */

add.c 文件

int add(inta,intb)
{

   return a+b;

}

此时,如果你再用命令去编译链接时候就显得比较麻烦了,如果代码文件更多呢?那就不可想象了,因此我们要学会写Makefile文件。

Makefile是一个文件文件形式的脚本文件,其中包含一些规则告诉make编译哪些文件怎么编译以及在什么条件下编译。

让我们先来粗略地看一看Makefile的规则。[

target:dependency

    command

...

目标:依赖

     执行指令 ...

注意每个command 第一个字符必须是tab键,而不是4个空格。不然的话make会报错停止。执行的时候make空格后接目标,当然也可以不输入目标。这时make就会默认只执行第一个目标。

下面就由简单到复杂编写Makefile文件:

1.写一个最简单的Makefile

start:
	gcc –o test Test.c


在命令输入make回车即可完成编译和链接。

2..将编译和链接分开

start:Test.o

        gcc -o Test Test.o

Test.o:Test.c

        gcc -o  Test.o -c Test.c


这里出现两个目标(target)start,和Test.o如果在make时候没有加上目标的话,其只会执行第一个目标,除非有依赖才执行下面的(如2)。这里当你在命令行中输入make后面没有更任何参数时候其会从start开始执行,发现其依赖Test.o文件,其就往下找,就会执行Test.o这个目标。

当然这里可以make Test.o ,就不会执行第一个目标了。

3.引入变量

CC = gcc

SRCS = Test.c

OBJS = Test.o

EXEC = Test

start:$(OBJS)

        $(CC) -o $(EXEC) $(OBJS)

$(OBJS):$(SRCS)

        $(CC) -o $(OBJS) -c$(SRCS)


为什么要引入变量CC,SRCS等(变量习惯使用大写),后面在使用变量的时候要这样写:$(变量名)。引入变量的原因,主要是方便修改,比如要换编译器,要换文件等比较方便。

4.进一步完善

CC = gcc

SRCS = Test.c

OBJS = $(SRCS:.c=.o)

EXEC = Test

start:$(OBJS)

        $(CC) -o $(EXEC) $(OBJS)

$(OBJS):

        $(CC) -o $(OBJS) -c$(SRCS)
clean:
        rm -f $(OBJS)

OBJS = $(SRCS:.c=.o) 这句话意思是把SRSC字符中.c替换成.o

5.再完善

.SUFFIXES:.c .o

CC = gcc

SRCS = Test.c

OBJS = $(SRCS:.c=.o)

EXEC = Test

start:$(OBJS)

        $(CC) -o $(EXEC) $(OBJS)
.c.o:

        $(CC) -o $@ -c $<
clean:

        rm -f $(OBJS)

.SUFFIXES:.c .o 表示任何x.c 和x.o相关联如果这里使用是cpp文件则改为:.SUFFIXES:.cpp .o (注意cpp和.o之间有个空格)

OBJS = $(SRCS:.cpp=.o)


$@和$<是make预定义的变量。$@为规则目标所对应的文件名,$<规则中第一个相关的文件名(这里可以理解为.c文件)。

6.如果有多个.c或者.cpp文件怎么办?Test..c 和add.c 文件存在。

.SUFFIXES:.c .o
CC = gcc
SRCS = Test.c        add.c
OBJS = $(SRCS:.c=.o)
EXEC = Test

start:$(OBJS)
	$(CC) -o $(EXEC) $(OBJS)
.c.o:
	$(CC) -o $@ -c $<
clean:
	rm -f $(OBJS)

这里\ 相当于换行链接。三个可以写成这样

技术分享

如果文件非常多也可以这样写,

.SUFFIXES:.c .o
CC = gcc
SRCS = $(shell ls *.c)
OBJS = $(SRCS:.c=.o)
EXEC = Test

start:$(OBJS)
	$(CC) -o $(EXEC) $(OBJS)
.c.o:
	$(CC) -o $@ -c $<
clean:
	rm -f $(OBJS)
$(shell ls *.c) 表示使用shell 查找符合条件文件

执行结果:

技术分享



 




学习写Makefile文件