Makefile、头文件依赖
假设我有一个 makefile,其规则
%.o: %.c
gcc -Wall -Iinclude ...
是我希望在头文件更改时重建 *.o。每当 /include
中的任何头文件发生更改时,都必须重新构建该目录中的所有对象,而不是制定依赖项列表。
我想不出一个很好的方法来改变规则来适应这一点,我愿意接受建议。如果标头列表不必进行硬编码,则有加分
Let's say I have a makefile with the rule
%.o: %.c
gcc -Wall -Iinclude ...
I want *.o to be rebuilt whenever a header file changes. Rather than work out a list of dependencies, whenever any header file in /include
changes, then all objects in the dir must be rebuilt.
I can't think of a nice way to change the rule to accomodate this, I'm open to suggestions. Bonus points if the list of headers doesn't have to be hard-coded
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
如果您使用 GNU 编译器,编译器可以为您组装依赖项列表。 Makefile 片段:
或者
其中
SRCS
是指向整个源文件列表的变量。还有
makedepend
这个工具,但我从来没有像gcc -MM
那样喜欢它If you are using a GNU compiler, the compiler can assemble a list of dependencies for you. Makefile fragment:
or
where
SRCS
is a variable pointing to your entire list of source files.There is also the tool
makedepend
, but I never liked it as much asgcc -MM
大多数答案都出奇地复杂或错误。然而,简单而强大的示例已在其他地方发布 [codereview]。诚然,gnu 预处理器提供的选项有点令人困惑。但是,使用
-MM
从构建目标中删除所有目录已记录在案,而不是错误 [gpp]:(较新的)
-MMD
选项可能就是您想要的。为了完整起见,这是一个支持多个 src 目录和构建目录的 makefile 示例,并带有一些注释。对于没有构建目录的简单版本,请参阅 [codereview]。此方法之所以有效,是因为如果单个目标有多个依赖关系行,则只需连接依赖关系,例如:
相当于:
如以下所述: 为单个目标创建多个依赖行?
Most answers are surprisingly complicated or erroneous. However simple and robust examples have been posted elsewhere [codereview]. Admittedly the options provided by the gnu preprocessor are a bit confusing. However, the removal of all directories from the build target with
-MM
is documented and not a bug [gpp]:The (somewhat newer)
-MMD
option is probably what you want. For completeness an example of a makefile that supports multiple src dirs and build dirs with some comments. For a simple version without build dirs see [codereview].This method works because if there are multiple dependency lines for a single target, the dependencies are simply joined, e.g.:
is equivalent to:
as mentioned at: Makefile multiple dependency lines for a single target?
正如我发布的此处 gcc 可以同时创建依赖项和编译:
“-MF”参数指定一个用于存储依赖项的文件。
“-include”开头的破折号告诉 Make 在 .d 出现时继续文件不存在(例如在第一次编译时)。
请注意,gcc 中似乎存在关于 -o 选项的错误。如果将对象文件名设置为 obj/_file__c.o,则生成的 file.d 仍将包含 file.o,而不是 obj/_file__c.o。
As I posted here gcc can create dependencies and compile at the same time:
The '-MF' parameter specifies a file to store the dependencies in.
The dash at the start of '-include' tells Make to continue when the .d file doesn't exist (e.g. on first compilation).
Note there seems to be a bug in gcc regarding the -o option. If you set the object filename to say obj/_file__c.o then the generated file.d will still contain file.o, not obj/_file__c.o.
怎么样:
您也可以直接使用通配符,但我倾向于发现我在不止一个地方需要它们。
请注意,这仅适用于小型项目,因为它假设每个目标文件都依赖于每个头文件。
How about something like:
You could also use the wildcards directly, but I tend to find I need them in more than one place.
Note that this only works well on small projects, since it assumes that every object file depends on every header file.
马丁的上述解决方案效果很好,但不能处理驻留在子目录中的 .o 文件。 Godric 指出 -MT 标志可以解决这个问题,但它同时会阻止 .o 文件被正确写入。下面将解决这两个问题:
Martin's solution above works great, but does not handle .o files that reside in subdirectories. Godric points out that the -MT flag takes care of that problem, but it simultaneously prevents the .o file from being written correctly. The following will take care of both of those problems:
这将很好地完成工作,甚至可以处理指定的子目录:
用 gcc 4.8.3 测试它
This will do the job just fine , and even handle subdirs being specified:
tested it with gcc 4.8.3
这是一个两行代码:
只要您在 OBJS 中有所有目标文件的列表,这适用于默认的 make 配方。
Here's a two-liner:
This works with the default make recipe, as long as you have a list of all your object files in
OBJS
.Sophie 的 answer 的稍微修改版本,允许将 *.d 文件输出到不同的文件夹(我只会粘贴生成依赖文件的有趣部分):
请注意,该参数
用于确保生成的 *.d 文件中的目标(即目标文件名)包含 *.o 文件的完整路径,而不仅仅是文件名。
我不知道为什么在将 -MMD 与 -c 结合使用时不需要此参数(如 Sophie 的 版本)。在这种组合中,它似乎将 *.o 文件的完整路径写入 *.d 文件中。如果没有此组合,-MMD 也仅将不带任何目录组件的纯文件名写入 *.d 文件。也许有人知道为什么 -MMD 与 -c 结合使用时会写入完整路径。我在 g++ 手册页中没有找到任何提示。
A slightly modified version of Sophie's answer which allows to output the *.d files to a different folder (I will only paste the interesting part that generates the dependency files):
Note that the parameter
is used to ensure that the targets (i.e. the object file names) in the generated *.d files contain the full path to the *.o files and not just the file name.
I don't know why this parameter is NOT needed when using -MMD in combination with -c (as in Sophie's version). In this combination it seems to write the full path of the *.o files into the *.d files. Without this combination, -MMD also writes only the pure file names without any directory components into the *.d files. Maybe somebody knows why -MMD writes the full path when combined with -c. I have not found any hint in the g++ man page.
我更喜欢这个解决方案,而不是迈克尔·威廉姆森接受的答案,它捕获对源+内联文件的更改,然后是源+标头,最后仅捕获源。这样做的优点是,如果只进行了一些更改,则不需要重新编译整个库。对于具有几个文件的项目来说这并不是一个重要的考虑因素,但如果您有 10 个或 100 个源,您就会注意到差异。
I prefer this solution, over the accepted answer by Michael Williamson, it catches changes to sources+inline files, then sources+headers, and finally sources only. Advantage here is that the whole library is not recompiled if only a a few changes are made. Not a huge consideration for a project with a couple of files, bur if you have 10 or a 100 sources, you will notice the difference.
以下对我有用:
The following works for me: