diff options
author | Fred Hebert <mononcqc@ferd.ca> | 2015-07-02 14:47:54 -0400 |
---|---|---|
committer | Fred Hebert <mononcqc@ferd.ca> | 2015-07-02 14:47:54 -0400 |
commit | 75b7dda523861b1b1f0cf06910f8bcaabd226ca3 (patch) | |
tree | 464aa2f93fd4ea611d7b6907704dbe2b9bf8140b | |
parent | 6cc18c931cdeec68f50708fdc7638e13611b825d (diff) | |
parent | 9a64826172ade12997e8ee0ff32df52757c43025 (diff) | |
download | rebar-75b7dda523861b1b1f0cf06910f8bcaabd226ca3.tar.gz |
Merge pull request #520 from tuncer/tonyrog-cross-arch
Fixed version of #451
-rw-r--r-- | THANKS | 1 | ||||
-rw-r--r-- | rebar.config | 3 | ||||
-rw-r--r-- | src/rebar_port_compiler.erl | 52 | ||||
-rw-r--r-- | src/rebar_utils.erl | 172 |
4 files changed, 206 insertions, 22 deletions
@@ -142,3 +142,4 @@ Derek Brown Danil Onishchenko Stavros Aronis James Fish +Tony Rogvall diff --git a/rebar.config b/rebar.config index a3849ec..bcd5368 100644 --- a/rebar.config +++ b/rebar.config @@ -29,7 +29,8 @@ - (\"gpb_compile\":\"format_error\"/\"1\") - (\"diameter_codegen\":\"from_dict\"/\"4\") - (\"diameter_dict_util\":\"format_error\"/\"1\") - - (\"diameter_dict_util\":\"parse\"/\"2\"))", + - (\"diameter_dict_util\":\"parse\"/\"2\") + - (\"erlang\":\"timestamp\"/\"0\"))", []}]}. {dialyzer, diff --git a/src/rebar_port_compiler.erl b/src/rebar_port_compiler.erl index 5855589..dcd8a20 100644 --- a/src/rebar_port_compiler.erl +++ b/src/rebar_port_compiler.erl @@ -165,7 +165,14 @@ info_help(Description) -> "~n" "Valid rebar.config options:~n" " ~p~n" - " ~p~n", + " ~p~n" + "Cross-arch environment variables:~n" + " REBAR_TARGET_ARCH to set the tool chain name to use~n" + " REBAR_TARGET_ARCH_WORDSIZE optional " + "(if CC fails to determine word size)~n" + " fallback word size is 32~n" + " REBAR_TARGET_ARCH_VSN optional " + "(if a special version of CC/CXX is requested)~n", [ Description, {port_env, [{"CFLAGS", "$CFLAGS -Ifoo"}, @@ -183,8 +190,10 @@ setup_env(Config, ExtraEnv) -> %% Get any port-specific envs; use port_env first and then fallback %% to port_envs for compatibility - RawPortEnv = rebar_config:get_list(Config, port_env, - rebar_config:get_list(Config, port_envs, [])), + RawPortEnv = rebar_config:get_list( + Config, + port_env, + rebar_config:get_list(Config, port_envs, [])), PortEnv = filter_env(RawPortEnv, []), Defines = get_defines(Config), @@ -568,9 +577,21 @@ erl_interface_dir(Subdir) -> end. default_env() -> + Arch = os:getenv("REBAR_TARGET_ARCH"), + Vsn = os:getenv("REBAR_TARGET_ARCH_VSN"), [ - {"CC" , "cc"}, - {"CXX", "c++"}, + {"CC", get_tool(Arch, Vsn,"gcc", "cc")}, + {"CXX", get_tool(Arch, Vsn,"g++", "c++")}, + {"AR", get_tool(Arch, "ar", "ar")}, + {"AS", get_tool(Arch, "as", "as")}, + {"CPP", get_tool(Arch, Vsn, "cpp", "cpp")}, + {"LD", get_tool(Arch, "ld", "ld")}, + {"RANLIB", get_tool(Arch, Vsn, "ranlib", "ranlib")}, + {"STRIP", get_tool(Arch, "strip", "strip")}, + {"NM", get_tool(Arch, "nm", "nm")}, + {"OBJCOPY", get_tool(Arch, "objcopy", "objcopy")}, + {"OBJDUMP", get_tool(Arch, "objdump", "objdump")}, + {"DRV_CXX_TEMPLATE", "$CXX -c $CXXFLAGS $DRV_CFLAGS $PORT_IN_FILES -o $PORT_OUT_FILE"}, {"DRV_CC_TEMPLATE", @@ -588,9 +609,12 @@ default_env() -> {"EXE_CFLAGS" , "-g -Wall -fPIC -MMD $ERL_CFLAGS"}, {"EXE_LDFLAGS", "$ERL_LDFLAGS"}, - {"ERL_CFLAGS", lists:concat([" -I\"", erl_interface_dir(include), - "\" -I\"", filename:join(erts_dir(), "include"), - "\" "])}, + {"ERL_CFLAGS", lists:concat( + [ + " -I\"", erl_interface_dir(include), + "\" -I\"", filename:join(erts_dir(), "include"), + "\" " + ])}, {"ERL_EI_LIBDIR", lists:concat(["\"", erl_interface_dir(lib), "\""])}, {"ERL_LDFLAGS" , " -L$ERL_EI_LIBDIR -lerl_interface -lei"}, {"ERLANG_ARCH" , rebar_utils:wordsize()}, @@ -639,7 +663,17 @@ default_env() -> {"win32", "EXE_LINK_TEMPLATE", "$LINKER $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS /OUT:$PORT_OUT_FILE"}, %% ERL_CFLAGS are ok as -I even though strictly it should be /I - {"win32", "ERL_LDFLAGS", " /LIBPATH:$ERL_EI_LIBDIR erl_interface.lib ei.lib"}, + {"win32", "ERL_LDFLAGS", + " /LIBPATH:$ERL_EI_LIBDIR erl_interface.lib ei.lib"}, {"win32", "DRV_CFLAGS", "/Zi /Wall $ERL_CFLAGS"}, {"win32", "DRV_LDFLAGS", "/DLL $ERL_LDFLAGS"} ]. + +get_tool(Arch, Tool, Default) -> + get_tool(Arch, false, Tool, Default). + +get_tool(false, _, _, Default) -> Default; +get_tool("", _, _, Default) -> Default; +get_tool(Arch, false, Tool, _Default) -> Arch++"-"++Tool; +get_tool(Arch, "", Tool, _Default) -> Arch++"-"++Tool; +get_tool(Arch, Vsn, Tool, _Default) -> Arch++"-"++Tool++"-"++Vsn. diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 9681756..045e67b 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -67,7 +67,8 @@ processing_base_dir/1, processing_base_dir/2, patch_env/2, - cleanup_code_path/1]). + cleanup_code_path/1 + ]). %% for internal use only -export([otp_release/0]). @@ -91,20 +92,24 @@ is_arch(ArchRegex) -> nomatch -> false end. - +%% +%% REBAR_TARGET_ARCH, if used, should be set to the "standard" +%% target string. That is a prefix for binutils tools. +%% "x86_64-linux-gnu" or "arm-linux-gnueabi" are good candidates +%% ${REBAR_TARGET_ARCH}-gcc, ${REBAR_TARGET_ARCH}-ld ... +%% get_arch() -> - Words = wordsize(), - otp_release() ++ "-" - ++ erlang:system_info(system_architecture) ++ "-" ++ Words. + Arch = os:getenv("REBAR_TARGET_ARCH"), + Words = wordsize(Arch), + otp_release() ++ "-" ++ get_system_arch(Arch) ++ "-" ++ Words. + +get_system_arch(Arch) when Arch =:= false; Arch =:= "" -> + erlang:system_info(system_architecture); +get_system_arch(Arch) -> + Arch. wordsize() -> - try erlang:system_info({wordsize, external}) of - Val -> - integer_to_list(8 * Val) - catch - error:badarg -> - integer_to_list(8 * erlang:system_info(wordsize)) - end. + wordsize(os:getenv("REBAR_TARGET_ARCH")). sh_send(Command0, String, Options0) -> ?INFO("sh_send info:\n\tcwd: ~p\n\tcmd: ~s < ~s\n", @@ -673,3 +678,146 @@ cleanup_code_path(OrigPath) -> _ -> code:set_path(OrigPath) end. + +wordsize(Arch) when Arch =:= false; Arch =:= "" -> + native_wordsize(); +wordsize(Arch) -> + AllArchs = [ + {"i686","32"}, + {"i386","32"}, + {"arm","32"}, + {"aarch64", "64"}, + {"x86_64","64"} + ], + case match_wordsize(Arch, AllArchs) of + false -> + case cross_wordsize(Arch) of + "" -> + env_wordsize(os:getenv("REBAR_TARGET_ARCH_WORDSIZE")); + WordSize -> + WordSize + end; + {_, Wordsize} -> + Wordsize + end. + +match_wordsize(Arch, [V={Match,_Bits}|Vs]) -> + case re:run(Arch, Match, [{capture, none}]) of + match -> + V; + nomatch -> + match_wordsize(Arch, Vs) + end; +match_wordsize(_Arch, []) -> + false. + +env_wordsize(Wordsize) when Wordsize =:= false; + Wordsize =:= "" -> + ?WARN("REBAR_TARGET_ARCH_WORDSIZE not set, assuming 32\n", []), + "32"; +env_wordsize(Wordsize) -> + case Wordsize of + "16" -> Wordsize; + "32" -> Wordsize; + "64" -> Wordsize; + _ -> + ?WARN("REBAR_TARGET_ARCH_WORDSIZE bad value: ~p\n", [Wordsize]), + "32" + end. + +%% +%% Find out the word size of the target by using Arch-gcc +%% +cross_wordsize(Arch) -> + cross_sizeof(Arch, "void*"). + +%% +%% Find the size of target Type using a specially crafted C file +%% that will report an error on the line of the byte size of the type. +%% +cross_sizeof(Arch, Type) -> + Compiler = if Arch =:= "" -> "cc"; + true -> Arch ++ "-gcc" + end, + TempFile = mktempfile(".c"), + ok = file:write_file(TempFile, + <<"int t01 [1 - 2*(((long) (sizeof (TYPE))) == 1)];\n" + "int t02 [1 - 2*(((long) (sizeof (TYPE))) == 2)];\n" + "int t03 [1 - 2*(((long) (sizeof (TYPE))) == 3)];\n" + "int t04 [1 - 2*(((long) (sizeof (TYPE))) == 4)];\n" + "int t05 [1 - 2*(((long) (sizeof (TYPE))) == 5)];\n" + "int t06 [1 - 2*(((long) (sizeof (TYPE))) == 6)];\n" + "int t07 [1 - 2*(((long) (sizeof (TYPE))) == 7)];\n" + "int t08 [1 - 2*(((long) (sizeof (TYPE))) == 8)];\n" + "int t09 [1 - 2*(((long) (sizeof (TYPE))) == 9)];\n" + "int t10 [1 - 2*(((long) (sizeof (TYPE))) == 10)];\n" + "int t11 [1 - 2*(((long) (sizeof (TYPE))) == 11)];\n" + "int t12 [1 - 2*(((long) (sizeof (TYPE))) == 12)];\n" + "int t13 [1 - 2*(((long) (sizeof (TYPE))) == 13)];\n" + "int t14 [1 - 2*(((long) (sizeof (TYPE))) == 14)];\n" + "int t15 [1 - 2*(((long) (sizeof (TYPE))) == 15)];\n" + "int t16 [1 - 2*(((long) (sizeof (TYPE))) == 16)];\n" + >>), + Cmd = Compiler ++ " -DTYPE=\""++Type++"\" " ++ TempFile, + ShOpts = [{use_stdout, false}, return_on_error], + {ok, Res} = sh(Cmd, ShOpts), + ok = file:delete(TempFile), + case string:tokens(Res, ":") of + [_, Ln | _] -> + try list_to_integer(Ln) of + NumBytes -> integer_to_list(NumBytes*8) + catch + error:_ -> + "" + end; + _ -> + "" + end. + +mktempfile(Suffix) -> + {A,B,C} = rebar_now(), + Dir = temp_dir(), + File = "rebar_"++os:getpid()++ + integer_to_list(A)++"_"++ + integer_to_list(B)++"_"++ + integer_to_list(C)++Suffix, + filename:join(Dir, File). + +temp_dir() -> + case os:type() of + {win32, _} -> windows_temp_dir(); + _ -> "/tmp" + end. + +windows_temp_dir() -> + case os:getenv("TEMP") of + false -> + case os:getenv("TMP") of + false -> "C:/WINDOWS/TEMP"; + TMP -> TMP + end; + TEMP -> TEMP + end. + +rebar_now() -> + case erlang:function_exported(erlang, timestamp, 0) of + true -> + erlang:timestamp(); + false -> + %% erlang:now/0 was deprecated in 18.0, and as the escript has to + %% pass erl_lint:module/1 (even without -mode(compile)), we would + %% see a deprecation warning for erlang:now/0. One solution is to + %% use -compile({nowarn_deprecated_function, [{erlang, now, 0}]}), + %% but that would raise a warning in versions older than 18.0. + %% Calling erlang:now/0 via apply/3 avoids that. + apply(erlang, now, []) + end. + +native_wordsize() -> + try erlang:system_info({wordsize, external}) of + Val -> + integer_to_list(8 * Val) + catch + error:badarg -> + integer_to_list(8 * erlang:system_info(wordsize)) + end. |