我想从包含未使用目标的Makefile中提取所有*.cc
和*.h
文件名。这里是Makefile示例:https://gist.github.com/berceanu/7554a9c4371b807e425259c7e99b5de9
我试过运行make -Bnd
并查看修剪过的文件,但我不知道这是否遗漏了什么。make -Bnd | grep "Pruning file" | sort | uniq
预期结果:上述生成文件上*.h
使用的所有*.cc
和make run
文件的列表。
最佳答案
您试图从Makefile
中提取此信息的方法可能是错误的。make
不知道实际使用了哪些头文件。make
只知道您在依赖项中明确告诉了make
哪些头文件,这不是很可靠。Makefile
中的信息有两种可能是错误的。它可以包含未使用的目标(如您所注意到的)或未使用的头文件。它可能会丢失实际包含但未在Makefile
中提及的头文件。更糟糕的是,如果头文件的实际包含依赖于宏,比如#ifdef XYZ_FEATURE #include "additionalHeaderFile.h" #endif
,该怎么办。
至少有三种方法可以生成所需的列表,即编译过程中实际使用的.cc
和.h
文件列表:
(盲目信任Makefile
)make -n --print-data-base
(遵循构建的真实文件,但也有点难以解析)strace -f make
(依赖于GCC、clang、armcc和其他编译器中的一个特性来生成Makefile
,非常可靠)将CPPFLAGS:=-MMD
添加到Makefile
,运行make clean
,然后make
,然后使用cat *.d
获取用于生成.cc
的所有.h
和run
文件的列表。你甚至可以在不改变Makefile
:make clean; make CPPFLAGS:=-MMD && cat *.d | sed -e 's/\\//g' -e 's/:/ /g' -e 's/ \+/\n/g' | sort -u
的情况下做到这一点。
另外,您在要点中共享的Makefile
也有很多问题。
按照惯例,默认目标应命名为all
123.PHONY
目标。
带有对象文件列表的变量应命名为OBJS
或OBJECTS
,而不是OBJ
。这个名字有误导性,因为它是单数的。
而不是OBJ
使用rm
,这意味着$(RM)
,因此在文件不存在的情况下不会有麻烦。(作为副作用,-f
将变得更加便携,因为并非所有平台都使用Makefile
来删除文件。)rm
不是文件,因此应该是clean
目标。.PHONY
应该使用clean
而不是::
作为其配方,以便将来当:
更大并拆分为多个文件时,每个文件都可以有自己的Makefile
目标而不会出现问题。
非规则特定的变量应在定义时展开,而不是在引用时展开,因此应使用clean
而不是:=
来定义。
使用已定义的=
而不是C++
。
使用CXX
,而不是将选项放入C++
/CXX
,因为您正在链接。
应该有一个与二进制文件具有相同基名的源文件。然后可以使用内置规则进行链接。LDFLAGS
中的显式依赖关系是维护的一个难题。每次添加、删除或更改项目头文件的Makefile
语句时,#include
都必须更新,这很容易忘记,而且这是一种痛苦,尤其是当Makefile
语句位于头文件中时。即使尽职尽责,这也是一场看不见的合并冲突。您应该在#include
开头使用Makefile
,在CPPFLAGS+=-MMD
结尾附加Makefile
,并将-include $(wildcard *.d)
添加到要在Makefile
中删除的文件列表中,而不是在*.d
中具有显式依赖关系。然后可以从clean
中删除所有依赖关系规则(除了链接的规则)。
命名二进制Makefile
不是一个好主意。看到您的run
有一个Makefile
目标的用户会希望它运行实际的程序,而不是链接它。
最好把每一个对象单独放在一行。当多个开发人员同时更改对象列表时,这显著减少了项目中的合并冲突。
实际的run
应该是这样的,二进制文件从Makefile
重命名为run
:LDFLAGS:=-Wno-deprecated -lm
CPPFLAGS+=-MMD
BINARY:=program
OBJECTS:= \
$(BINARY).o \
binomh.o \
# More objects here
.PHONY: all
all: $(BINARY)
$(BINARY): $(OBJECTS)
.PHONY: clean
clean::
$(RM) \
$(BINARY) \
*.[adios] \
-include $(wildcard *.d)
这个program
将做与您的Makefile
相同的事情,但它几乎是免维护的。不需要更新依赖项,因为它们是从C预处理器生成的依赖项文件中自动获取的。Makefile
还将删除在您将*.[adios]
添加到任何-save-temps
、CFLAGS
或CXXFLAGS
时创建的文件。
众所周知,这种类型的CPPFLAGS
适用于GCC、clang、AOCC(AMD optimizec Compiler)和armcc。它可能也适用于其他一些编译器和预处理器,特别是当它们基于GCC或clang/LLVM或试图与GCC或clang/LLVM兼容时。
顺便说一句,如果你有兴趣知道这对你有用的话,除了经验之外,还有很高的信心:我已经把你的Makefile
添加到它上面,以便复制你的源代码结构。头文件将只是空文件。C++源文件将是从Makefile
中的依赖项获取的#include
语句列表。%.cc:
grep '^$*\.o.*:' $(MAKEFILE_LIST) | sed -e 's/.*://' -e 's/.*$*\.cc//' -e 's/ \([^ ]\+\)/#include "\1"\n/g' >$@
%.h:
touch $@
关于c++ - 通过解析Makefile检索使用的头文件和源文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54029987/