在单独的目录中单独构建

时间:2011-09-03 02:24:37

标签: makefile

我确信这是完全正常的事情,但我无法弄清楚如何做到这一点。

我有一个编译器,它生成通常形式的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构建/测试/%。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 / A.o M / B.o&gt; main',这似乎与gnu make文档相反,说明$ ^应该包括包含发现依赖关系的VPATH目录。奇怪的是,如果我删除'main'并再次制作,这次它使用正确的路径。这是GNU make,3.81。

这里发生了什么?是否有更好的方法来构建不同的标志? VPATH似乎是一个笨拙的工具,肯定有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

Make工作正常。它首次尝试cat M/A.o M/B.o >main,因为它无法找到所需的先决条件,但它知道M/A.o' and M / Bo (<em>not</em> build / M / Ao'和{{1}的规则并且期望这就是规则将产生的。如果您删除build/M/B.o并重试,则会通过VPATH找到main build / M / B.o`。

让我们分阶段修改这个makefile。首先我们更改VPATH,以便它可以找到build/M/A.o' and个文件(Make擅长使用那里来构建这里,而不是反之亦然,并且这就是VPATH的优点,并稍微改变规则:

.hs

现在是不同的对象目录。

build/%.o: %.hs
    cp $< $@

VPATH = M

main: build/A.o build/B.o
    cat $^ > $@

然后我们简化了最后两条规则,这样就可以轻松添加更多目标文件和二进制目标:

build/test/%.o build/project/%.o: %.hs
    cp $< $@

VPATH = M

test: build/test/A.o build/test/B.o
    cat $^ > $@

project: build/project/A.o build/project/B.o
    cat $^ > $@

现在针对不同的编译器标志:

OBJECTS = A.o B.o

test: $(addprefix build/test/,$(OBJECTS))
project: $(addprefix build/project/,$(OBJECTS))

test project:
    cat $^ > $@

最后是依赖关系。这有点棘手。假设您希望依赖项build/test/%.o: FLAGS += test_flags build/project/%.o: FLAGS += proj_flags build/test/%.o build/project/%.o: %.hs @echo building $@ from $^ using flags $(FLAGS) cp $< $@ 应用于您拥有的许多对象。这是一种方法:

B.o : A.hs

要生成这样的行,我将原始行(例如OBJECT_PATHS = build/test/ build/project/ # The following is from the included file generated by the compiler $(addsuffix B.o,$(OBJECT_PATHS)) : A.hs )通过B.o: A.hs进行管道处理,并注意如果要将其放入makefile命令中,请不要忘记将sed 's/\(.*\):\(.*\)/\1:\2/'符号加倍,以便为shell保留它们。

我知道要吸收很多东西。一步一步,让我们知道它是如何工作的。

答案 1 :(得分:0)

如果您现在还没有解决问题或遇到进一步的问题,最好给autotools(automake和autoconf)一个机会。他们将快速构建一个Makefile,支持更多可配置和灵活的树外构建。