windows linux mac下erlang nif或者port_driver通用编译脚本
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

212 行
6.0 KiB

  1. #!/usr/bin/env escript
  2. %% -*- erlang -*
  3. %%!
  4. -include_lib("kernel/include/file.hrl").
  5. main(Args) ->
  6. case lists:member("--help", Args) of
  7. true ->
  8. usage(),
  9. halt(0);
  10. false ->
  11. ok
  12. end,
  13. %% Get a string repr of build time
  14. BuiltTime = getTimeStr(),
  15. %% Get a string repr of first matching VCS changeset
  16. VcsInfo = vcsInfo([{git, ".git", "git describe --always --tags", "git status -s"}]),
  17. %% Check for force=1 flag to force a rebuild
  18. case lists:member("force=1", Args) of
  19. true ->
  20. rm("ebin/*.beam");
  21. false ->
  22. case filelib:is_file("ebin/npRMain.beam") of
  23. true -> rm("ebin/npRMain.beam");
  24. false -> io:fwrite("No beam files found.~n")
  25. end
  26. end,
  27. %% Add check for debug flag
  28. DebugFlag =
  29. case lists:member("debug", Args) of
  30. true -> debug_info;
  31. false -> undefined
  32. end,
  33. OtpInfo = string:strip(erlang:system_info(otp_release), both, $\n),
  34. %% Types dict:dict() and digraph:digraph() have been introduced in
  35. %% Erlang 17.
  36. %% At the same time, their counterparts dict() and digraph() are to be
  37. %% deprecated in Erlang 18. namespaced_types option is used to select
  38. %% proper type name depending on the OTP version used.
  39. %% Extract the system info of the version of OTP we use to compile npRMain
  40. %% NamespacedTypes =
  41. %% case is_otp(OtpInfo, "^[0-9]+") of
  42. %% true -> {d, namespaced_types};
  43. %% false -> undefined
  44. %% end,
  45. %% Compile all src/*.erl to ebin
  46. %% To not accidentally try to compile files like Mac OS X resource forks,
  47. %% we only look for npRMain source files that start with a letter.
  48. Opts = [
  49. DebugFlag,
  50. {outdir, "ebin"},
  51. {i, "include"},
  52. {d, 'BUILD_TIME', BuiltTime},
  53. {d, 'VCS_INFO', VcsInfo},
  54. {d, 'OTP_INFO', OtpInfo}
  55. ],
  56. case make:files(filelib:wildcard("src/*.erl"), Opts) of
  57. up_to_date ->
  58. ok;
  59. error ->
  60. io:format("Failed to compile eNpc files!\n"),
  61. halt(1)
  62. end,
  63. %% Make sure file:consult can parse the .app file
  64. case file:consult("ebin/eNpc.app") of
  65. {ok, _} ->
  66. ok;
  67. {error, Reason} ->
  68. io:format("Invalid syntax in ebin/eNpc.app: ~p\n", [Reason]),
  69. halt(1)
  70. end,
  71. %% Add ebin/ to our path
  72. true = code:add_path("ebin"),
  73. %% Run npRMain compile to do proper .app validation etc.
  74. %% and npRMain escriptize to create the npRMain script
  75. %% RebarArgs = Args -- ["debug"], %% Avoid trying to run 'debug' command
  76. % npRMain:main(["compile"] ++ RebarArgs),
  77. escriptize(),
  78. %% Finally, update executable perms for our script on *nix,
  79. %% or write out script files on win32.
  80. case os:type() of
  81. {unix, _} ->
  82. [] = os:cmd("chmod u+x eNpc"),
  83. ok;
  84. {win32, _} ->
  85. writeWindowsScripts(),
  86. ok;
  87. _ ->
  88. ok
  89. end,
  90. %% Add a helpful message
  91. io:format(<<"Congratulations! You now have a self-contained script called"
  92. " \"eNpc\" in\n"
  93. "your current working directory. "
  94. "Place this script anywhere in your path\n"
  95. "and you can use eNpc to build native code for Erlang\n">>).
  96. usage() ->
  97. io:format(<<"Usage: bootstrap [OPTION]...~n">>),
  98. io:format(<<" force=1 unconditional build~n">>),
  99. io:format(<<" debug add debug information~n">>).
  100. %% is_otp(OtpInfo, Regex) ->
  101. %% case re:run(OtpInfo, Regex, [{capture, none}]) of
  102. %% match -> true;
  103. %% nomatch -> false
  104. %% end.
  105. rm(Path) ->
  106. NativePath = filename:nativename(Path),
  107. Cmd = case os:type() of
  108. {unix, _} -> "rm -f ";
  109. {win32, _} -> "del /q "
  110. end,
  111. [] = os:cmd(Cmd ++ NativePath),
  112. ok.
  113. getTimeStr() ->
  114. {{Y, M, D}, {H, Min, S}} = erlang:localtime(),
  115. lists:flatten(io_lib:format("~B_~2.10.0B_~2.10.0B ~B:~2.10.0B:~2.10.0B", [Y, M, D, H, Min, S])).
  116. vcsInfo([]) ->
  117. "No VCS info available.";
  118. vcsInfo([{Id, Dir, VsnCmd, StatusCmd} | Rest]) ->
  119. case filelib:is_dir(Dir) of
  120. true ->
  121. Vsn = string:strip(os:cmd(VsnCmd), both, $\n),
  122. Status =
  123. case string:strip(os:cmd(StatusCmd), both, $\n) of
  124. [] ->
  125. "";
  126. _ ->
  127. "-dirty"
  128. end,
  129. lists:concat([Id, " ", Vsn, Status]);
  130. false ->
  131. vcsInfo(Rest)
  132. end.
  133. writeWindowsScripts() ->
  134. CmdScript =
  135. "@echo off\r\n"
  136. "setlocal\r\n"
  137. "set rebarscript=%~f0\r\n"
  138. "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
  139. ok = file:write_file("eNpc.cmd", CmdScript).
  140. escriptize() ->
  141. AppName = "eNpc",
  142. ScriptName = "eNpc",
  143. Files = loadEScriptFiles(AppName, "ebin", "*"),
  144. {ok, {"mem", ZipBin}} = zip:create("mem", Files, [memory]),
  145. Shebang = "#!/usr/bin/env escript\n",
  146. Comment = "%%\n",
  147. EmuArgs = io_lib:format("%%! -pa ~s/~s/ebin\n", [AppName, AppName]),
  148. Script = iolist_to_binary([Shebang, Comment, EmuArgs, ZipBin]),
  149. ok = file:write_file(ScriptName, Script),
  150. %% Finally, update executable perms for our script
  151. {ok, #file_info{mode = Mode}} = file:read_file_info(ScriptName),
  152. ok = file:change_mode(ScriptName, Mode bor 8#00111).
  153. loadEScriptFiles(AppName, Path, WildCard) ->
  154. FileNames = filelib:wildcard(WildCard, Path),
  155. Entries =
  156. lists:flatmap(
  157. fun(FN) ->
  158. FPath = filename:join(Path, FN),
  159. {ok, Contents} = file:read_file(FPath),
  160. ZipPath = filename:join(AppName, FPath),
  161. [{ZipPath, Contents} | dirEntries(ZipPath)]
  162. end,
  163. FileNames),
  164. usort(Entries).
  165. %% Given a filename, return zip archive dir entries for each sub-dir.
  166. %% Required to work around issues fixed in OTP-10071.
  167. dirEntries(File) ->
  168. Dirs = dirs(File),
  169. [{Dir ++ "/", <<>>} || Dir <- Dirs].
  170. %% Given "foo/bar/baz", return ["foo", "foo/bar", "foo/bar/baz"].
  171. dirs(Dir) ->
  172. dirs1(filename:split(Dir), "", []).
  173. dirs1([], _, Acc) ->
  174. lists:reverse(Acc);
  175. dirs1([H | T], "", []) ->
  176. dirs1(T, H, [H]);
  177. dirs1([H | T], Last, Acc) ->
  178. Dir = filename:join(Last, H),
  179. dirs1(T, Dir, [Dir | Acc]).
  180. usort(List) ->
  181. lists:ukeysort(1, lists:flatten(List)).