【问题标题】:How to make two different source directories in a Makefile output to one bin directory?如何将 Makefile 输出中的两个不同源目录生成到一个 bin 目录?
【发布时间】:2010-12-26 01:07:39
【问题描述】:

我有以下 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

使 main 工作正常,但如果我尝试 make test 它会失败:

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

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

【问题讨论】:

  • 我绝对是使用 make/Makefiles 的新手。我尝试研究解决方案,但正在努力寻找解决方案。

标签: erlang makefile


【解决方案1】:

您可以在 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】:

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

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

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

【讨论】:

  • 我不介意编译输出在同一个 ebin 目录下,但更喜欢应用程序和测试源代码分开。
  • 现在 rebar (github.com/basho/rebar) 是 Erlang 应用程序的最佳选择。
【解决方案3】:

这并不能真正回答您的问题,但我不希望冒使用启用测试的代码污染我的 ebin/ 的风险。所以这就是我组织顶层 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 宏被启用,这样如果单元测试被 ifdefs 包围,就像 eunit 指南所建议的那样:

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

这是我非常满意的设置。

【讨论】:

  • 我正在寻找类似的东西,但更喜欢所有的梁文件都以 ebin 结尾 - 不要将梁文件与 erl 文件混合在一起。
  • 这很简单。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    这是在做我想做的事:

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

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

      %.beam: %.erl

      【讨论】:

      • 这不起作用,因为我的 Makefile 与源或输出不在同一目录中。我有 ./Makefile ./src ./test/eunit
      猜你喜欢
      • 1970-01-01
      • 2021-05-10
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 2013-11-02
      • 2010-09-18
      • 1970-01-01
      • 2018-08-29
      相关资源
      最近更新 更多