如何在Makefile输出中将两个不同的源目录放到一个bin目录中?

时间:2009-12-12 18:54:32

标签: erlang makefile

我有以下Makefile来构建我的erlang项目:

.SUFFIXES: .erl .beam .yrl

ERL_SRC := $(wildcard src/*.erl)
ERL_OBJ := $(patsubst src/%.erl,ebin/%.beam,${ERL_SRC})

all: main

main: ${ERL_OBJ}

ebin/%.beam: src/%.erl
        erlc +debug_info -W -o ebin $<

clean:
        rm -fr ebin/*.beam

我正在尝试更新它以在test / eunit文件夹中构建我的eunit测试,并让输出转到与src相同的ebin文件夹,如下所示:

.SUFFIXES: .erl .beam .yrl

ERL_SRC := $(wildcard src/*.erl)
ERL_OBJ := $(patsubst src/%.erl,ebin/%.beam,${ERL_SRC})
EUNIT_SRC := $(wildcard test/eunit/*.erl)
EUNIT_OBJ := $(patsubst test/eunit/%.erl,ebin/%.beam,${EUNIT_SRC})

all: main

main: ${ERL_OBJ}

ebin/%.beam: src/%.erl test/eunit/%.erl
        erlc +debug_info -W -o ebin $<

clean:
        rm -fr ebin/*.beam

eunit: ${EUNIT_OBJ}

test: main eunit

使主要工作正常,但如果我尝试进行测试,它会失败:

make: *** No rule to make target `ebin/data_eunit.beam', needed by `eunit'.  Stop.

测试模块data_eunit.erl位于test / eunit中。问题似乎与ebin /%。beam target有关。如果我将src /%。erl与test / eunit /%。erl交换,那么我可以构建测试而不是src。如何从两个源文件夹进行构建并将输出转到一个输出文件夹?

6 个答案:

答案 0 :(得分:5)

您可以在Makefile中使用vpath / VPATH

.SUFFIXES: .erl .beam .yrl

# use vpath to tell make where to search for %.erl files
vpath %.erl src eunit
# or use VPATH to tell make where to search for any prerequisite
# VPATH=src:eunit    

ERL_OBJ = $(patsubst src/%.erl,ebin/%.beam, $(wildcard src/*erl))
ERL_OBJ += $(patsubst eunit/%.erl,ebin/%.beam, $(wildcard eunit/*erl))

all: main

main: ${ERL_OBJ}

ebin/%.beam: %.erl
    erlc +debug_info -W -o ebin $<

clean:
    rm -fr ebin/*.beam

答案 1 :(得分:4)

也许你应该大大简化你的构建。我的erlang构建系统只是使用如下所示的Emakefile调用erl -make

{"src/*", [debug_info, {outdir, "ebin"}, {i, "include"}]}.

当然,您可以拥有多个src loc,但只需混合测试和常规代码 - 您已经将它们混合在ebin中。不要让自己变得比它需要的更难。

答案 2 :(得分:2)

这不会真正回答你的问题,但我不喜欢冒着使用支持测试的代码污染我的ebin /的风险。所以这就是我组织我的toplevel Makefile的方式:

all:
    (cd src && erl -make)

test:
    (cd test && erl -make && \
       erl -noinput -eval 'eunit:test({dir, "."}, [verbose]), init:stop()')

然后我将以下内容放入src/Emakefile

{['*'],
 [{outdir,"../ebin"}]}.

进入test/Emakefile我放

{['../src/*'], 
 [debug_info, {d, 'TEST'}]}.
{['*'],
 [debug_info, {d, 'TEST'}]}.

所以如果我运行make all然后src / * .erl被编译成ebin /,但是如果我运行make test我将src / *。erl和test / * .erl编译成test /和使用单元测试运行所有梁文件。

在编译测试时,启用了TEST宏,以便在使用ifdef作为eunit指南建议时禁用单元测试:

-ifdef(TEST).
test_code_() -> ...
-endif.

这是我非常满意的设置。

答案 3 :(得分:0)

你应该创建另一个目标,将该树编译成ebin,使其依赖于原始构建目标。

答案 4 :(得分:0)

这就是我想要的:

.SUFFIXES: .erl .beam .yrl

ERL_SRC := $(wildcard src/*.erl)
ERL_OBJ := $(patsubst src/%.erl,ebin/%.beam,${ERL_SRC})
EUNIT_SRC := $(wildcard test/eunit/*.erl)
EUNIT_OBJ := $(patsubst test/eunit/%.erl,ebin/%.beam,${EUNIT_SRC})

all: main

main: ${ERL_OBJ}

${ERL_OBJ}: ${ERL_SRC}
        erlc +debug_info -W -o ebin $<

clean:
        rm -fr ebin/*.beam

${EUNIT_OBJ}: ${EUNIT_SRC}
        erlc +debug_info -W -o ebin $<

eunit: ${EUNIT_OBJ}

test: main eunit

我可以通过其他方式改进这个吗?也许将$ {ERL_OBJ}和$ {EUNIT_OBJ}中的类似编译行移动到变量。

答案 5 :(得分:0)

而不是“ebin /%。beam:src /%。erl test / eunit /%。erl”你试过了:

%。beam:%。erl