%% vim:ts=2:sw=2:et
%% For cross building using erlang:system_info() does not work as rebar runs
%% using the build hosts Erlang runtime.
%% If CXX environment variable is defined we are most likely running in a cross environment.
{CXX,Target,Sysroot} =
  case os:getenv("CXX") of
    false    ->
      {"g++",erlang:system_info(system_architecture),""};
    Compiler ->
      {Compiler,string:strip(os:cmd(Compiler ++ " -dumpmachine"),   right, $\n),
                string:strip(os:cmd(Compiler ++ " -print-sysroot"), right, $\n)}
  end,

%% By default use poll(2).  If USE_POLL=0 is defined, use select(2):
UsePoll =
  case os:getenv("USE_POLL") of
    false   -> " -DUSE_POLL=1";
    "0"     -> "";
    "false" -> ""
  end,

%% Commonly on Linux, compilers report the target triplet as <arch>-<vendor>-linux,
%% however, Erlang runtime reports and expects it as <arch>-<vendor>-linux-gnu.
%% Fix by appending "-gnu".
Mach =
  case string:str(Target,"linux") of
    0 -> Target;
    _ -> case string:words(Target,$-) of
           4 -> Target;
           _ -> Target ++ "-gnu"
         end
  end,

Vsn = string:strip(os:cmd("git describe --always --tags --abbrev=0 | sed 's/^v//'"), right, $\n),

%% Check for Linux capability API (Install package: libcap-devel).
{LinCXX, LinLD} =
  case file:read_file_info(Sysroot ++ "/usr/include/sys/capability.h") of
    {ok, _} -> {" -DHAVE_CAP", " -lcap"};
    _       -> {"", ""}
  end,

X64 =
  case Mach of
    "x86_64" ++ _E -> " -m64";
    _              -> ""
  end,

Optimize =
  fun(0) ->
     io:format(standard_error, "Building exec-port without optimization\n", []),
     " -O0";
  (I) when is_integer(I), I > 0 ->
    " -O" ++ integer_to_list(I) ++ " -DNDEBUG"
  end,
Optim =
  case os:getenv("OPTIMIZE") of
    false   -> Optimize(3);
    "true"  -> Optimize(3);
    "false" -> Optimize(0);
    Level   -> Optimize(list_to_integer(Level))
  end,

CxxFlags = " -g -std=c++11" ++ UsePoll ++ Optim,

% Merge configuration options read from rebar.config with those dynamically set below
maps:to_list(lists:foldl(
  fun({K, V}, M) ->
    case maps:find(K, M) of
      {ok, V0} -> M#{K => V0 ++ V};
      error    -> M#{K => V}
    end
  end,
  maps:from_list(CONFIG),
  [
    {port_env,  [{"solaris", "CXXFLAGS", "$CXXFLAGS -DHAVE_SETREUID" ++ CxxFlags},
                 {"solaris", "LDFLAGS",  "$LDFLAGS -lrt" ++ X64},

                 {"darwin",  "CXXFLAGS", "$CXXFLAGS -DHAVE_SETREUID" ++ CxxFlags},
                 {"darwin",  "LDFLAGS",  "$LDFLAGS" ++ X64},

                 {"freebsd",   "CXXFLAGS", "$CXXFLAGS -DHAVE_SETRESUID -DHAVE_PIPE2" ++ CxxFlags ++ X64},
                 {"freebsd",   "LDFLAGS",  "$LDFLAGS" ++ X64},

                 {"openbsd",   "CXXFLAGS", "$CXXFLAGS -DHAVE_SETRESUID -DHAVE_PIPE2" ++ CxxFlags ++ X64},
                 {"openbsd",   "LDFLAGS",  "$LDFLAGS" ++ X64},

                 {"dragonfly",   "CXXFLAGS", "$CXXFLAGS -DHAVE_SETRESUID -DHAVE_PIPE2" ++ CxxFlags ++ X64},
                 {"dragonfly",   "LDFLAGS",  "$LDFLAGS" ++ X64},

                 {"linux",   "CXXFLAGS", "$CXXFLAGS -DHAVE_SETRESUID -DHAVE_PIPE2" ++ LinCXX ++ CxxFlags ++ X64},
                 {"linux",   "LDFLAGS",  "$LDFLAGS" ++ LinLD},

                 {"CC",  CXX},
                 {"CXX", CXX},
                 {"EXE_CFLAGS", "-Wall -fPIC -MMD $ERL_CFLAGS"},
                 {"CXXFLAGS",   "$CXXFLAGS -DHAVE_PTRACE"}
                ]},

    {port_specs,[{filename:join(["priv", Mach, "exec-port"]), ["c_src/*.cpp"]}]},
    {edoc_opts, [{def,             {vsn, Vsn}}]}
  ]
)).
