开发者

How to make two different source directories in a Makefile output to one bin directory?

I have the following Makefile to build my erlang project:

.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

I'm trying to update this to also build my eunit tests in the test/eunit folder and have the output go to the same ebin folder as the src like this:

.SUFFIXES: .erl .beam .yrl

ERL_SRC := $(wildcard src/*.erl)
ERL_OBJ := $(patsubst src/%.erl,eb开发者_高级运维in/%.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

Making main works fine, but if I try make test it fails with:

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

The test module data_eunit.erl is located in test/eunit. The problem seems to be with the ebin/%.beam target. If I swap src/%.erl with test/eunit/%.erl then I can build the tests but not the src. How can I do a build from two source folders and have the output go to one output folder?


You can use the vpath/VPATH in your Makefile

.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


Perhaps you should greatly simplify your build. My erlang build systems just invoke erl -make with an Emakefile that looks like this:

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

You could, of course, have more than one src loc, but just mix the tests and the regular code -- you're already mixing them in ebin. Don't make it harder on yourself than it needs to be.


This wont really answer your question, but I dont like to have the risk of polluting my ebin/ with test-enabled code. So this is how I organize my toplevel Makefile:

all:
    (cd src && erl -make)

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

Then I put the following into src/Emakefile:

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

And into test/Emakefile I put

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

So if I run make all then src/*.erl is compiled into ebin/, but if I run make test I compile src/*.erl and test/*.erl into test/ and run all beam files there with unit tests.

When compiling the tests the TEST macro is enabled so that unit-tests are disabled if surrounded with ifdefs as the eunit guide suggest:

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

Its a setup that I'm quite pleased with.


You should make another target that compiles that tree into ebin, make it depend on the original build target.


This is doing what I want:

.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

Any other way I can improve this? Maybe move similar compile lines in ${ERL_OBJ} and ${EUNIT_OBJ} to a variable.


Instead of "ebin/%.beam: src/%.erl test/eunit/%.erl" have you tried just:

%.beam: %.erl

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