You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.8 KiB

  1. %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 ft=erlang et
  3. -module(erlc_rt).
  4. -export([files/0,
  5. run/1]).
  6. -include_lib("eunit/include/eunit.hrl").
  7. -define(MODULES,
  8. [first_xrl,
  9. first_yrl,
  10. first_erl,
  11. foo,
  12. foo_app,
  13. foo_sup,
  14. foo_test_worker,
  15. foo_worker,
  16. 'SIMPLE-ASN']).
  17. -define(BEAM_FILES,
  18. ["first_xrl.beam",
  19. "first_yrl.beam",
  20. "first_erl.beam",
  21. "foo.beam",
  22. "foo_app.beam",
  23. "foo_sup.beam",
  24. "foo_test_worker.beam",
  25. "foo_worker.beam",
  26. "SIMPLE-ASN.beam"]).
  27. files() ->
  28. [
  29. {copy, "../../rebar", "rebar"},
  30. {copy, "rebar.config", "rebar.config"},
  31. {copy, "rebar-no_debug_info.config", "rebar-no_debug_info.config"},
  32. {copy, "include", "include"},
  33. {copy, "extra-include", "extra-include"},
  34. {copy, "src", "src"},
  35. {copy, "extra-src", "extra-src"},
  36. {copy, "mibs", "mibs"},
  37. {copy, "asn1", "asn1"},
  38. {create, "ebin/foo.app", app(foo, ?MODULES)},
  39. %% deps
  40. {create, "deps/foobar/ebin/foobar.app", app(foobar, [foobar])},
  41. {copy, "foobar.erl", "deps/foobar/src/foobar.erl"}
  42. ].
  43. run(_Dir) ->
  44. ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
  45. ok = check_beams(true),
  46. ok = check_debug_info(true),
  47. MibResult = filename:join(["priv", "mibs", "SIMPLE-MIB.bin"]),
  48. ?assertMatch(true, filelib:is_regular(MibResult)),
  49. ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])),
  50. ok = check_beams(false),
  51. ?assertMatch(false, filelib:is_regular(MibResult)),
  52. ?assertMatch(
  53. {ok, _},
  54. retest_sh:run("./rebar -C rebar-no_debug_info.config compile", [])),
  55. ok = check_beams(true),
  56. ok = check_debug_info(false),
  57. ?assertMatch(true, filelib:is_regular(MibResult)),
  58. %% Regression test for https://github.com/rebar/rebar/issues/249
  59. %%
  60. %% Root cause: We didn't have per-project .rebar/erlcinfo but just one in
  61. %% <base_dir>/.rebar/erlcinfo.
  62. %%
  63. %% Solution: Ensure every project has its own .rebar/erlcinfo
  64. %%
  65. %% For the bug to happen, the following conditions must be met:
  66. %%
  67. %% 1. <base_dir>/rebar.config has erl_first_files
  68. %% 2. one of the 'first' files depends on another file (in this
  69. %% case via -include_lib())
  70. %% 3. a sub project's rebar.config, if any, has no erl_first_files entry
  71. %%
  72. %% Now because erl_first_files is retrieved via rebar_config:get_list/3,
  73. %% base_dir/rebar.config's erl_first_files is inherited, and because we had
  74. %% a shared <base_dir>/.rebar/erlcinfo instead of one per project, the
  75. %% cached entry was reused. Next, while compiling the sub project
  76. %% rebar_erlc_compiler:needs_compile/3 gets a last modification time of
  77. %% zero for the 'first' file which does not exist inside the sub project.
  78. %% This, and the fact that it has at least one dependency, makes
  79. %% needs_compile/3 return 'true'. The root cause is that we didn't have per
  80. %% project .rebar/erlcinfo. For <base_dir>/.rebar/erlcinfo to be populated,
  81. %% base_dir has to be compiled at least once. Therefore, after the first
  82. %% compile any compile processing the sub project will fail because
  83. %% needs_compile/3 will always return true for the non-existent 'first'
  84. %% file.
  85. ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])),
  86. ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
  87. ok = check_beams(true),
  88. ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
  89. ok = check_beams(true),
  90. ok.
  91. check_beams(Exist) ->
  92. check_files(Exist, fun filelib:is_regular/1).
  93. check_debug_info(HasDebugInfo) ->
  94. check_files(HasDebugInfo, fun has_debug_info/1).
  95. check_files(Expected, Check) ->
  96. lists:foreach(
  97. fun(F) ->
  98. File = filename:join("ebin", F),
  99. ?assertEqual(Expected, Check(File))
  100. end,
  101. ?BEAM_FILES).
  102. %% NOTE: Copied from dialyzer_utils:get_abstract_code_from_beam/1 and
  103. %% modified for local use. We could have called the function directly,
  104. %% but dialyzer_utils is not an official API to rely on.
  105. has_debug_info(File) ->
  106. case beam_lib:chunks(File, [abstract_code]) of
  107. {ok, {_Mod, List}} ->
  108. case lists:keyfind(abstract_code, 1, List) of
  109. {abstract_code, {raw_abstract_v1, _Abstr}} ->
  110. true;
  111. _ ->
  112. false
  113. end;
  114. _ ->
  115. false
  116. end.
  117. %%
  118. %% Generate the contents of a simple .app file
  119. %%
  120. app(Name, Modules) ->
  121. App = {application, Name,
  122. [{description, atom_to_list(Name)},
  123. {vsn, "1"},
  124. {modules, Modules},
  125. {registered, []},
  126. {applications, [kernel, stdlib]}]},
  127. io_lib:format("~p.\n", [App]).