makefile 自动生成头文件依赖关系

2023-11-13

在使用makefile 自动生成头文件依赖是,大家多半使用了下面这个方法。

这个sed语句被称之为 "上帝的符号",可读性不言而喻。(PS:CSDN这个排版怎么也搞不好,只能用图片了。)

gcc的 -MMD 选项可以自动生成带有依赖规则的.d文件,为创建头文件依赖带来了方便。

示例如下:

CC     = gcc

TARGET = main.out
LDLIBS = -m32 -Wl,--as-needed
CFLAGS = -m32 -g -MMD -MP -Wall -c

SRCS = main.c
ODIR = ./objs
OBJS = $(addprefix $(ODIR)/,$(SRCS:.c=.o))
DEPS = $(addprefix $(ODIR)/,$(SRCS:.c=.d))

.PHONY: all clean $(ODIR)

all: $(ODIR) $(TARGET)
	
$(TARGET): $(OBJS)
	$(CC) $(LDLIBS) $(OBJS) -o $@

$(ODIR)/%.o: %.c
	$(CC) $(CFLAGS) -o $@ $< 

-include $(DEPS)

$(ODIR):
	@test -d $@ || mkdir -p $@

clean:
	rm -rf $(ODIR)
	rm -f $(TARGET)

测试代码:

/*main.c*/

#include <stdio.h>
#include "test.h"

int main(int argc, char *argv[])
{
    printf("hello world! xtest=%d\n", xtest);
    return 0;
}

/*test.h*/
#define xtest (1)

[root@ubuntu:makefile]# ll
总用量 20
drwxr-xr-x 2 root root 4096 Oct 26 16:42 ./
drwxr-xr-x 8 root root 4096 Oct 25 17:36 ../
-rw-r--r-- 1 root root  136 Oct 26 16:09 main.c
-rwxr--r-- 1 root root  488 Oct 26 16:18 makefile*
-rw-r--r-- 1 root root   20 Oct 26 16:09 test.h
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]# cat ./objs/main.d
objs/main.o: main.c test.h

test.h:
[root@ubuntu:makefile]# touch test.h
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]#

原理分析:
gcc -MMD -MP *.c 生成带有头文件依赖关系的*.d
展开这个makefile的关键部分

CC     = gcc
TARGET = main.out
LDLIBS = -m32 -Wl,--as-needed
CFLAGS = -m32 -g -MMD -MP -Wall -c

SRCS = main.c
ODIR = ./objs
OBJS = $(addprefix $(ODIR)/,$(SRCS:.c=.o))
DEPS = $(addprefix $(ODIR)/,$(SRCS:.c=.d))

.PHONY: all clean $(ODIR)

all: $(ODIR) $(TARGET)
	
$(TARGET): $(OBJS)
	$(CC) $(LDLIBS) $(OBJS) -o $@

#$(ODIR)/%.o: %.c
objs/main.o: main.c
#	$(CC) $(CFLAGS) -o $@ $< 
	gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
	
#-include $(DEPS)
#-include main.d
objs/main.o: main.c test.h #-MMD选项生成
test.h:                    #-MP 选项生成

$(ODIR):
	@test -d $@ || mkdir -p $@

clean:
	rm -rf $(ODIR)
	rm -f $(TARGET)

合并相同的目标,makefile的最终形式为:

CC     = gcc
TARGET = main.out
LDLIBS = -m32 -Wl,--as-needed
CFLAGS = -m32 -g -MMD -MP -Wall -c

SRCS = main.c
ODIR = ./objs
OBJS = $(addprefix $(ODIR)/,$(SRCS:.c=.o))
DEPS = $(addprefix $(ODIR)/,$(SRCS:.c=.d))

.PHONY: all clean $(ODIR)

all: $(ODIR) $(TARGET)
	
$(TARGET): $(OBJS)
	$(CC) $(LDLIBS) $(OBJS) -o $@

objs/main.o: main.c test.h
	gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
	
test.h:

$(ODIR):
	@test -d $@ || mkdir -p $@

clean:
	rm -rf $(ODIR)
	rm -f $(TARGET)

