linux makefile 头文件和源码文件不在一个文件夹中,【Linux + Makefile】Makefile的高阶用法:解决C文件包含的头文件修改了,但C文件不重新编译的问题...

本文介绍了如何在Linux Makefile中处理头文件和源码文件不在同一目录的情况,以及当头文件修改时,确保C文件会自动重新编译。通过利用GCC的-MD和-MF选项生成依赖文件列表,实现了头文件变化时自动触发C文件的重新编译,从而解决了Makefile中的常见问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://blog.csdn.net/szullc/article/details/85038875

在上一篇 《【Linux + Makefile】十分钟教你学会Makefile的FORCE 》文章的最后,笔者就FORCE的用法在一个示例工程中使用,提出了一个问题:为何build_info.h每次都是新生成的(有修改过),而main.c又是有include “build-info.h”,但main.c却不是每次都重新编译呢?这个到底是不是违反了Makefile的基本规则呢?本文将给你答案,通过阅读本文,你将了解到以下内容:

如何保证在C文件中包含的头文件修改了的时候,C文件每次都会被重新编译?

为了更好地展示上诉描述的问题,我们将之前的示例工程稍微复杂化一点点:

整个工程有3个.c文件,a.c/b.c/main.c,其中main.c会调用a.c/b.c中的两个接口,同时main.c会include头文件build_info.h;这个build_info.h每次编译都会重新生成,按照我们之前的写法,我们Makefile可能就是这样:

SHELL = /bin/bash #指定shell使用/bin/bash,否则echo -e可能会出问题

ECHO = echo

BIN = test

BUILG_INFO_H = build_info.h

SRC-C-y += a.c

SRC-C-y += b.c

SRC-C-y += main.c

SRC-O = $(patsubst %.c, $(O)%.o, $(SRC-C-y))

all: gen_build_info $(BIN)

clean:

rm -rf $(SRC-O) $(BIN) $(BUILG_INFO_H)

$(BIN) : $(SRC-O)

gcc -o $(O)"$@" $(SRC-O)

%.o : %.c

gcc -c "$

gen_build_info: $(BUILG_INFO_H)

$(BUILG_INFO_H): FORCE #强制生成build_info.h

@$(RM) $@

@$(ECHO) ' GEN $@'

@$(ECHO) -e " #ifndef __BUILD_INFO_H__\n"\

"#define __BUILD_INFO_H__\n"\

"#define APP_TIME \"`date "+%Y-%m-%d %H:%M:%S"`\"\n"\

"#endif" > $@

FORCE:

.PHONY: FORCE

执行make,我们会发现,跟我们的预期不一样:它虽然会每次都生成build_info.h,但是main.c包含了build_info.h却不会每次都重新编译。这个问题发生的原因,我们来分析下:

在我们的Makefile规则中,main.o只依赖于main.c (Makefile 第18-19行),而在第二次执行make的时候,main.c显然并没有被修改,所以main.o不会重新生成,自然可执行文件就不会重新生成。这里的问题根源在于,main.c它是依赖于build_info.h的,而这个依赖关系并没有体现在Makefile中,所以整个编译流程达不到我们的预期想法。我们尝试下,将main.c的依赖头文件也写入到Makefile中,怎么实现呢?

恰好,GCC给了我们强大的支持,它有个非常有用的选项 -MD -MF,它可以在生成一个.o的同时也生成它的依赖文件列表,修改后的Makefile如下所示:

SHELL = /bin/bash #指定shell使用/bin/bash,否则echo -e可能会出问题

ECHO = echo

BIN = test

BUILG_INFO_H = build_info.h

SRC-C-y += a.c

SRC-C-y += b.c

SRC-C-y += main.c

SRC-O = $(patsubst %.c, $(O)%.o, $(SRC-C-y))

SRC-C-DEPS = $(patsubst %.c, $(O).%.o.d, $(SRC-C-y)) ## 由 a.c ==> .a.o.d

all: gen_build_info $(BIN)

clean:

rm -rf $(SRC-O) $(BIN) $(BUILG_INFO_H) $(SRC-C-DEPS)

$(BIN) : $(SRC-O)

gcc -o $(O)"$@" $(SRC-O)

%.o : %.c

#生成xxx.o的时候,同时生成它的依赖列表,放在文件.xxx.o.d中

gcc -c "$

gen_build_info: $(BUILG_INFO_H)

$(BUILG_INFO_H): FORCE #强制生成build_info.h

@$(RM) $@

@$(ECHO) ' GEN $@'

@$(ECHO) -e " #ifndef __BUILD_INFO_H__\n"\

"#define __BUILD_INFO_H__\n"\

"#define APP_TIME \"`date "+%Y-%m-%d %H:%M:%S"`\"\n"\

"#endif" > $@

FORCE:

.PHONY: FORCE

# 在Makefile末尾强制包含这些依赖文件

-include $(SRC-C-DEPS)

测试结果如下所示:

214125546_1_20210127113801835

再次执行make,多试几次,一样的结果。

214125546_2_20210127113802272

由上可知,经过改造后的Makefile是实现了我们的需求,每次build_info.h重新生成,导致main.c包含了build_info.h也会重新编译,而a.c和b.c没有被修改,所以在未执行make clean的情况下,a.c和b.c是不会被重新编译的,每次都是仅仅main.c被再次编译,从而重新生成新的test可执行文件。这样就是已经达到了【当C文件包含的头文件修改了的时候,C文件必须重新编译】的目的。

以上就是关于Makefile的高阶用法,基本满足了我们日常工程实践的需求。如果你对该Makefile有疑问,欢迎在评论席提出你的疑问,博主很乐意为你解答。

原创作者:李路昌

电子邮箱:recan.szu@foxmail.com

延伸阅读:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值