Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

617 rindas
24 KiB

pirms 14 gadiem
pirms 14 gadiem
pirms 13 gadiem
pirms 12 gadiem
pirms 12 gadiem
pirms 14 gadiem
pirms 13 gadiem
pirms 14 gadiem
pirms 12 gadiem
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. %% -------------------------------------------------------------------
  4. %%
  5. %% rebar: Erlang Build Tools
  6. %%
  7. %% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
  8. %%
  9. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %% of this software and associated documentation files (the "Software"), to deal
  11. %% in the Software without restriction, including without limitation the rights
  12. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %% copies of the Software, and to permit persons to whom the Software is
  14. %% furnished to do so, subject to the following conditions:
  15. %%
  16. %% The above copyright notice and this permission notice shall be included in
  17. %% all copies or substantial portions of the Software.
  18. %%
  19. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %% THE SOFTWARE.
  26. %% -------------------------------------------------------------------
  27. -module(rebar_port_compiler).
  28. -export([compile/2,
  29. clean/2]).
  30. %% for internal use only
  31. -export([setup_env/1,
  32. info/2]).
  33. -include("rebar.hrl").
  34. %% ===================================================================
  35. %% Public API
  36. %% ===================================================================
  37. %% Supported configuration variables:
  38. %%
  39. %% * port_specs - Erlang list of tuples of the forms
  40. %% {ArchRegex, TargetFile, Sources, Options}
  41. %% {ArchRegex, TargetFile, Sources}
  42. %% {TargetFile, Sources}
  43. %%
  44. %% * port_env - Erlang list of key/value pairs which will control
  45. %% the environment when running the compiler and linker.
  46. %%
  47. %% By default, the following variables are defined:
  48. %% CC - C compiler
  49. %% CXX - C++ compiler
  50. %% CFLAGS - C compiler
  51. %% CXXFLAGS - C++ compiler
  52. %% LDFLAGS - Link flags
  53. %% ERL_CFLAGS - default -I paths for erts and ei
  54. %% ERL_LDFLAGS - default -L and -lerl_interface -lei
  55. %% DRV_CFLAGS - flags that will be used for compiling
  56. %% DRV_LDFLAGS - flags that will be used for linking
  57. %% EXE_CFLAGS - flags that will be used for compiling
  58. %% EXE_LDFLAGS - flags that will be used for linking
  59. %% ERL_EI_LIBDIR - ei library directory
  60. %% DRV_CXX_TEMPLATE - C++ command template
  61. %% DRV_CC_TEMPLATE - C command template
  62. %% DRV_LINK_TEMPLATE - Linker command template
  63. %% EXE_CXX_TEMPLATE - C++ command template
  64. %% EXE_CC_TEMPLATE - C command template
  65. %% EXE_LINK_TEMPLATE - Linker command template
  66. %% PORT_IN_FILES - contains a space separated list of input
  67. %% file(s), (used in command template)
  68. %% PORT_OUT_FILE - contains the output filename (used in
  69. %% command template)
  70. %%
  71. %% Note that if you wish to extend (vs. replace) these variables,
  72. %% you MUST include a shell-style reference in your definition.
  73. %% e.g. to extend CFLAGS, do something like:
  74. %%
  75. %% {port_env, [{"CFLAGS", "$CFLAGS -MyOtherOptions"}]}
  76. %%
  77. %% It is also possible to specify platform specific options
  78. %% by specifying a triplet where the first string is a regex
  79. %% that is checked against Erlang's system architecture string.
  80. %% e.g. to specify a CFLAG that only applies to x86_64 on linux
  81. %% do:
  82. %%
  83. %% {port_env, [{"x86_64.*-linux", "CFLAGS",
  84. %% "$CFLAGS -X86Options"}]}
  85. %%
  86. -record(spec, {type::'drv' | 'exe',
  87. target::file:filename(),
  88. sources = [] :: [file:filename(), ...],
  89. objects = [] :: [file:filename(), ...],
  90. opts = [] ::list() | []}).
  91. compile(Config, AppFile) ->
  92. case get_specs(Config, AppFile) of
  93. [] ->
  94. ok;
  95. Specs ->
  96. SharedEnv = rebar_config:get_env(Config, rebar_deps) ++
  97. rebar_config:get_env(Config, ?MODULE),
  98. %% Compile each of the sources
  99. NewBins = compile_sources(Config, Specs, SharedEnv),
  100. %% Make sure that the target directories exist
  101. ?INFO("Using specs ~p\n", [Specs]),
  102. lists:foreach(fun(#spec{target=Target}) ->
  103. ok = filelib:ensure_dir(Target)
  104. end, Specs),
  105. %% Only relink if necessary, given the Target
  106. %% and list of new binaries
  107. lists:foreach(
  108. fun(#spec{target=Target, objects=Bins, opts=Opts}) ->
  109. AllBins = [sets:from_list(Bins),
  110. sets:from_list(NewBins)],
  111. Intersection = sets:intersection(AllBins),
  112. case needs_link(Target, sets:to_list(Intersection)) of
  113. true ->
  114. LinkTemplate = select_link_template(Target),
  115. Env = proplists:get_value(env, Opts, SharedEnv),
  116. Cmd = expand_command(LinkTemplate, Env,
  117. string:join(Bins, " "),
  118. Target),
  119. rebar_utils:sh(Cmd, [{env, Env}]);
  120. false ->
  121. ?INFO("Skipping relink of ~s\n", [Target]),
  122. ok
  123. end
  124. end, Specs)
  125. end.
  126. clean(Config, AppFile) ->
  127. case get_specs(Config, AppFile) of
  128. [] ->
  129. ok;
  130. Specs ->
  131. lists:foreach(fun(#spec{target=Target, objects=Objects}) ->
  132. rebar_file_utils:delete_each([Target]),
  133. rebar_file_utils:delete_each(Objects)
  134. end, Specs)
  135. end,
  136. ok.
  137. setup_env(Config) ->
  138. setup_env(Config, []).
  139. %% ===================================================================
  140. %% Internal functions
  141. %% ===================================================================
  142. info(help, compile) ->
  143. info_help("Build port sources");
  144. info(help, clean) ->
  145. info_help("Delete port build results").
  146. info_help(Description) ->
  147. ?CONSOLE(
  148. "~s.~n"
  149. "~n"
  150. "Valid rebar.config options:~n"
  151. " ~p~n"
  152. " ~p~n",
  153. [
  154. Description,
  155. {port_env, [{"CFLAGS", "$CFLAGS -Ifoo"},
  156. {"freebsd", "LDFLAGS", "$LDFLAGS -lfoo"}]},
  157. {port_specs, [{"priv/so_name.so", ["c_src/*.c"]},
  158. {"linux", "priv/hello_linux", ["c_src/hello_linux.c"]},
  159. {"linux", "priv/hello_linux", ["c_src/*.c"], [{env, []}]}]}
  160. ]).
  161. setup_env(Config, ExtraEnv) ->
  162. %% Extract environment values from the config (if specified) and
  163. %% merge with the default for this operating system. This enables
  164. %% max flexibility for users.
  165. DefaultEnv = filter_env(default_env(), []),
  166. %% Get any port-specific envs; use port_env first and then fallback
  167. %% to port_envs for compatibility
  168. RawPortEnv = rebar_config:get_list(Config, port_env,
  169. rebar_config:get_list(Config, port_envs, [])),
  170. PortEnv = filter_env(RawPortEnv, []),
  171. Defines = get_defines(Config),
  172. OverrideEnv = Defines ++ PortEnv ++ filter_env(ExtraEnv, []),
  173. RawEnv = apply_defaults(os_env(), DefaultEnv) ++ OverrideEnv,
  174. expand_vars_loop(merge_each_var(RawEnv, [])).
  175. get_defines(Config) ->
  176. RawDefines = rebar_config:get_xconf(Config, defines, []),
  177. Defines = string:join(["-D" ++ D || D <- RawDefines], " "),
  178. [{"ERL_CFLAGS", "$ERL_CFLAGS " ++ Defines}].
  179. replace_extension(File, NewExt) ->
  180. OldExt = filename:extension(File),
  181. replace_extension(File, OldExt, NewExt).
  182. replace_extension(File, OldExt, NewExt) ->
  183. filename:rootname(File, OldExt) ++ NewExt.
  184. %%
  185. %% == compile and link ==
  186. %%
  187. compile_sources(Config, Specs, SharedEnv) ->
  188. lists:foldl(
  189. fun(#spec{sources=Sources, type=Type, opts=Opts}, NewBins) ->
  190. Env = proplists:get_value(env, Opts, SharedEnv),
  191. compile_each(Config, Sources, Type, Env, NewBins)
  192. end, [], Specs).
  193. compile_each(_Config, [], _Type, _Env, NewBins) ->
  194. lists:reverse(NewBins);
  195. compile_each(Config, [Source | Rest], Type, Env, NewBins) ->
  196. Ext = filename:extension(Source),
  197. Bin = replace_extension(Source, Ext, ".o"),
  198. case needs_compile(Source, Bin) of
  199. true ->
  200. Template = select_compile_template(Type, compiler(Ext)),
  201. Cmd = expand_command(Template, Env, Source, Bin),
  202. ShOpts = [{env, Env}, return_on_error, {use_stdout, false}],
  203. exec_compiler(Config, Source, Cmd, ShOpts),
  204. compile_each(Config, Rest, Type, Env, [Bin | NewBins]);
  205. false ->
  206. ?INFO("Skipping ~s\n", [Source]),
  207. compile_each(Config, Rest, Type, Env, NewBins)
  208. end.
  209. exec_compiler(Config, Source, Cmd, ShOpts) ->
  210. case rebar_utils:sh(Cmd, ShOpts) of
  211. {error, {_RC, RawError}} ->
  212. AbsSource = case rebar_utils:processing_base_dir(Config) of
  213. true ->
  214. Source;
  215. false ->
  216. filename:absname(Source)
  217. end,
  218. ?CONSOLE("Compiling ~s\n", [AbsSource]),
  219. Error = re:replace(RawError, Source, AbsSource,
  220. [{return, list}, global]),
  221. ?CONSOLE("~s", [Error]),
  222. ?FAIL;
  223. {ok, Output} ->
  224. ?CONSOLE("Compiling ~s\n", [Source]),
  225. ?CONSOLE("~s", [Output])
  226. end.
  227. needs_compile(Source, Bin) ->
  228. %% TODO: Generate depends using gcc -MM so we can also
  229. %% check for include changes
  230. filelib:last_modified(Bin) < filelib:last_modified(Source).
  231. needs_link(SoName, []) ->
  232. filelib:last_modified(SoName) == 0;
  233. needs_link(SoName, NewBins) ->
  234. MaxLastMod = lists:max([filelib:last_modified(B) || B <- NewBins]),
  235. case filelib:last_modified(SoName) of
  236. 0 ->
  237. ?DEBUG("Last mod is 0 on ~s\n", [SoName]),
  238. true;
  239. Other ->
  240. ?DEBUG("Checking ~p >= ~p\n", [MaxLastMod, Other]),
  241. MaxLastMod >= Other
  242. end.
  243. %%
  244. %% == port_specs ==
  245. %%
  246. get_specs(Config, AppFile) ->
  247. Specs = case rebar_config:get_local(Config, port_specs, []) of
  248. [] ->
  249. %% No spec provided. Construct a spec
  250. %% from old-school so_name and sources
  251. [port_spec_from_legacy(Config, AppFile)];
  252. PortSpecs ->
  253. Filtered = filter_port_specs(PortSpecs),
  254. OsType = os:type(),
  255. [get_port_spec(Config, OsType, Spec) || Spec <- Filtered]
  256. end,
  257. [S || S <- Specs, S#spec.sources /= []].
  258. port_spec_from_legacy(Config, AppFile) ->
  259. %% Get the target from the so_name variable
  260. Target = case rebar_config:get(Config, so_name, undefined) of
  261. undefined ->
  262. %% Generate a sensible default from app file
  263. {_, AppName} = rebar_app_utils:app_name(Config, AppFile),
  264. filename:join("priv",
  265. lists:concat([AppName, "_drv.so"]));
  266. AName ->
  267. %% Old form is available -- use it
  268. filename:join("priv", AName)
  269. end,
  270. %% Get the list of source files from port_sources
  271. Sources = port_sources(rebar_config:get_list(Config, port_sources,
  272. ["c_src/*.c"])),
  273. #spec { type = target_type(Target),
  274. target = maybe_switch_extension(os:type(), Target),
  275. sources = Sources,
  276. objects = port_objects(Sources) }.
  277. filter_port_specs(Specs) ->
  278. [S || S <- Specs, filter_port_spec(S)].
  279. filter_port_spec({ArchRegex, _, _, _}) ->
  280. rebar_utils:is_arch(ArchRegex);
  281. filter_port_spec({ArchRegex, _, _}) ->
  282. rebar_utils:is_arch(ArchRegex);
  283. filter_port_spec({_, _}) ->
  284. true.
  285. get_port_spec(Config, OsType, {Target, Sources}) ->
  286. get_port_spec(Config, OsType, {undefined, Target, Sources, []});
  287. get_port_spec(Config, OsType, {Arch, Target, Sources}) ->
  288. get_port_spec(Config, OsType, {Arch, Target, Sources, []});
  289. get_port_spec(Config, OsType, {_Arch, Target, Sources, Opts}) ->
  290. SourceFiles = port_sources(Sources),
  291. ObjectFiles = port_objects(SourceFiles),
  292. #spec{type=target_type(Target),
  293. target=maybe_switch_extension(OsType, Target),
  294. sources=SourceFiles,
  295. objects=ObjectFiles,
  296. opts=port_opts(Config, Opts)}.
  297. port_sources(Sources) ->
  298. lists:flatmap(fun filelib:wildcard/1, Sources).
  299. port_objects(SourceFiles) ->
  300. [replace_extension(O, ".o") || O <- SourceFiles].
  301. port_opts(Config, Opts) ->
  302. [port_opt(Config, O) || O <- Opts].
  303. port_opt(Config, {env, Env}) ->
  304. {env, setup_env(Config, Env)};
  305. port_opt(_Config, Opt) ->
  306. Opt.
  307. maybe_switch_extension({win32, nt}, Target) ->
  308. switch_to_dll_or_exe(Target);
  309. maybe_switch_extension(_OsType, Target) ->
  310. Target.
  311. switch_to_dll_or_exe(Target) ->
  312. case filename:extension(Target) of
  313. ".so" -> filename:rootname(Target, ".so") ++ ".dll";
  314. [] -> Target ++ ".exe";
  315. _Other -> Target
  316. end.
  317. %%
  318. %% == port_env ==
  319. %%
  320. %%
  321. %% Choose a compiler variable, based on a provided extension
  322. %%
  323. compiler(".cc") -> "$CXX";
  324. compiler(".cp") -> "$CXX";
  325. compiler(".cxx") -> "$CXX";
  326. compiler(".cpp") -> "$CXX";
  327. compiler(".CPP") -> "$CXX";
  328. compiler(".c++") -> "$CXX";
  329. compiler(".C") -> "$CXX";
  330. compiler(_) -> "$CC".
  331. %%
  332. %% Given a list of {Key, Value} variables, and another list of default
  333. %% {Key, Value} variables, return a merged list where the rule is if the
  334. %% default is expandable expand it with the value of the variable list,
  335. %% otherwise just return the value of the variable.
  336. %%
  337. apply_defaults(Vars, Defaults) ->
  338. dict:to_list(
  339. dict:merge(fun(Key, VarValue, DefaultValue) ->
  340. case is_expandable(DefaultValue) of
  341. true ->
  342. rebar_utils:expand_env_variable(DefaultValue,
  343. Key,
  344. VarValue);
  345. false -> VarValue
  346. end
  347. end,
  348. dict:from_list(Vars),
  349. dict:from_list(Defaults))).
  350. %%
  351. %% Given a list of {Key, Value} environment variables, where Key may be defined
  352. %% multiple times, walk the list and expand each self-reference so that we
  353. %% end with a list of each variable singly-defined.
  354. %%
  355. merge_each_var([], Vars) ->
  356. Vars;
  357. merge_each_var([{Key, Value} | Rest], Vars) ->
  358. Evalue = case orddict:find(Key, Vars) of
  359. error ->
  360. %% Nothing yet defined for this key/value.
  361. %% Expand any self-references as blank.
  362. rebar_utils:expand_env_variable(Value, Key, "");
  363. {ok, Value0} ->
  364. %% Use previous definition in expansion
  365. rebar_utils:expand_env_variable(Value, Key, Value0)
  366. end,
  367. merge_each_var(Rest, orddict:store(Key, Evalue, Vars)).
  368. %%
  369. %% Give a unique list of {Key, Value} environment variables, expand each one
  370. %% for every other key until no further expansions are possible.
  371. %%
  372. expand_vars_loop(Vars) ->
  373. expand_vars_loop(Vars, [], dict:from_list(Vars), 10).
  374. expand_vars_loop(_Pending, _Recurse, _Vars, 0) ->
  375. ?ABORT("Max. expansion reached for ENV vars!\n", []);
  376. expand_vars_loop([], [], Vars, _Count) ->
  377. lists:keysort(1, dict:to_list(Vars));
  378. expand_vars_loop([], Recurse, Vars, Count) ->
  379. expand_vars_loop(Recurse, [], Vars, Count-1);
  380. expand_vars_loop([{K, V} | Rest], Recurse, Vars, Count) ->
  381. %% Identify the variables that need expansion in this value
  382. ReOpts = [global, {capture, all_but_first, list}, unicode],
  383. case re:run(V, "\\\${?(\\w+)}?", ReOpts) of
  384. {match, Matches} ->
  385. %% Identify the unique variables that need to be expanded
  386. UniqueMatches = lists:usort([M || [M] <- Matches]),
  387. %% For each variable, expand it and return the final
  388. %% value. Note that if we have a bunch of unresolvable
  389. %% variables, nothing happens and we don't bother
  390. %% attempting further expansion
  391. case expand_keys_in_value(UniqueMatches, V, Vars) of
  392. V ->
  393. %% No change after expansion; move along
  394. expand_vars_loop(Rest, Recurse, Vars, Count);
  395. Expanded ->
  396. %% Some expansion occurred; move to next k/v but
  397. %% revisit this value in the next loop to check
  398. %% for further expansion
  399. NewVars = dict:store(K, Expanded, Vars),
  400. expand_vars_loop(Rest, [{K, Expanded} | Recurse],
  401. NewVars, Count)
  402. end;
  403. nomatch ->
  404. %% No values in this variable need expansion; move along
  405. expand_vars_loop(Rest, Recurse, Vars, Count)
  406. end.
  407. expand_keys_in_value([], Value, _Vars) ->
  408. Value;
  409. expand_keys_in_value([Key | Rest], Value, Vars) ->
  410. NewValue = case dict:find(Key, Vars) of
  411. {ok, KValue} ->
  412. rebar_utils:expand_env_variable(Value, Key, KValue);
  413. error ->
  414. Value
  415. end,
  416. expand_keys_in_value(Rest, NewValue, Vars).
  417. expand_command(TmplName, Env, InFiles, OutFile) ->
  418. Cmd0 = proplists:get_value(TmplName, Env),
  419. Cmd1 = rebar_utils:expand_env_variable(Cmd0, "PORT_IN_FILES", InFiles),
  420. rebar_utils:expand_env_variable(Cmd1, "PORT_OUT_FILE", OutFile).
  421. %%
  422. %% Given a string, determine if it is expandable
  423. %%
  424. is_expandable(InStr) ->
  425. case re:run(InStr,"\\\$",[{capture,none}]) of
  426. match -> true;
  427. nomatch -> false
  428. end.
  429. %%
  430. %% Filter a list of env vars such that only those which match the provided
  431. %% architecture regex (or do not have a regex) are returned.
  432. %%
  433. filter_env([], Acc) ->
  434. lists:reverse(Acc);
  435. filter_env([{ArchRegex, Key, Value} | Rest], Acc) ->
  436. case rebar_utils:is_arch(ArchRegex) of
  437. true ->
  438. filter_env(Rest, [{Key, Value} | Acc]);
  439. false ->
  440. filter_env(Rest, Acc)
  441. end;
  442. filter_env([{Key, Value} | Rest], Acc) ->
  443. filter_env(Rest, [{Key, Value} | Acc]).
  444. erts_dir() ->
  445. lists:concat([code:root_dir(), "/erts-", erlang:system_info(version)]).
  446. os_env() ->
  447. ReOpts = [{return, list}, {parts, 2}, unicode],
  448. Os = [list_to_tuple(re:split(S, "=", ReOpts)) ||
  449. S <- lists:filter(fun discard_deps_vars/1, os:getenv())],
  450. %% Drop variables without a name (win32)
  451. [T1 || {K, _V} = T1 <- Os, K =/= []].
  452. %%
  453. %% To avoid having multiple repetitions of the same environment variables
  454. %% (ERL_LIBS), avoid exporting any variables that may cause conflict with
  455. %% those exported by the rebar_deps module (ERL_LIBS, REBAR_DEPS_DIR)
  456. %%
  457. discard_deps_vars("ERL_LIBS=" ++ _Value) -> false;
  458. discard_deps_vars("REBAR_DEPS_DIR=" ++ _Value) -> false;
  459. discard_deps_vars(_Var) -> true.
  460. select_compile_template(drv, Compiler) ->
  461. select_compile_drv_template(Compiler);
  462. select_compile_template(exe, Compiler) ->
  463. select_compile_exe_template(Compiler).
  464. select_compile_drv_template("$CC") -> "DRV_CC_TEMPLATE";
  465. select_compile_drv_template("$CXX") -> "DRV_CXX_TEMPLATE".
  466. select_compile_exe_template("$CC") -> "EXE_CC_TEMPLATE";
  467. select_compile_exe_template("$CXX") -> "EXE_CXX_TEMPLATE".
  468. select_link_template(Target) ->
  469. case target_type(Target) of
  470. drv -> "DRV_LINK_TEMPLATE";
  471. exe -> "EXE_LINK_TEMPLATE"
  472. end.
  473. target_type(Target) -> target_type1(filename:extension(Target)).
  474. target_type1(".so") -> drv;
  475. target_type1(".dll") -> drv;
  476. target_type1("") -> exe;
  477. target_type1(".exe") -> exe.
  478. erl_interface_dir(Subdir) ->
  479. case code:lib_dir(erl_interface, Subdir) of
  480. {error, bad_name} ->
  481. throw({error, {erl_interface,Subdir,"code:lib_dir(erl_interface)"
  482. "is unable to find the erl_interface library."}});
  483. Dir -> Dir
  484. end.
  485. default_env() ->
  486. [
  487. {"CC" , "cc"},
  488. {"CXX", "c++"},
  489. {"DRV_CXX_TEMPLATE",
  490. "$CXX -c $CXXFLAGS $DRV_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE"},
  491. {"DRV_CC_TEMPLATE",
  492. "$CC -c $CFLAGS $DRV_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE"},
  493. {"DRV_LINK_TEMPLATE",
  494. "$CC $PORT_IN_FILES $LDFLAGS $DRV_LDFLAGS -o $PORT_OUT_FILE"},
  495. {"EXE_CXX_TEMPLATE",
  496. "$CXX -c $CXXFLAGS $EXE_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE"},
  497. {"EXE_CC_TEMPLATE",
  498. "$CC -c $CFLAGS $EXE_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE"},
  499. {"EXE_LINK_TEMPLATE",
  500. "$CC $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS -o $PORT_OUT_FILE"},
  501. {"DRV_CFLAGS" , "-g -Wall -fPIC $ERL_CFLAGS"},
  502. {"DRV_LDFLAGS", "-shared $ERL_LDFLAGS"},
  503. {"EXE_CFLAGS" , "-g -Wall -fPIC $ERL_CFLAGS"},
  504. {"EXE_LDFLAGS", "$ERL_LDFLAGS"},
  505. {"ERL_CFLAGS", lists:concat([" -I\"", erl_interface_dir(include),
  506. "\" -I\"", filename:join(erts_dir(), "include"),
  507. "\" "])},
  508. {"ERL_EI_LIBDIR", lists:concat(["\"", erl_interface_dir(lib), "\""])},
  509. {"ERL_LDFLAGS" , " -L$ERL_EI_LIBDIR -lerl_interface -lei"},
  510. {"ERLANG_ARCH" , rebar_utils:wordsize()},
  511. {"ERLANG_TARGET", rebar_utils:get_arch()},
  512. {"darwin", "DRV_LDFLAGS",
  513. "-bundle -flat_namespace -undefined suppress $ERL_LDFLAGS"},
  514. %% Solaris specific flags
  515. {"solaris.*-64$", "CFLAGS", "-D_REENTRANT -m64 $CFLAGS"},
  516. {"solaris.*-64$", "CXXFLAGS", "-D_REENTRANT -m64 $CXXFLAGS"},
  517. {"solaris.*-64$", "LDFLAGS", "-m64 $LDFLAGS"},
  518. %% OS X Leopard flags for 64-bit
  519. {"darwin9.*-64$", "CFLAGS", "-m64 $CFLAGS"},
  520. {"darwin9.*-64$", "CXXFLAGS", "-m64 $CXXFLAGS"},
  521. {"darwin9.*-64$", "LDFLAGS", "-arch x86_64 $LDFLAGS"},
  522. %% OS X Snow Leopard, Lion, and Mountain Lion flags for 32-bit
  523. {"darwin1[0-2].*-32", "CFLAGS", "-m32 $CFLAGS"},
  524. {"darwin1[0-2].*-32", "CXXFLAGS", "-m32 $CXXFLAGS"},
  525. {"darwin1[0-2].*-32", "LDFLAGS", "-arch i386 $LDFLAGS"},
  526. %% Windows specific flags
  527. %% add MS Visual C++ support to rebar on Windows
  528. {"win32", "CC", "cl.exe"},
  529. {"win32", "CXX", "cl.exe"},
  530. {"win32", "LINKER", "link.exe"},
  531. {"win32", "DRV_CXX_TEMPLATE",
  532. %% DRV_* and EXE_* Templates are identical
  533. "$CXX /c $CXXFLAGS $DRV_CFLAGS $PORT_IN_FILES /Fo$PORT_OUT_FILE"},
  534. {"win32", "DRV_CC_TEMPLATE",
  535. "$CC /c $CFLAGS $DRV_CFLAGS $PORT_IN_FILES /Fo$PORT_OUT_FILE"},
  536. {"win32", "DRV_LINK_TEMPLATE",
  537. "$LINKER $PORT_IN_FILES $LDFLAGS $DRV_LDFLAGS /OUT:$PORT_OUT_FILE"},
  538. %% DRV_* and EXE_* Templates are identical
  539. {"win32", "EXE_CXX_TEMPLATE",
  540. "$CXX /c $CXXFLAGS $EXE_CFLAGS $PORT_IN_FILES /Fo$PORT_OUT_FILE"},
  541. {"win32", "EXE_CC_TEMPLATE",
  542. "$CC /c $CFLAGS $EXE_CFLAGS $PORT_IN_FILES /Fo$PORT_OUT_FILE"},
  543. {"win32", "EXE_LINK_TEMPLATE",
  544. "$LINKER $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS /OUT:$PORT_OUT_FILE"},
  545. %% ERL_CFLAGS are ok as -I even though strictly it should be /I
  546. {"win32", "ERL_LDFLAGS", " /LIBPATH:$ERL_EI_LIBDIR erl_interface.lib ei.lib"},
  547. {"win32", "DRV_CFLAGS", "/Zi /Wall $ERL_CFLAGS"},
  548. {"win32", "DRV_LDFLAGS", "/DLL $ERL_LDFLAGS"}
  549. ].