Makefile工具的使用

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

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

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

#include"test.h"

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

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

在test.c中

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

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

gcc test.h main.c -o main

运行结果就是
this is test.c

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

makefile简单示例

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

main.o:test.o main.c
    gcc test.o main.c
test.o:test.c
    gcc -c test.c

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

gcc -c test.c   
gcc test.o main.c

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

Makefile具体使用

伪目标

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

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来执行伪目标

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

Makefile自动变量

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

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

main.o:test.o main.c
    gcc -g $^ -o $@
test.o:test.c
    gcc -g -c  $< -o $@

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

gcc -c test.c   
gcc test.o main.c

编译生成多个可执行文件

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中函数的调用形式

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

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

  • $(wildcard path)
    当前目录下匹配模式的文件
src=$(wildcard *.c)  // 在当前目录下搜索所以.c文件,文件名称保存到src中
  • $(patsubst pattern,replacement,text)模式替换函数,就是把text中文件列表从模式pattern替换为replacement模式
$(patsubst %.c,%.o,$src)  // 把src中的.c文件列表中的文件从.c替换为.o
等价于:$(src:.c=.o)  //这种方式更为常用
  • shell函数 shell函数可以执行shell下的命令,同样是使用$来引用的,例如
$(shell ls -d */)  //将当前目录下的所有文件列出来

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

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)

猜你喜欢

转载自blog.csdn.net/qq_39478237/article/details/82833077
今日推荐