项目make 成功后没有生成的文件_浅谈 GNU Make 构建项目实践

本文介绍了GNU Make的基础原理,通过实际项目经验深入讨论了Makefile的编写,包括单文件和多文件C程序的构建、头文件依赖处理、复杂项目构建的通用规则与模板。此外,还探讨了在Vim中利用Makefile进行快捷编译的方法,旨在帮助读者更好地理解和应用Make。
摘要由CSDN通过智能技术生成

浅谈 GNU Make 构建项目实践

摘要

本文简明地介绍 make 的基础原理,并组合实际项目经验,由浅入深讨论了一种实用 的 makefile 通用规则与模板的编写方案。对其中涉及的语法功能技巧择要阐述,希望 有助于初学者理解。

make 原理简介

make 是 linux/unix 系统下的一款工具,就如同 ls/cp/find/grep 这类程序一样属 于基础、通用且经典的设施。其基本原理是根据目标文件与依赖文件的(时间戳)新旧关 系,如果依赖文件更新了(目标文件更旧了),就执行指定的一系列操作。因此它需要这 两部分关键信息,或按 make 的术语叫“规则”:

  • 哪个目标文件,会依赖哪些目标文件
  • 满足条件后要执行什么样的操作

用户需要将这些规则写入配置文件,以指示 make 的运行,习惯上取名为 makefileMakefie ,也可取为其他名字,那就需要额外加上 -f 选项,如:

make
make -f filename_other_than_makefile

一个简单的 makefile 规则内容如下:

oldfile: newfile
    echo Hello World
    echo 'cp newfile oldfile' >> make.log
    cp newfile oldfile

这里假设 makefile 文件所在目录中另有两个文件名为 oldfilenewfile ,只 要在该目录下执行 make 命令,make 程序就会比较这两个文件的时间戳,如果 newfile 更新了,就会将其复制到 oldfile (作为备份之用?),如果没有更新就 不会有任何操作。

可以配置多条操作,凡能在 shell 命令行执行的操作都行。每操作配置需要缩进一个 TAB 键,目标与依赖文件不能缩进,用一个 : 分隔。这就是 makefile 文件的基 本格式要求,当然还有其他许多语法细节,诸如变量引用、变量替换函数、目标依赖链、 隐式规则等,那就不是本文所能细说的了,请参考其他入门教程以及官方手册。

简单 C 程序的构建

虽然可以花式操作用 make 做些奇怪的事,但 make 的主要用途是构建 C/C++ 程序 。一般地,从 C/C++ 源文件到最终可执行程序要经过预处理、编译、链接等多步流程, make 就是为简化这种构建流程而诞生的。

单文件程序

先看个最简单的情况,假设只有一个 main.c 文件,那么 makefile 可如下写法:

main.exe: main.o
    gcc -o main.exe main.o

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

这规则文件表明,main.exe 文件依赖 main.o ,而 main.o 又依赖 main.c 。 于是若执行 make 命令,就相当于依次执行如下两条命令:

gcc -c -o main.o main.c
gcc -o main.exe main.o

结果会生成 main.exe 可执行文件,当然在 linux 系统下可执行文件不须也不推荐加 上 .exe 后缀名,此只为说明方便起见。

另外,gcc 编译器有很多默认行为,可直接执行 gcc -c main.c 生成默认 main.o 的目标文件,不必加 -o 选项。甚至直接 gcc main.c 一步到位,自动预处理、编译 、链接成可执行文件,不过若无 -o 指定输出文件名,默认生成的是 a.out

正因为构建 C/C++ 程序是 make 的拿手好戏,它专门为此默认了一些隐式规则,以简化 makefile 的编写,比如 *.o 目标文件的依赖与生成规则就可以省略。简化为一条规 则:

main.exe: main.o
    gcc -o main.exe main.o

多文件程序

当然对于单文件程序的编绎,没必要写 makefie ,直接 gcc -o main.exe main.c 一条命令解决问题。但假如有多个文件,除 main.c 外,还有两个额外的辅助源文件 util1.c util2.c (及相应的 .h 头文件)。这时直接一条命令虽然也能完成编译 链接工作:

gcc -o main.exe *.c

但有个问题,只要改了一个源文件,就要重新编译所有源文件。所以 make 就有用了, 可写个 makefile 如下:

TARGET = main.exe
ALL_OBJ = main.o util1.o util2.o

CFLAGS += -Wall 

$(TARGET) : $(ALL_OBJ)
    gcc $(CFLAGS) -o $(TARGET) $(ALL_OBJ)

这里用到了变量,语法类似 shell ,不过引用变量要加括号 $(VAR_NAME) 。也省略了 从 .c.o 的编译规则,但按 make 的隐式规则,也会自动编译生成三个 .o 中间文件。如果后来修改了一个 .c 文件,则 make 只会重新编译一个 .o 文件, 另外两个目标不用重新编译,然后将新编译 .o 文件与原来无改动的 .o 文件一起链 接生成新的 main.exe 最终可执行文件。

make 命令可以加参数的,参数就是所用 makefile 内定义的目标(文件)名,默认 是文件内定义的第一个目标。假如在开发中改过 util1.c 文件,只是暂时想 检查一下语法有没错误,可以明确提供目标参数:

make util1.o

这里的 util1.o 能由隐式规则生成,故而也是可用的。这比直接在命令行写 gcc -c util1.c 的优势是可在 makefile 定义一系列编译选项,避免记不住或每次 输入麻烦的问题。

头文件包含依赖处理

前述的三文件例程,还漏了重要一点,没加入头文件依赖。最终可执行 main.exe 只依 赖几个 .o 文件,而每个 .o 文件只依赖对应的 .c 文件,在上个

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值