代码之家  ›  专栏  ›  技术社区  ›  Jeremy Raymond

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

  •  2
  • Jeremy Raymond  · 技术社区  · 15 年前

    .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.
    

    测试模块数据_eunit.erl位于测试/eunit中。问题似乎出在ebin/%.beam目标上。如果我将src/%.erl与test/eunit/%.erl交换,那么我可以构建测试,但不能构建src。如何从两个源文件夹进行生成,并将输出转到一个输出文件夹?

    6 回复  |  直到 15 年前
        1
  •  6
  •   dergeffi    15 年前

    您可以在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
    
        2
  •  4
  •   Dustin    15 年前

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

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

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

        3
  •  2
  •   Christian    15 年前

    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

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

    这是一个我很满意的设置。

        4
  •  0
  •   user177800 user177800    15 年前

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

        5
  •  0
  •   Jeremy Raymond    15 年前

    这就是我想要的:

    .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}中类似的编译行移动到一个变量。

        6
  •  0
  •   gdamjan    15 年前

    与“ebin/%.beam:src/%.erl test/eunit/%.erl”不同,您是否尝试过:

    %.beam:%.erl