makefile实例

Makefile的介绍

使用 GCC 的命令行进行程序编译在单个文件下是比较方便的,当工程中的文件逐渐增多,甚至变得十分庞大的时候,使用 GCC 命令编译就会变得力不从心。Linux 中的 make 工具提供了一种管理工程的功能,可以方便的进行程序的编译,对更新的文件进行重编译。

Makefile的基本格式为:

TARGET... : DEPENDEDS...
    COMMAND
    ...
    ...
  • TARGET:规则所定义的目标,通常是最后生成的文件,也可以是一个“动作”,称之为“伪目标”。
  • DEPENDEDS:执行此规则所必须的依赖条件。
  • COMMAND:规则所执行的命令。命令可以是多个,每个命令占一行,以 Tab 开头。

使用make进行项目管理,需要编写Makefile。在编译时,make程序按照顺序从Makefile文件中读取指令,依次执行!
当需要编译工程时,直接在工程目录中执行 make 即可。如果想清除编译过程中生成的目标文件,执行 make clean 即可。
makefile两种执行方式:直接make与make -f 指定文件
如果在本地工程目录下有文件名为makefile的makefile文件,使用make执行编译,使用make clean执行清除目标文件。
如果在本地工程目录下有指定的makefile文件,比如:demo.makefile文件,使用make -f demo.makefile执行编译,使用make clean -f demo.makefile执行清除目标文件。
使用预定义变量的Makefile

在Makefile中还有一些变量是系统预定义的,用户可以直接使用。

Makefile中经常使用的变量及含义

变量名 含 义 默 认 值
AR 生成静态库库文件的程序名称 ar
AS 汇编编译器的名称 as
CC C语言编译器的名称 cc
CPP C语言预编译器的名称 $(CC) -E
CXX C++语言编译器的名称 g++
FC FORTRAN语言编译器的名称 f77
RM 删除文件程序的名称 rm -f
ARFLAGS 生成静态库库文件程序的选项 无默认值
ASFLAGS 汇编语言编译器的编译选项 无默认值
CFLAGS C语言编译器的编译选项 无默认值
CPPFLAGS C语言预编译器的编译选项 无默认值
CXXFLAGS C++语言编译器的编译选项 无默认值
FFLAGS FORTRAN语言编译器的编译选项 无默认值

因此,前面的Makefile文件可以改写成:

CFLAGS = -Iadd -Isub -O2
OBJS = add/add_int.o add/add_float.o \
       sub/sub_int.o sub/sub_float.o main.o
TARGET = cacu

$(TARGET):$(OBJS)
    $(CC) -o $(TARGET) $(OBJS) $(CFLAGS)

clean:
    -$(RM) $(TARGET) $(OBJS)

其中变量 $(CC) $(RM)可以直接使用,默认值分别是 ccrm -f。另外 CFLAGS等变量是调用编译器时的默认选项配置,在生成 main.o时没有指定编译选项,make程序自动调用了文件中定义的 CFLAGS选项来增加头文件的搜索路径。
使用自动变量的Makefile

还记得上面出现的 <<和@ 吗?它们是Makefile中的自动变量,分别代表依赖项和目标项。下面是一些常见的自动变量及其含义:

Makefile 中常见的自动变量和含义

变量 含义
* 表示目标文件的名称,不包含目标文件的扩展名
+ 表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能包含重复的依赖文件
< 表示依赖项中第一个依赖文件的名称
? 依赖项中,所有目标文件时间戳晚的依赖文件,依赖文件之间以空格分开
@ 目标项中目标文件的名称
^ 依赖项中,所有不重复的依赖文件,这些文件之间以空格分开

由此,对上面的Makefile文件进行重写,代码如下:

CFLAGS = -Iadd -Isub -O2
OBJS = add/add_int.o add/add_float.o \
       sub/sub_int.o sub/sub_float.o main.o
TARGET = cacu

$(TARGET):$(OBJS)
    $(CC) $^ -o $@ $(CFLAGS)

$(OBJS):%o:%c
    $(CC) -c $< -o $@ $(CFLAGS)

clean:
    -$(RM) $(TARGET) $(OBJS)

Makefile的实例

扫描二维码关注公众号,回复: 136469 查看本文章
实例
add.h
#include <stdio.h>

int add(int a,int b);

add.cpp
#include "add.h"

int add(int a,int b)
{
	int r = 0;
	r = a+b;
	return r;
}

main.cpp
#include "add.h"

int main(int argc, char *argv[])
{
	printf("simple demo \n");
	printf("add(91,8)=%d\n",add(91,8));
	
	return 0;
}

main.makefile文件或makefile文件
test:main.o add.o
	g++ main.o add.o -o test
	
main.o:main.cpp add.h
	g++ -c main.cpp -o main.o
add.o:add.cpp add.h
	g++ -c add.cpp -o add.o

.PHONY:clean
clean:
	rm -rf *.o test

文件名为makefile的makefile文件,使用make执行编译,使用make clean执行清除目标文件。
文件名为main.makefile文件,使用make -f main.makefile执行编译,使用make clean -f main.makefile执行清除目标文件。

简化后的makefile文件
#这是简化后的makefile
CC=g++
OBJS=main.o add.o

test:$(OBJS)
	${CC} $^ -o $@
%.o:%.c
	${CC} $< -o $@
    
clean:
	rm -rf *.o test

执行makefile并编译,生成test文件。
最后执行文件,输入命令./test

结果输出:
simple demo
add(91,8)=99

makefile中的$@, $^, $< , $?, $%, $+, $*

$@  表示目标文件
$^  表示所有的依赖文件
$<  表示第一个依赖文件
$?  表示比目标还要新的依赖文件列表
$%    表示仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是“foo.a(bar.o)”,那么,“$%”就是“bar.o”,“$@”就是“foo.a”。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$+ 这个变量很像“$^”,也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$*    这个变量表示目标模式中“%”及其之前的部分。如果目标是“dir/a.foo.b”,并且目标的模式是“a.%.b”,那么,“$*”的值就是“dir/a.foo”。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么“$*”也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么“$*”就是除了后缀的那一部分。例如:如果目标是“foo.c”,因为“.c”是make所能识别的后缀名,所以,“$*”的值就是“foo”。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用“$*”,除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么“$*”就是空值。

查看目标的依赖关系
写 Makefile 的时候, 需要确定每个目标的依赖关系。GNU提供一个机制可以查看C代码文件依赖那些文件。
查看C文件的依赖关系
gcc -MM main.c
结果输出
main.o: main.cpp add.h
查看C++文件的依赖关系
g++ -MM main.cpp
结果输出
main.o: main.cpp add.h

猜你喜欢

转载自blog.csdn.net/byxdaz/article/details/79578604