关于test.h:

如果没有这个目标,当头文件被删除或者忘了包含时,make报错如下:

[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -Wall -c  -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]#
[root@ubuntu:makefile]#
[root@ubuntu:makefile]#
[root@ubuntu:makefile]# mv test.h test.x
[root@ubuntu:makefile]# make
make: *** 没有规则可以创建“objs/main.o”需要的目标“test.h”。 停止。
[root@ubuntu:makefile]#

加上test.h: make报错如下:

[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
gcc -m32 -Wl,--as-needed ./objs/main.o -o main.out
[root@ubuntu:makefile]#
[root@ubuntu:makefile]# mv test.h test.x
[root@ubuntu:makefile]# make
gcc -m32 -g -MMD -MP -Wall -c -o objs/main.o main.c
main.c:3:18: fatal error: test.h: 没有那个文件或目录
 #include "test.h"
                  ^
compilation terminated.
make: *** [objs/main.o] 错误 1
[root@ubuntu:makefile]#

因为目标test.h 没有对应的规则,所以make会继续向下进行,从而准确的定位出产生错误的原因。

最后给出一个相对完善的makefile,主要支持如下功能:
1、支持c/c++混合编译
2、支持交叉编译
3、支持源文件放在不同的目录
4、自动生成头文件依赖关系
5、支持生成预编译文件

CC = gcc
CX = g++
CP = cp
MV = mv
RM = -rm -rf
JB = ${shell cat /proc/cpuinfo | grep "processor" | wc -l}

vpath %.h   inc
vpath %.c   src
vpath %.cpp src

SRCS = xmain.c xsha256.c xuart.c xutils.c xlibusb.c test.cpp
LIBS = -lpthread -lusb
ODIR = obj
OBJS = $(addprefix $(ODIR)/, $(patsubst %.c, %.o, $(filter %.c, $(SRCS))) $(patsubst %.cpp, %.o, $(filter %.cpp, $(SRCS))))
DEPS = $(addprefix $(ODIR)/, $(patsubst %.c, %.d, $(filter %.c, $(SRCS))) $(patsubst %.cpp, %.d, $(filter %.cpp, $(SRCS))))
PRES = $(addprefix $(ODIR)/, $(patsubst %.c, %.i, $(filter %.c, $(SRCS))) $(patsubst %.cpp, %.i, $(filter %.cpp, $(SRCS))))

TARGET = $(ODIR)/a.out
INCDIR = -I./inc
CFLAGS = -g3 -Wall -c -gdwarf-2
LFLAGS = -L./lib -Wl,-rpath=${shell pwd}/lib

ifeq ($(HOST), mips)
    CC = mips-openwrt-linux-gcc
    CX = mips-openwrt-linux-g++
    ifeq (${shell file ./$(ODIR)/*.o | grep "MIPS"   | wc -l}, 0)
        ${shell rm -rf ./$(ODIR)}
    endif
else
    ifeq (${shell file ./$(ODIR)/*.o | grep "x86-64" | wc -l}, 0)
        ${shell rm -rf ./$(ODIR)}
    endif
endif

ifeq ($(filter %.cpp, $(SRCS)),)
   LD = $(CC)
else
   LD = $(CX)
endif

.PHONY: all clean $(ODIR)

all: $(ODIR) $(TARGET)

$(TARGET): $(OBJS) $(PRES)
	@echo LD $@
	@$(LD) $(LFLAGS) $(OBJS) $(LIBS) -o $@
	@echo CP $@ ./
	@$(CP) $@ ./

$(ODIR)/%.i: %.cpp
	@$(CX) $(CFLAGS)       -E $(INCDIR) -o $@ $<

$(ODIR)/%.o: %.cpp
	@echo CX $<
	@$(CX) $(CFLAGS) -MMD -MP $(INCDIR) -o $@ $<

$(ODIR)/%.i: %.c
	@$(CC) $(CFLAGS)       -E $(INCDIR) -o $@ $<

$(ODIR)/%.o: %.c
	@echo CC $<
	@$(CC) $(CFLAGS) -MMD -MP $(INCDIR) -o $@ $<

-include $(DEPS)

$(ODIR):
	@test -d $@ || mkdir -p $@

clean:
	@$(RM) $(ODIR) 
	@echo RM $(ODIR)

v2.0版本

CC = gcc
CX = g++
CP = cp
MV = mv
AR = ar
RM = -rm -rf
JB = ${shell cat /proc/cpuinfo | grep "processor" | wc -l}

LIBA = libx.a
LIBO = libx.so

DIRS = ./ ../
vpath %.c   $(DIRS)
vpath %.cpp $(DIRS)

SRCS = a.cpp b.cpp c.cpp d.cpp e.cpp 
ifneq ($(MAKECMDGOALS), $(LIBA))
  SRCS += main.cpp
else
  ifneq ($(MAKECMDGOALS), $(LIBO))
    SRCS += main.cpp
  endif
endif

LIBS = -lpthread
ODIR = obj
OBJS = $(addprefix $(ODIR)/, $(notdir $(patsubst %.c, %.o, $(filter %.c, $(SRCS))) $(patsubst %.cpp, %.o, $(filter %.cpp, $(SRCS)))))
DEPS = $(addprefix $(ODIR)/, $(notdir $(patsubst %.c, %.d, $(filter %.c, $(SRCS))) $(patsubst %.cpp, %.d, $(filter %.cpp, $(SRCS)))))
PRES = $(addprefix $(ODIR)/, $(notdir $(patsubst %.c, %.i, $(filter %.c, $(SRCS))) $(patsubst %.cpp, %.i, $(filter %.cpp, $(SRCS)))))

TARGET = $(ODIR)/test
INCDIR = $(addprefix -I, $(DIRS))
CFLAGS = -g3 -Wall -c -gdwarf-2 -fpic
XFLAGS = -std=c++11
LFLAGS = -L./lib -Wl,-rpath=${shell pwd}/lib -Wl,--as-needed

ifeq ($(host), arm)
    CC = arm-linux-gnueabihf-gcc
    CX = arm-linux-gnueabihf-g++
    AR = arm-linux-gnueabihf-ar
    ifeq (${shell file ./$(ODIR)/*.o | grep "ARM"   | wc -l}, 0)
        ${shell rm -rf ./$(ODIR)}
    endif
else
    ifeq (${shell file ./$(ODIR)/*.o | grep "x86-64" | wc -l}, 0)
        ${shell rm -rf ./$(ODIR)}
    endif
endif

ifeq ($(filter %.cpp, $(SRCS)),)
   LD = $(CC)
else
   LD = $(CX)
endif

.PHONY: all clean $(ODIR) 

all: $(ODIR) $(TARGET) $(LIBA) $(LIBO)

$(TARGET): $(ODIR) $(OBJS) $(PRES)
	@echo LD $@
	@$(LD) $(LFLAGS) $(OBJS) $(LIBS) -o $@
	@echo CP $@ ./
	@$(CP) $@ ./

$(LIBA): $(ODIR) $(OBJS)
	@echo AR $(ODIR)/$@
	@$(AR) -rcs $(ODIR)/$@ $(OBJS)
	
$(LIBO): $(ODIR) $(OBJS)
	@echo LD $(ODIR)/$@
	@$(LD) $(LFLAGS) $(OBJS) $(LIBS) -shared -o $(ODIR)/$@

$(ODIR)/%.i: %.cpp
	@$(CX) $(CFLAGS) $(XFLAGS)       -E $(INCDIR) -o $@ $<

$(ODIR)/%.o: %.cpp
	@echo CX $(notdir $<)
	@$(CX) $(CFLAGS) $(XFLAGS) -MMD -MP $(INCDIR) -o $@ $<

$(ODIR)/%.i: %.c
	@$(CC) $(CFLAGS)                 -E $(INCDIR) -o $@ $<

$(ODIR)/%.o: %.c
	@echo CC $(notdir $<)
	@$(CC) $(CFLAGS)           -MMD -MP $(INCDIR) -o $@ $<

-include $(DEPS)

$(ODIR):
	@test -d $@ || mkdir -p $@

clean:
	@$(RM) $(ODIR)
	@echo RM $(ODIR)


#SRCS = $(notdir $(foreach dir, $(DIRS), $(wildcard $(dir)*.cpp)))
#-Wl,-soname,$@
#-Wl,--whole-archive libx liby -Wl,--no-whole-archive
#-Wl,--start-group   libx liby -Wl,--end-group


 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

makefile 自动生成头文件依赖关系 的相关文章

  • 链接到遗留库:-lgfortranbegin from a premade makefile

    我在尝试编译由一些研究人员开发的程序时遇到了一些麻烦 该程序应该以非常精确的方式计算傅立叶变换和其他一些有用的操作科学论文在这里 https www researchgate net profile Gerard Gomez2 public
  • 如何在 Makefile 中将带引号的字符串转换为普通字符串?

    我不确定我是否正确描述了这个问题 但目前我正在通过以下方式解决这个问题 QUOTEDSTR hello world NORMALSTR shell echo QUOTEDSTR 是否有一种更内置的方法可以让 make 在不调用 shell
  • echo 命令,然后运行它? (如制作)

    有没有某种方法可以让 bash 进入一种详细模式 这样 当它运行 shell 脚本时 它会在运行之前回显将要运行的命令 也就是说 这样就可以看到运行的命令 以及它们的输出 类似于make 也就是说 如果运行像这样的 shell 脚本 ech
  • makefile patternrule 在目标文件名中带有更多通配符

    我需要创建一个特殊的 makefile 规则 最好通过一个示例来解释 也许我们用规则创建文件 test pdf tex pdflatex jobname test tex result pdf tex pdflatex jobname re
  • 如何在make后运行.o文件

    我一直在尝试运行一个 C 程序https github com rinon Simple Homomorphic Encryption https github com rinon Simple Homomorphic Encryption
  • 有没有比“手表制造”更明智的替代方案?

    我遇到了这个有用的提示 如果您经常处理文件并且希望它们自动构建 则可以运行 手表品牌 每隔几秒钟它就会重新运行一次 一切都会构建完成 然而 它似乎一直在吞噬所有的输出 我认为它可能更聪明 也许显示输出流 但抑制 全部 不做任何事情 这样如果
  • makefile 中的路径不起作用

    我正在运行以下命令makefile哪些需要改变dir到特定目标并在那里运行npm install 问题是我能够在输出中看到它将目录 项目 应用程序 打印到正确的目录 但安装 npm install 在上层 项目 上运行 为什么 例如 当我运
  • 如何在 GNU Make 模式规则中包含路径前缀

    考虑以下 foo bar echo lt gt 假设我们有一个文件1 bar 执行的命令很简单echo 1 bar gt 1 foo 然而 当 包含一个路径 而不仅仅是一个文件名 它开始变得挑剔 我的问题是我想在前面添加另一条路径 bar
  • make: *** 没有规则可以创建“all”所需的目标“gcc”。停止

    我正在通过一个eg pgm 来创建一个make 文件 http mrbook org tutorials make http mrbook org tutorials make 我的文件夹eg make creation包含以下文件 des
  • 如果覆盖率低于一定百分比,则单元测试失败

    我制作了一个执行的 makefilego test cover 是否有可能失败make unit tests如果覆盖范围低于 X 则命令 我该怎么做呢 您可以使用TestMain在你的测试中做到这一点 TestMain 可以充当测试的自定义
  • mingw32-make 的目录更改错误

    我正在MinGW32下构建POCO库1 6 0 环境 Windows 7 Ultimate 32位 shell MSYS 执行成功 配置 configure Configured for MinGW config make的内容 POCO
  • C 预处理器“/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp”未通过完整性检查

    在使用 Xcode 11 3 的 macOS Mojave 上 我有一个基于 Autotool 的第三方库 在终端中运行我的构建脚本时构建得很好 但在 Xcode 中运行时失败Run Script步骤为 BuildScript Showin
  • 对 sf:: 的未定义引用

    我想用 C 制作 GUI 应用程序 发现 SFML 是一个不错的选择 幸运的是 我使用的是 Linux 所以 SFML 2 4 已经安装在我的系统上 所以我开始搜索一些教程并找到了一个制作简单窗口的教程 但是当我运行代码时 出现错误 提示未
  • 使用 makefile 和静态模式规则进行树外构建

    我正在开发一些在 ARM 上运行的裸机嵌入式代码 因此必须处理整个 ARM 与 THUMB 模式的区别 当前的构建系统使用静态模式规则来确定是否以 ARM 或 THUMB 模式编译文件 ACOBJS o c echo CC c CFLAGS
  • Makefile 和通配符

    好吧 这是我当前的 makefile 设置 有一些文件名为public01 c public02 c等等 我正在尝试使用以下方法为每个人制作目标文件public o带有通配符的标签 public o public c hashtable h
  • 我怎样才能强制Make一直执行一个菜谱

    当前的 Makefile 有这样的内容 target1 lib1 a lib2 a target2 lib1 a lib3 a target3 lib3 a lib1 a MAKE C sub dir all 我想更改此 Makefile
  • 构建 makefile 依赖/继承树

    如果我解释得不好或者问了一些明显的问题 我很抱歉 但我是 Linux 内核的新手 而且有点深入 我们有一个嵌入式 Linux 系统 它附带一个 文档非常糟糕的 SDK 其中包含数百个文件夹stuff 大多数文件夹包含rules make m
  • 用于发布和调试目标的 Makefile

    我正在尝试构建一个 Makefile 它可以通过指定目标而不是变量 例如make debug 1 不太好 我这里有一个精简的简化示例 它模拟了我想要实现的目标 ifdef debug BINARY my binary debug MODUL
  • makefile 目标中可以有多个 % 符号吗?

    所以我有一个具有如下目标依赖项的 makefile all foreach lang LANGS foreach models MODELS targetName model xml lang targetName 目标如下所示 targe
  • GNU make 的回溯

    有没有办法让 GNU make 打印导致命令失败时执行的目标的 回溯 我经常处理严重混淆的 makefile 同时解决在新系统上构建软件的可移植性问题 这对于 make 来说似乎是一件非常简单的事情 这将极大地帮助调试 但我找不到任何方法来

随机推荐

  • 三种常见的文件共享服务--ftp,nfs,samba

    FTP File Transfer Protocol 文件传输协议 是一种应用层协议 可以实现很好的实现跨平台 但是无法实现一些其他的功能 像如文件系统挂载等功能 NFS Network File System 网路文件系统 是工作在内核模
  • codisQ&A

    Codis 是什么 Codis 是 Wandoujia Infrastructure Team 开发的一个分布式 Redis 服务 用户可以看成是一个无限内存的 Redis 服务 有动态扩 缩容的能力 对偏存储型的业务更实用 如果你需要 S
  • git中将某一分支代码完全覆盖另一分支

    如果需要将分支1的代码覆盖到分支2上 只需要如下操作 1 切换到分支2 git checkout 分支2 2 设置代码给远程的分支1 git reset hard origin 分支1 3 本地已覆盖 推送到远程分支上 git push f
  • 【Github】查看项目时可以清晰明了的看到项目的结构以及具体代码

    效果如下 Octotree通过左侧面板中的目录轻松浏览仓库的源代码 如下图 Octotree安装步骤 1 下载octotree 路径 https dl pconline com cn download 2561546 html 如果下载不成
  • 7-11 计算天数 (15 分)

    本题要求编写程序计算某年某月某日是该年中的第几天 输入格式 输入在一行中按照格式 yyyy mm dd 即 年 月 日 给出日期 注意 闰年的判别条件是该年年份能被4整除但不能被100整除 或者能被400整除 闰年的2月有29天 输出格式
  • 解决brew卡在Updating Homebrew...的正确姿势

    Updating的终端不要关 新开一个标签页 直接输入后续命令即可
  • Android 页面倒计时跳转 微博启动页为例

    首先创建项目 然后在右键再创一个empty avtivity xml布局中的图片自己去找然后复制进去 可复制进drawable中
  • 00 数组基础知识

    1 数组的存储方式 数组是存放在连续内存空间上的相同类型数据的集合 数组可以方便的通过下表索引的方式获取到下表下对应的数据 注意 数组的下标都是从0开始的 数组内存空间的地址是连续的 数组中存放的数据类型相同 正是因为数组的在内存空间的地址
  • 逆向爬虫07 requests进阶(反爬)

    逆向爬虫07 requests进阶 反爬 1 有些网站会在被访问时 检查客户端是否为浏览器 如果不是浏览器则拒绝访问 该问题可以通过在requests请求中 添加浏览器header参数 装成浏览器 import requests url h
  • BadImageFormatException,如果在安装32位oracle客户端组件的情况下以64位模式运行,将出现此问题

    今天开发人员发过来个问题 如题 现场是64位oracle 64位数据库主机 32 64位 具体不能确定 应用 64位应用中间件服务器 32位oracle客户端 这个问题按照字面来理解 就是安装了32位oracle客户端 但是试图以64位模式
  • Flask-SQLAlchemy插件

    Flask SQLALchemy插件 另外一个框架 叫Flask SQLAlchemy Flask SQLAlchemy是对SQLAlchemy进行了一个简单的封装 使得我们在flask中使用sqlalchemy更加的简单 可以通过 pip
  • 【RouterOS】利用ros搭建×××(PPTP)服务器要点

    关于拨号 与此对应的还有SiteToSite 的用途 我想不必多说 举几个例子 1 公司员工出差在外 需要收取公司内网的邮件 就需要 拨号进入公司内网收发邮件 2 网吧的技术人员在家休假时 需要远程维护网吧服务器 也需要 拨号进入网吧的网络
  • 随机森林原理及其用于分类问题的matlab实现

    随机森林 随机森林是多个决策树的集成学习 每个决策树用bagging的方法选数据集 并且在选择最佳属性划分的时候随机划分一些属性进行分类 比单个分类器效果更好 泛化能力更强 代码解释 1 用结构体的嵌套实现树的结构 2 makerandom
  • CSDN 不能复制或需关注才能查看代码

    解决csdn 不能复制问题 F12 不能复制代码 content views pre css user select text content views pre code css user select text 关注才能看代码 var
  • USB的传输,编码,数据格式,掌握usb的必备知识

    1 端点 位于USB设备或主机上的一个数据缓冲区 用来存放和发送USB的各种数据 每一个端点都有惟一的确定地址 有不同的传输特性 如输入端点 输出端点 配置端点 批量传输端点 2 帧 时间概念 在USB中 一帧就是1MS 它是一个独立的单元
  • d3dx9_43.dll如何修复

    你是否也和小编已经在运行一些应用程序或电脑游戏时会弹出d3dx9 43 dll文件丢失 小编在网上查询了此类文件丢失后的解决方案 并将其以图文的形式完成了整理 你只需要根据步骤完成操作即可解决这项问题 有一说一 莫名打不开电脑游戏是非常让人
  • Python语法检查——pyflakes

    Python 语法检查 pyflakes 安装 python m install pyflakes 使用 python m pyflakes xxx py
  • 终止代码 page_fault_in_nonpaged_area

    终止代码 page fault in nonpaged area 解决方法 电脑如果出现了 Page Fault In Nonpaged Area 错误 说明电脑的虚拟内存分页文件出现了问题 解决方法如下 第一步 用鼠标右键单击桌面上的 计
  • Spring Boot学习三:事务管理

    前面我们已经配置好了JPA 那么为了保证数据的一致性 我们就要用到事务控制 在springboot上使用事务其实很简单 就一个注解 Transactional 那么就来试试吧 首先写个方法 RequestMapping save Trans
  • makefile 自动生成头文件依赖关系

    在使用makefile 自动生成头文件依赖是 大家多半使用了下面这个方法 这个sed语句被称之为 上帝的符号 可读性不言而喻 PS CSDN这个排版怎么也搞不好 只能用图片了 gcc的 MMD 选项可以自动生成带有依赖规则的 d文件 为创建