From b2b648037037199fa0b69318a83f6e44fd510c57 Mon Sep 17 00:00:00 2001 From: Christopher Meiklejohn Date: Mon, 4 Nov 2013 12:32:01 -0800 Subject: [PATCH 1/3] Add Core Erlang support. Support the compilation of .core files in the directory for applications which use source code authored directly in Core Erlang. --- src/rebar_erlc_compiler.erl | 52 +++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index 6f7e3a3f..bb7e5c01 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -129,9 +129,11 @@ doterl_compile(Config, OutDir, MoreSources) -> %% contain erlang source. This might be used, for example, should %% eunit tests be separated from the core application source. SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)), - RestErls = [Source || Source <- gather_src(SrcDirs, []) ++ MoreSources, + RestErls = [Source || Source <- gather_src(SrcDirs, [], erl) ++ MoreSources, not lists:member(Source, FirstErls)], + Cores = [Source || Source <- gather_src(SrcDirs, [], core) ++ MoreSources], + %% Split RestErls so that parse_transforms and behaviours are instead added %% to erl_first_files, parse transforms first. %% This should probably be somewhat combined with inspect_epp @@ -159,6 +161,10 @@ doterl_compile(Config, OutDir, MoreSources) -> fun(S, C) -> internal_erl_compile(S, C, OutDir, ErlOpts) end), + rebar_base_compiler:run(Config, [], Cores, + fun(S, C) -> + internal_core_compile(S, C, OutDir, ErlOpts) + end), true = code:set_path(CurrPath), ok. @@ -177,7 +183,8 @@ include_path(Source, Config) -> -spec inspect(Source::file:filename(), IncludePath::[file:filename(), ...]) -> {string(), [string()]}. inspect(Source, IncludePath) -> - ModuleDefault = filename:basename(Source, ".erl"), + Extension = filename:extension(Source), + ModuleDefault = filename:basename(Source, Extension), case epp:open(Source, IncludePath) of {ok, Epp} -> inspect_epp(Epp, Source, ModuleDefault, []); @@ -229,6 +236,37 @@ needs_compile(Source, Target, Hrls) -> lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end, [Source] ++ Hrls). +-spec internal_core_compile(Source::file:filename(), + Config::rebar_config:config(), + Outdir::file:filename(), + ErlOpts::list()) -> 'ok' | 'skipped'. +internal_core_compile(Source, Config, Outdir, ErlOpts) -> + %% Determine the target name and includes list by inspecting the source file + {Module, Hrls} = inspect(Source, include_path(Source, Config)), + + %% Construct the target filename + Target = filename:join([Outdir | string:tokens(Module, ".")]) ++ ".beam", + ok = filelib:ensure_dir(Target), + + %% If the file needs compilation, based on last mod date of includes or + %% the target + case needs_compile(Source, Target, Hrls) of + true -> + Opts = [from_core, {outdir, filename:dirname(Target)}] ++ + ErlOpts ++ [{i, "include"}, return], + case compile:file(Source, Opts) of + {ok, _Mod} -> + ok; + {ok, _Mod, Ws} -> + rebar_base_compiler:ok_tuple(Source, Ws); + {error, Es, Ws} -> + rebar_base_compiler:error_tuple(Source, Es, Ws, Opts) + end; + false -> + skipped + end. + + -spec internal_erl_compile(Source::file:filename(), Config::rebar_config:config(), Outdir::file:filename(), @@ -306,10 +344,14 @@ compile_xrl_yrl(Source, Target, Opts, Mod) -> skipped end. -gather_src([], Srcs) -> +gather_src([], Srcs, _Type) -> Srcs; -gather_src([Dir|Rest], Srcs) -> - gather_src(Rest, Srcs ++ rebar_utils:find_files(Dir, ".*\\.erl\$")). +gather_src([Dir|Rest], Srcs, erl) -> + Erls = rebar_utils:find_files(Dir, ".*\\.erl\$"), + gather_src(Rest, Srcs ++ Erls, erl); +gather_src([Dir|Rest], Srcs, core) -> + Cores = rebar_utils:find_files(Dir, ".*\\.core\$"), + gather_src(Rest, Srcs ++ Cores, core). -spec dirs(Dir::file:filename()) -> [file:filename()]. From d118a19c5b0a00d8d636b7f91b7c4a2eea53de1f Mon Sep 17 00:00:00 2001 From: Christopher Meiklejohn Date: Mon, 4 Nov 2013 22:30:32 -0500 Subject: [PATCH 2/3] Don't subdirectory beams. In the case of a beam called Coq.Arith.EqNat, which will be called directly in the Core Erlang like call 'Coq.Arith.EqNat':'beq_nat', don't put into a subdirectory or the emulator will not be able to find it. --- src/rebar_erlc_compiler.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index bb7e5c01..ef3e7fc3 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -245,7 +245,7 @@ internal_core_compile(Source, Config, Outdir, ErlOpts) -> {Module, Hrls} = inspect(Source, include_path(Source, Config)), %% Construct the target filename - Target = filename:join([Outdir | string:tokens(Module, ".")]) ++ ".beam", + Target = filename:join([Outdir,Module]) ++ ".beam", ok = filelib:ensure_dir(Target), %% If the file needs compilation, based on last mod date of includes or From d9cbd78e72f3473185666db4a9b71111dbfb3c4e Mon Sep 17 00:00:00 2001 From: Christopher Meiklejohn Date: Fri, 8 Nov 2013 12:32:53 -0500 Subject: [PATCH 3/3] Add Core Erlang test. --- test/rebar_eunit_tests.erl | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/test/rebar_eunit_tests.erl b/test/rebar_eunit_tests.erl index 72fb3ea7..b0014c53 100644 --- a/test/rebar_eunit_tests.erl +++ b/test/rebar_eunit_tests.erl @@ -46,17 +46,18 @@ eunit_test_() -> {"Ensure EUnit runs with tests in a 'test' dir and no defined suite", - setup, fun() -> setup_basic_project(), rebar("-v eunit") end, + setup, fun() -> setup_core_project(), rebar("-v eunit") end, fun teardown/1, fun(RebarOut) -> [{"Tests in 'test' directory are found and run", ?_assert(string:str(RebarOut, "myapp_mymod_tests:") =/= 0)}, + {"", fun() -> ?assertEqual(RebarOut, false) end}, {"Tests in 'src' directory are found and run", ?_assert(string:str(RebarOut, "myapp_mymod:") =/= 0)}, {"Tests are only run once", - ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}] + ?_assert(string:str(RebarOut, "All 3 tests passed") =/= 0)}] end}. cover_test_() -> @@ -141,10 +142,27 @@ basic_setup_test_() -> ["test/myapp_mymod_tests.erl", "src/myapp_mymod.erl"])}. +basic_core_test_() -> + {"Create a core project with a 'test' directory, a test, and a module", + setup, fun setup_core_project/0, fun teardown/1, + + %% Test the setup function + assert_dirs_in("Core Project", + ["src", "ebin", "test"]) ++ + assert_files_in("Core Project", + ["src/myapp_mycoremod.core"])}. + %% ==================================================================== %% Setup and Teardown %% ==================================================================== +-define(myapp_mycoremod, + ["module 'myapp_mycoremod' [ 'myfunc'/0 ] attributes [ ]\n", + "\n", + "'myfunc'/0 = fun() ->\n", + " []\n", + "end"]). + -define(myapp_mymod, ["-module(myapp_mymod).\n", "-export([myfunc/0]).\n", @@ -156,7 +174,8 @@ basic_setup_test_() -> ["-module(myapp_mymod_tests).\n", "-compile([export_all]).\n", "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n"]). + "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n", + "myfunc_core_test() -> ?assertMatch([], myapp_mycoremod:myfunc()).\n"]). -define(mysuite, ["-module(mysuite).\n", @@ -186,6 +205,10 @@ setup_basic_project() -> ok = file:write_file("test/myapp_mymod_tests.erl", ?myapp_mymod_tests), ok = file:write_file("src/myapp_mymod.erl", ?myapp_mymod). +setup_core_project() -> + setup_basic_project(), + ok = file:write_file("src/myapp_mycoremod.core", ?myapp_mycoremod). + setup_cover_project() -> setup_basic_project(), ok = file:write_file("rebar.config", "{cover_enabled, true}.\n").