Current section
Files
Jump to
Current section
Files
rebar.config.script
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
%%
%% Copyright (c) 2016-2018 Tuncer Ayaz. All Rights Reserved.
%%
%% Permission to use, copy, modify, and distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
%% If library matching wildcard can be found in common lib dirs, return Opt1,
%% otherwise Opt2.
FindLibByWC = fun(WC, Opt1, Opt2) ->
Dirs = [ "/usr/local/lib/"
, "/usr/lib64/"
, "/usr/lib/"
, "/lib64/"
, "/lib/"
],
case lists:flatmap(fun(D) ->
filelib:wildcard(D ++ WC)
end,
Dirs)
of
[] -> Opt2;
[LibDir|_] -> {filename:dirname(LibDir), Opt1}
end
end.
%% If "c++ --version" identifies itself as clang, and there is libc++, use
%% that, otherwise default to libstdc++.
IsClang = fun() ->
Vsn = os:cmd("c++ --version"),
case re:run(Vsn, "clang", [{capture, none}]) of
match -> clang;
nomatch -> other_compiler
end
end.
LibCPP = "c++".
LibStdCPP = "stdc++".
MaybeUseLibCPP = fun() ->
case FindLibByWC("libc++*.{so,dylib}",
LibCPP,
LibStdCPP) of
{_LibDir, LibCPP} -> LibCPP;
LibStdCPP -> LibStdCPP
end
end.
WhichCPPLib = fun() ->
case IsClang() of
clang ->
MaybeUseLibCPP();
_ ->
LibStdCPP
end
end.
%% Only look for libc++ if rebar is older than 2.6.4. If it's new
%% enough, we can omit the extra LDFLAGS, because CXX will be used in
%% the link command.
LDFLAGS = case application:get_key(rebar, vsn) of
{ok, Rebar2Vsn} when Rebar2Vsn < "2.6.4" ->
[{"(linux|freebsd|solaris)",
"LDFLAGS", "$LDFLAGS -l" ++ WhichCPPLib()}];
_ ->
%% If undefined, Elixir's mix is evaluating
%% rebar.config.script, and since it defaults to using
%% rebar3, the port_compiler plugin will be new enough. If
%% defined, Rebar2Vsn will be newer than 2.6.4 and also good
%% enough.
[]
end.
LocalIncDir = "-Ic_src/re2".
%% Find re2 include dir on system.
Re2IncDir = fun() ->
%% Get include dir which contains the re2/ dir.
Hs = [filename:dirname(filename:dirname(F)) ||
F <- filelib:wildcard("/usr/local/include/re2/re2.h")
++ filelib:wildcard("/usr/include/re2/re2.h")],
case Hs of
[] -> not_found;
[IncDir|_] -> "-I" ++ IncDir
end
end.
FindRe2 = fun(SysLib, LocalLib) ->
%% If there is libre2.so use it, otherwise enable fetching
%% and building of a local re2 copy.
%% We could try to test compile a simple program which makes
%% use of re2, but that would needlessly complicate the build
%% process due to the requirement of caching configure
%% results.
Lib = FindLibByWC("libre2.{so,dylib}", SysLib, LocalLib),
IncDir = Re2IncDir(),
case {IncDir, Lib} of
%% re2.h not found, and even though libre2 might
%% exist, we need the headers. Therefore, fall back to
%% local re2.
{not_found, {_LibDir, SysLib}} ->
{LocalIncDir, LocalLib};
%% Neither re2.h nor libre2.so found, use local lib.
{not_found, not_found} ->
{LocalIncDir, LocalLib};
%% If re2.h is found, but there is no libre2.so, which
%% should never be the case, fall back to local re2.
{IncDir, LocalLib} ->
{LocalIncDir, LocalLib};
%% If re2.h _and_ libre2.so are found, we can use
%% system re2.
{IncDir, {LibDir, SysLib}=Sys} ->
{IncDir, Sys}
end
end.
{DebugFlags, LocalRe2Archive} = case os:getenv("DEBUG") of
false ->
{[], "c_src/re2/obj/libre2.a"};
_ ->
{"-g", "c_src/re2/obj/dbg/libre2.a"}
end,
WhichRe2 = fun() ->
SysRe2Lib = {sys, "-lre2"},
LocalRe2Lib = {local, LocalRe2Archive},
%% If env var SYSTEM_RE2 is set, try to find system re2 and
%% only fall back to local re2, if it cannot be found in the
%% system. Ideally, the default should be the other way
%% around, but it's likely this would disrupt too many
%% users' environments due to the requirement of having
%% libre2.so available. Eventually, the default should be
%% changed to give an option to skip detection of a system
%% re2.
case os:getenv("SYSTEM_RE2") of
false ->
{LocalIncDir, LocalRe2Lib};
_ ->
FindRe2(SysRe2Lib, LocalRe2Lib)
end
end.
IsRebar3 = erlang:function_exported(rebar3, main, 1),
Hooks = fun() ->
case IsRebar3 of
true ->
[ {pre_hooks,
[{{pc, compile}, "c_src/build_deps.sh"}]}
, {post_hooks,
[{{pc, clean}, "c_src/build_deps.sh clean"}]}
];
false ->
[ {pre_hooks, [{compile, "c_src/build_deps.sh"}]}
, {post_hooks, [{clean, "c_src/build_deps.sh clean"}]}
]
end
end,
CommonOpts = fun() ->
PortSpecs = {port_specs,
[
{"priv/re2_nif.so", ["c_src/re2_nif.cpp"]}
]},
BaseCFLAGS = "$DRV_CFLAGS -O3 -Wall -Wextra -std=c++11 "
++ DebugFlags ++ " ",
case WhichRe2() of
{Inc, {LibDir, {sys, Lib}}} ->
%% Use already existing (system) re2
[ PortSpecs
, {port_env,
LDFLAGS ++
[ {"DRV_CFLAGS", BaseCFLAGS ++ Inc}
, {"DRV_LDFLAGS",
"$DRV_LDFLAGS -L" ++ LibDir
++ " " ++ Lib}
]}
];
{Inc, {local, Lib}} ->
%% Use local re2, which is fetched and built by a
%% shell hook.
PortCompilerSettings =
[ PortSpecs
, {port_env,
LDFLAGS ++
[ {"DRV_CFLAGS", BaseCFLAGS ++ Inc}
, {"DRV_LDFLAGS",
"$DRV_LDFLAGS " ++ Lib}
]}
],
PortCompilerSettings ++ Hooks()
end
end.
Rebar2ExclusiveOpts = fun() -> [{qc_opts, [{qc_mod, triq}]}] end.
Rebar3ExclusiveOpts = fun() ->
[ {plugins, [pc]}
, {artifacts, ["priv/re2_nif.so"]}
, {provider_hooks,
[ {pre,
[ {compile, {pc, compile}}
, {clean, {pc, clean}}
]}
]}
]
end.
Config0 = case IsRebar3 of
true ->
CommonOpts() ++ Rebar3ExclusiveOpts();
false ->
CommonOpts() ++ Rebar2ExclusiveOpts()
end.
TriqDep = [{triq, ".*", {git, "https://github.com/triqng/triq"}}].
Config = case os:getenv("RE2_TEST_DEPS") of
false ->
Config0;
_ ->
case lists:keysearch(deps, 1, Config0) of
{value, {deps, Deps}} ->
NDeps = Deps ++ TriqDep,
lists:keyreplace(deps, 1, Config0, {deps, NDeps});
false ->
Config0 ++ [{deps, TriqDep}]
end
end.
%% If env var DEBUG_CONFIG is set, log config term.
case os:getenv("DEBUG_CONFIG") of
false ->
Config;
_ ->
C = Config,
io:format(standard_error, "rebar config:~n~p~n", [C]),
C
end.