在不同的目录中单独构建
我确信这是一件完全正常的事情,但我不知道如何让 make 做到这一点。
我有一个编译器,可以生成通常形式的 make 依赖项:
M/A.o : M/A.hs
M/B.o : M/A.o
因此,我编写了一条规则将 %.hs 编译为 %.o,添加一条规则来链接二进制文件,包含依赖项文件,一切都很好。但我想要几个带有不同标志的二进制目标。例如,我想使用 -DTESTING 构建构建/测试,并使用 -prof 构建构建/配置文件。因此,我需要将 .o 文件保存在一个单独的树中,在那里它们将使用特殊标志进行编译。
我能想到的最直接的方法是拥有看起来像这样的依赖项:
build/test/M/A.o : M/A.hs
build/test/M/B.o : build/test/M/A.o
build/profile/M/A.o : M/A.hs
... etc.
然后规则,以便 %.hs 到 build/test/%.o 使用 -DTESTING 进行编译,等等。我认为这可行,但很笨拙,意味着预处理 deps 文件以添加所有构建/任何/前缀内容,并将其大小乘以任意多种构建。
VPATH 似乎是为这类事情而设计的,我的想法是我可以根据目标设置 VPATH 和编译器标志,它几乎可以工作,但是:
%.o: %.hs
@mkdir -p build/M
cp $< build/$@
VPATH = build
main: M/A.o M/B.o
cat $^ >$@
M/A.o : M/A.hs
M/B.o : M/B.hs
主目标第一次想要运行 'cat M/Ao M /Bo >main' 这似乎与 gnu make 文档相反,gnu make 文档说 $^ 应该包含包含在其中找到依赖项的 VPATH 目录。奇怪的是,如果我删除“main”并再次 make,这次它使用正确的路径。这是 GNU make,3.81。
这是怎么回事?有没有更好的方法来使用不同的标志进行构建? VPATH 似乎是一个笨拙的工具,肯定有更好的方法吗?
I'm sure this is a totally normal thing to do, but I can't figure out how to get make to do this.
I have a compiler that generates make dependencies of the usual form:
M/A.o : M/A.hs
M/B.o : M/A.o
So I write a rule to compile %.hs into %.o, add a rule to link the binary, include the dependencies file, and all is well. But I want to have several binary targets with different flags. E.g. I want build/test built with -DTESTING and build/profile built with -prof. So I need to keep the .o files in a separate tree, where they will be compiled with special flags.
The straightforward way I can think of would be to have dependencies that look something like this:
build/test/M/A.o : M/A.hs
build/test/M/B.o : build/test/M/A.o
build/profile/M/A.o : M/A.hs
... etc.
And then rules so that %.hs to build/test/%.o compiles with -DTESTING, etc. I think this would work, but it's clumsy, means preprocessing the deps file to add all that build/whatever/ prefix stuff, and would multiply its size by however many kinds of builds.
VPATH appears to be designed for this sort of thing and my idea was that I could set the VPATH and compiler flags depending on the target, and it almost works, but:
%.o: %.hs
@mkdir -p build/M
cp lt; build/$@
VPATH = build
main: M/A.o M/B.o
cat $^ >$@
M/A.o : M/A.hs
M/B.o : M/B.hs
The first time the main target wants to run 'cat M/A.o M/B.o >main' which seems contrary to the gnu make documentation that says $^ should include the include the VPATH directory in which the dependency was found. Curiously, if I remove 'main' and make again, this time it uses the correct path. This is GNU make, 3.81.
What's going on here? Is there a better way to build with different flags? VPATH seems like a clumsy tool, surely there is a better way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使工作正常。它第一次尝试
cat M/Ao M/Bo >main
因为它找不到所需的先决条件,但它知道M/Ao' 和
的规则>M/Bo(不是
build/M/Ao' 和build/M/Bo
) 并期望这就是规则的内容生产。如果您删除main
并重试,它将通过 VPATH 找到build/M/Ao' 和
build/M/Bo`。让我们分阶段修改这个makefile。首先我们更改 VPATH,以便它可以找到
.hs
文件(Make 擅长使用那里的东西来构建这里的东西,而不是虎钳-反之亦然,这就是 VPATH 的优点),并稍微更改规则:现在针对不同的对象目录。
然后我们简化最后两条规则,以便轻松添加更多目标文件和二进制目标:
现在介绍不同的编译器标志:
最后是依赖项。这有点棘手。假设您希望将依赖项
Bo : A.hs
应用于您拥有的任意多个对象。这是一种方法:要生成这样的行,我将通过
sed 's/\(.*\):\( 通过管道传输原始行(例如
,请注意,如果您想将其放入 makefile 命令中,请不要忘记将Bo: A.hs
) .*\)/\1:\2/'$
符号加倍以保留它们对于外壳。我知道需要吸收很多东西。一次一步地进行,让我们知道结果如何。
Make is working correctly. It tries
cat M/A.o M/B.o >main
the first time because it can't find the prerequisites it needs, but it knows a rule forM/A.o' and
M/B.o(<em>not</em>
build/M/A.o' andbuild/M/B.o
) and expects that that is what the rule will produce. If you removemain
and try again, it will findbuild/M/A.o' and
build/M/B.o` via VPATH.Let's modify this makefile in stages. First we change the VPATH so that it can find the
.hs
files (Make is good at using things there to build things here, not vise-versa, and that's what VPATH is good for), and change the rules slightly:Now for the different object directories.
Then we simplify those last two rules, so that it's easy to add more object files and binary targets:
Now for the different compiler flags:
Finally the dependencies. This is a little tricky. Suppose you want the dependency
B.o : A.hs
to apply to however many object you have. This is one approach:To generate lines like that, I'd pipe the raw lines (e.g.
B.o: A.hs
) throughsed 's/\(.*\):\(.*\)/\1:\2/'
, and note that if you want to put this in a makefile command, don't forget to double the$
signs to preserve them for the shell.I know that's a lot to absorb. Take it one step at a time and let us know how it works out.
如果您现在还没有解决问题或者遇到更多问题,最好给自动工具(automake 和 autoconf)一个机会。他们将快速为您构建一个 Makefile,支持更可配置和灵活的树外构建。
If you haven't solved your problem by now or are experiencing further problems, best give the autotools (automake and autoconf) a chance. They'll quickly build you a Makefile that supports more configurable and flexible out-of-tree builds.