Gnu Makefile - 处理依赖关系
Unix 平台上的 C++ 程序员使用什么方法来创建和管理 Makefile?
我在我的项目中使用手工制作的 Makefile,但它们不处理头文件更改和其他依赖项。我在谷歌上搜索了一下,这里找到了一个很好的解决方案。
但我在 sed 命令中遇到了一个问题 -
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
问题出在第三个表达式“-e 's/ *\$$//”。 这不起作用。它应该删除结尾的反斜杠。我知道那里必须有双美元,因为这是 Makefile 的一部分。有人能告诉我这里出了什么问题吗?
这是完整的 Makefile -
CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread
OBJS=file1.o file2.o
TARGET=testProg
$(TARGET) : $(OBJS)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
%.o : %.cpp
$(CC) -MMD -c -o $@ $< $(CFLAGS)
@cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(OBJS:%.o=%.P)
clean :
rm -f $(TARGET) $(OBJS)
all : $(TARGET)
除了这个问题的解决方案之外,我还想要一些针对我的第一个问题的提示/指针。
What approach do C++ programmers on Unix platform use to create and manage Makefiles?
I was using hand made Makefiles for my projects but they don't handle header file changes and other dependencies. I googled around and found a good solution here.
But I ran into a problem here in the sed command -
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$//' \
-e '/^$/ d' -e 's/$/ :/' < $*.d >> $*.P; \
The problem is with the 3rd expression "-e 's/ *\$$//'.
It doesn't work. Its supposed to remove trailing backslashes. I understand that there has to be double dollar there since this is part of a Makefile. Can someone tell me what wrong here?
Here's the complete Makefile -
CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread
OBJS=file1.o file2.o
TARGET=testProg
$(TARGET) : $(OBJS)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
%.o : %.cpp
$(CC) -MMD -c -o $@ lt; $(CFLAGS)
@cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$//' \
-e '/^$/ d' -e 's/$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(OBJS:%.o=%.P)
clean :
rm -f $(TARGET) $(OBJS)
all : $(TARGET)
Apart from the solution to this problem, I would also like some tips/pointers to my 1st question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
gcc/g++ 可以使用
-M
系列选项为您生成依赖项。下面的工作原理是指定如何在给定源文件的情况下生成
.depends
文件。通过执行-include $(DEPS)
$(DEPS) 被识别为目标,并将在源文件更改时构建/重建。gcc/g++ can generate dependencies for you with the
-M
family of options.The following works by specifying how to generate
.depends
files given a source file. By doing-include $(DEPS)
$(DEPS) is recognized as a target and will be built/rebuilt when the source files change.编辑:
我已经尝试过你的 makefile,并且 sed 语句似乎可以很好地删除尾部反斜杠。尝试一些更简单的方法,如下所示:
编辑:
好吧,现在我迷上了。您能尝试这些实验并告诉我们结果吗?
EDIT:
I've tried your makefile, and that sed statement seems to remove trailing backslashes just fine. Try something simpler, like this:
EDIT:
All right, now I'm hooked. Could you try these experiments and tell us the results?
在 make 文件中,您在依赖项行上列出的任何内容都是依赖项头文件或包含的其他文件。
关于 make 的 BSD 教程注意:您可以使用 GCC 的 -MM 开关自动生成标头依赖信息。
In a make file anything you list on the dependency line is a dependency header files or other files included.
BSD tutorial on make Note: you can auto generate header dependency info with the -MM switch of GCC.
我一定是错过了什么。为什么生成依赖文件对您不起作用?
I must be missing something. Why doesn't generating dependency files work for you?
我更喜欢使用 CMake,尽管它并不是严格意义上的问题解决方案。
它是一种项目描述语言,可以为您生成 Makefile、Visual Studio 项目、Eclipse 项目、KDevelop 等。所有依赖项都已为您完成:
CMakeLists.txt
在 lib/CMakeLists.txt
这会从 file1.c file2.c 链接到 my_library 创建一个 my_exe。我发现这更简单。它还具有包发现之类的功能:
I prefer to use CMake, even though it's not strictly the solution to your problem.
It's a project description language that'll generate your Makefiles, Visual Studio Project, Eclipse Project, KDevelop, etc for you. All the dependencies are done for you:
CMakeLists.txt
In lib/CMakeLists.txt
This creates a my_exe from file1.c file2.c linked against my_library. I find this much simpler. It also has things like package discovery:
makedepend 实用程序安装在许多系统上,对于生成依赖性信息非常有用。
下面是一个示例 Makefile,它使用
include
指令(加上一点 Perl 魔法)来合并 makedepend 的输出:如果
foo.cc
和main.cc
依赖于foo.h
,则Makefile.depend
的内容为:最终结果是来自
makedepend
的依赖信息> 作为一系列规则注入到 Makefile 中。它类似于 使用.d
每个.cc
文件 都有一个文件,但将依赖信息保留在一个文件中,而不是分散在各处。The makedepend utility is installed on many systems and can be quite useful for generating dependency information.
Here is an example Makefile that uses the
include
directive (plus a little Perl magic) to incorporate the output from makedepend:If both
foo.cc
andmain.cc
depend onfoo.h
, then the contents ofMakefile.depend
would be:The end result is that the dependency information from
makedepend
is injected into the Makefile as a series of rules. It's similar to the approach of using a.d
file for each.cc
file, but keeps the dependency information in one file instead of scattered all over the place.在 Mozilla 的构建系统中,我们使用 GCC 的 -MD 开关来生成依赖文件:
http://mxr.mozilla.org/mozilla-central/source/配置.in#7134
然后我们使用一个名为 mddepend.pl 的脚本来检查已删除的头文件,这样
删除标头只会导致重建,而不是错误:
http://mxr.mozilla.org/mozilla-central/源/config/rules.mk#2066
http://mxr.mozilla.org/mozilla-central/ source/build/unix/mddepend.pl
该脚本生成一个包含所有依赖项的 .all.pp 文件,并为缺少的头文件添加额外的 foo.o: FORCE 依赖项。然后,我们只需将 .all.pp 文件包含在下面的 Rules.mk 中。
In Mozilla's build system, we use GCC's -MD switch to generate the dependency files:
http://mxr.mozilla.org/mozilla-central/source/configure.in#7134
and then we use a script called mddepend.pl to check for removed header files, such that
removing a header simply causes a rebuild, not an error:
http://mxr.mozilla.org/mozilla-central/source/config/rules.mk#2066
http://mxr.mozilla.org/mozilla-central/source/build/unix/mddepend.pl
That script generates an .all.pp file containing all the dependencies, with extra
foo.o: FORCE
dependencies stuck in for missing header files. We then simply -include the .all.pp file in rules.mk right below there.您可以使用 qmake 为项目生成 Makefile,即使该项目不是使用 Qt。
You can use qmake to generate Makefiles for a project even if that project is not using Qt.
我使用 BSD make(pmake?),它为我做了很多工作(我的语言是 C,但我认为这里没有区别)。这是我常见的“local.prog.mk”,我从不更改它:
注意“bsd.prog.mk”包含 - 这处理所有构建、依赖、清理目标。特定于项目的
BSDmakefile
很简单:每次插入/删除任何 #include 指令时我都会 make dependent。
I use BSD make (pmake?) which does lot of work for me (my lang is C, but I think no difference here). This is my common 'local.prog.mk', I never change it:
Note 'bsd.prog.mk' inclusion -- this handles all, build, depend, clean targets. Project-specific
BSDmakefile
s are simple:I just make depend every time I insert/remove any #include directives.
使用 gcc 的 -MT 选项代替 sed 脚本来修改生成的依赖关系规则的目标。 这篇博文提供了更多信息。
Instead of the sed scripts, use gcc's -MT option to modify the target of the generated dependency rules. This blog post has more info.
使用更现代版本的 GCC,您可以添加 -MP 标志以使 GCC 为标头本身生成空规则。
With a more modern version of GCC, you can add the -MP flag to have GCC generate empty rules for the headers itself.
我发现在构建依赖项文件时有用的最重要提示是将依赖项文件作为目标包含在生成的规则中:
因此,如果源或任何标头发生更改,
make
将重新生成依赖项。包含标头的虚假目标 (GCC-MP
) 应该允许在标头被删除时进行稳定的构建 - 缺少所需标头仍然是编译错误,而不是 make 依赖项错误。假设依赖文件生成到与目标文件相同的目录中,则以下内容应适用于 Unix 上的 GCC:
(来自内存)
I top tip that I have found useful when building dependency files is to include the dependency file as a target in the generated rule:
Thus
make
will regenerate the dependencies if the source or any of the headers change. Including phony targets for the headers (GCC-MP
) should then allow stable builds when headers are removed - the absense of required header remains a compilation error, not a make dependency error.Assuming that dependency files are generated into the same directory as the object files, the following should work for GCC on Unix:
(from memory)