Fork me on GitHub

Makefile工具使用

Makefile是一个c语言的编译工具。如果学过Java,可能会认识Maven工具,makefile也是类似的工作。
Makefile能帮助c语言建立自动化的编译。一旦写好,执行一个make命令就可以编译整个工程。当然编写Makefile文件的时候有很多知识点在里面。这篇文章主要讲解如何编写基础性以及常用的Makefile文件。

没有Makefile工具时如何进行编译

首先我们看一个例子:
当前我们有3个文件,分别是test.h test.c main.c
在main.c中,头文件定义如下

1
#include"test.h"

在test.h中,头文件定义如下

1
2
#include"test.c"
void test_print();

在test.c中

1
2
3
4
5
#include<stdio.h>
void test_print()
{
printf("this is test.c \n");
}

当我们编译运行程序时,我们使用的命令是

1
gcc test.h main.c -o main

运行结果就是
this is test.c

对于小程序我们可以使用这样的命令,但是当我们这样运行一个大项目时,我们需要多少文件名来定义,此时Makefile就是一个很好的工具

makefile简单示例

就如上面的三个文件
我们vim 一个名为Makefile的文件

1
2
3
4
main.o:test.o main.c
gcc test.o main.c
test.o:test.c
gcc -c test.c

编辑好Makefile文件后,我们返回,执行make后,将会输出

1
2
gcc -c test.c   
gcc test.o main.c

这样是不是比原始的编译方便很多呢。其实也不是罪方便的,既然发明了make工具,那么肯定会让make工具更加方便开发人员使用的。

Makefile具体使用

伪目标

伪目标:不管是不是最新的,都需要重新生成;使用.PHONY来声明一个目标是伪目标;执行伪目标的效果等于执行了某一个动作,并不产生目标文件。例如添加一个伪目标:

1
2
3
4
5
6
main.o:test.o main.c
gcc test.o main.c
test.o:test.c
gcc -c test.c
clean : 【这是一个伪目标】
rm -f $(OBJECTS) main

使用make来执行伪目标

1
2
$ make clean
rm -f test.o main.c main.o

Makefile自动变量

选项名 作用
$@ 编写规则中啊哟生成的目标对象
$^ 编写规则中所有依赖文件列表
$< 编写规定中第一个依赖对象

因此,上面的Makefile文件我们可以改下如下:

1
2
3
4
main.o:test.o main.c
gcc -g $^ -o $@
test.o:test.c
gcc -g -c $< -o $@

执行make,可以看到效果还是一样的:

1
2
gcc -c test.c   
gcc test.o main.c

编译生成多个可执行文件

1
2
3
4
5
6
7
8
9
10
11
12
13
bin=main main2   //自定义变量bin
src=main.o test.o
all:$(bin) //重点
main: $(src)
gcc -g $^ -o $@
main2:$(bin)
gcc -g $< -o $@
main.o :main.c
gcc -g -c $< -o $@
main2.o :main2.c
gcc -g -c $< -o $@
clean :
rm -f $(src) $(bin)

为了生成目标文件all,需要生成bin,也就是main main2.这样就生成了两个可执行文件,利用自定义变量可以简化这段Makefile,但是这样写看起来内容其实还是很多的,因此下面我将介绍make的内嵌函数

make常用内嵌函数

首先看到make中函数的调用形式

1
$(function arguments)   //functions是函数名称,arguments是参数,使用$来调用

函数名与参数之间是空格
以下三个重要的内嵌函数

  • $(wildcard path)
    当前目录下匹配模式的文件

    1
    src=$(wildcard *.c)  // 在当前目录下搜索所以.c文件,文件名称保存到src中
  • $(patsubst pattern,replacement,text)模式替换函数,就是把text中文件列表从模式pattern替换为replacement模式

    1
    2
    $(patsubst %.c,%.o,$src)  // 把src中的.c文件列表中的文件从.c替换为.o
    等价于:$(src:.c=.o) //这种方式更为常用
  • shell函数
    shell函数可以执行shell下的命令,同样是使用$来引用的,例如

    1
    $(shell ls -d */)  //将当前目录下的所有文件列出来

下面我们通过一个例子来使用上面三个函数。假设当前目录下有main.c文件,同时还有若干个目录,每个目录中都有各自的.c文件,利用所有的.c文件编译生成最后的main文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CC      = gcc
CFLAGS = -g
BIN = main
SUBDIR = $(shell ls -d */) // SUBDIR变量保存了子目录的列表
ROOTSRC = $(wildcard *.c) //ROOTSRC保存了当前目录下的.c文件列表
ROOTOBJ = $(ROOTSRC:%.c = %.o) //ROOTBOJ 保存了当前目录下.c文件同名的.o列表
SUBSRC = $(shell find $(SUBDIR) -name '*.c') //SUBSRC 保存了所有子目录下的的.c文件
SUBOBJ = $(SUBSRC:%.c = %.o) //SUBOBJ保存了所有子目录下的.c文件同名的.o文件列表
$(BIN):$(ROOTOBJ) $(SUBOBJ) //main的生成依赖与当前目录及所有子目录下的.o文件
$(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ)
.o .c:
$(CC) $(CFLAGS) -c %< -o $@
clean:
rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)

本文标题:Makefile工具使用

文章作者:LiuXiaoKun

发布时间:2018年09月24日 - 16:09

最后更新:2018年10月05日 - 14:10

原始链接:https://LiuZiQiao.github.io/2018/09/24/Makefile工具使用/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%