IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> GNU Makefile--C/C++头文件依赖规则的生成 -> 正文阅读

[系统运维]GNU Makefile--C/C++头文件依赖规则的生成

使用GCC编译器生成头文件依赖

复杂的C/C++工程中的头文件比较多,在编写GNU Makefile时,手动指出其源代码文件的头文件依赖关系是不可行的,需要通过编译工具自动生成头文件的依赖关系。GNU GCC的-MXX命令行选项用于生成某个代码文件的依赖关系,通常使用的命令行选项为:

-MT object.o -MP -MMD -MF object.d

其中,-MT用于指定与源文件对应的目标文件名(此处为object.o);-MP指示GCC编译器为依赖的头文件增加伪目标规则;-MMD不会隐含增加-E编译选项,一次编译操作可以生成头文件依赖文件(上面的object.d)和目标文件,且不引入系统头文件的依赖。最后-MF object.d指定生成的依赖文件名称为object.d。这四个选项不会干扰正常的编译、链接流程,仅仅是告知编译器需要生成object.d;也就是说,依赖规则文件object.d在每次编译时都会随目标文件的生成而重新生成。

GNU Make读取依赖文件

依赖文件(或者依赖规则文件)是由GCC编译器在编译链接过程中,通过上面的-MXXX选项生成的。那么第一次编译C/C++代码时,这些依赖文件是不存在的;那么问题就来了:GNU Make如何包含一个尚未生成的规则文件?官方文档给出了解决方案:

-include FILENAMES
sinclude FILENAMES

GNU Make的-include指令可以忽略规则文件时文件不存在的错误。不过,这一功能特点并不能保证依赖文件会被创建。上面第一节中说明了,依赖文件会在编译过程被生成;这利用了GCC编译器的功能特性。某些情况下,还必须强制生成依赖文件,以便下次编译时能包含到。事实上,只要通过include命令包含的头文件,GNU Make都会尝试进行更新,不论其是否已经存在,这一点后面会提到。

笔者编写的简单C/C++代码共有4个文件,hello.c文件内容为:

#include <stdio.h>
#include "header0.h"
#include "header1.h"
int main(int argc, char *argv[])
{
    printf("%s %s!\n", HELLO, WOLRD);
    return 0;
}

header0.h的内容为:

#ifndef AD_HEADER0_H
#define AD_HEADER0_H 1
#define HELLO "hello"
#endif

header1.h的内容为:

#ifndef AD_HEADER1_H
#define AD_HEADER1_H 1
#include "header2.h"
#define WOLRD "world"
#endif

header2.h的内容为:

#ifndef AD_HEADER2_H
#define AD_HEADER2_H 1
/* nothing to define here */
#endif

最后,编写的Makefile脚本如下:

MAKEFLAGS   += -r -R
CC          := gcc
CFLAGS      := -Wall -O2 -fPIC
SOURCES     := $(wildcard *.c)
OBJS        := $(SOURCES:%.c=%.o)
DEPENDS     := $(SOURCES:%.c=%.d)
TARGETS     := $(OBJS) hello

.PHONY: all clean
all: $(TARGETS)
%: %.o
	$(CC) -o $@ $<
%.o %.d: %.c
	$(CC) -c $(CFLAGS) -MT $*.o -MP -MMD -MF $*.d -o $*.o $<

define include_depend
sinclude $(1)
endef
$(foreach depend,$(DEPENDS),$(eval $(call include_depend,$(depend))))
clean:
	rm -rf $(TARGETS)

自动生成的依赖文件

以上源代码文件保存后,执行make可以自动生成依赖文件hello.d

$ make
gcc -c -Wall -O2 -fPIC -MT hello.o -MP -MMD -MF hello.d -o hello.o hello.c
gcc -o hello hello.o
$ cat hello.d
hello.o: hello.c header0.h header1.h header2.h

header0.h:

header1.h:

header2.h:

查看其内容,可以了解到是标准的Makefile依赖规则;此外,该规则还列出了其间接依赖的header2.h头文件。这正是自动生成大型C/C++工程的头文件依赖关系的基本机制。当仅更新头文件,执行make会重新编译生成hello.o:

$ touch header1.h
$ make
gcc -c -Wall -O2 -fPIC -MT hello.o -MP -MMD -MF hello.d -o hello.o hello.c
gcc -o hello hello.o

这一点正是我们需要达到的效果。

强制生成依赖文件

注意到上面编写的Makefile没有将hello.d文件删除。如果在clean目标中,将该文件删除会怎么样?首先看一下不删除hello.d的效果:

$ make clean
rm -rf hello.o hello
$ make clean
rm -rf hello.o hello

接下来修改Makefile:

diff --git a/Makefile b/Makefile
index 5ef6129..74853be 100644
--- a/Makefile
+++ b/Makefile
@@ -24,4 +24,4 @@ endef
 
 $(foreach depend,$(DEPENDS),$(eval $(call include_depend,$(depend))))
 clean:
-       rm -rf $(TARGETS)
+       rm -rf $(TARGETS) *.d

多次执行make clean结果如下:

$ make clean
rm -rf hello.o hello *.d
$ make clean
gcc -c -Wall -O2 -fPIC -MT hello.o -MP -MMD -MF hello.d -o hello.o hello.c
rm -rf hello.o hello *.d
$ make clean
gcc -c -Wall -O2 -fPIC -MT hello.o -MP -MMD -MF hello.d -o hello.o hello.c
rm -rf hello.o hello *.d

出现这样的结果是因为,依赖文件hello.d是Makefile需要包含的文件;而对于包启的脚本文件,GNU Make会强制更新;如果未找到更新的规则,就会报错(此处不报错是因为使用了sinclude),或者不更新(当文件已存在时);官方文档对此做了详细的说明。因此,上面的编译脚本不删除依赖文件hello.d是有正当理由的。

最后,推荐使用CMake,已集成了自动生成头文件依赖文件的功能,可以省去这些烦恼。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 11:10:24  更:2021-08-02 11:10:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 16:22:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码