blob: f23628731561cdf8fd5d07b98d785daa314beccc [file] [log] [blame]
%% vim: set ft=erlang : -*- erlang -*- % Magic lines for code editors
%% Licensed under the Apache License, Version 2.0 (the "License"); you may not
%% use this file except in compliance with the License. You may obtain a copy of
%% the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
%% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
%% License for the specific language governing permissions and limitations under
%% the License.
CopyIfDifferent = fun(Path, Contents) ->
case filelib:is_file(Path) of
true ->
case file:read_file(Path) of
{ok, Contents} ->
ok;
_ ->
file:write_file(Path, Contents)
end;
false ->
file:write_file(Path, Contents)
end
end.
CouchJSName = case os:type() of
{win32, _} ->
"couchjs.exe";
_ ->
"couchjs"
end.
CouchJSPath = filename:join(["priv", CouchJSName]).
Version = case os:getenv("COUCHDB_VERSION") of
false ->
string:strip(os:cmd("git describe --always"), right, $\n);
Version0 ->
string:strip(Version0, right)
end.
GitSha = case os:getenv("COUCHDB_GIT_SHA") of
false ->
""; % release builds won\'t get a fallback
GitSha0 ->
string:strip(GitSha0, right)
end.
CouchConfig = case filelib:is_file(os:getenv("COUCHDB_CONFIG")) of
true ->
{ok, Result} = file:consult(os:getenv("COUCHDB_CONFIG")),
Result;
false ->
[]
end.
JsEngine = case lists:keyfind(js_engine, 1, CouchConfig) of
{_, "spidermonkey"} ->
"spidermonkey";
{_, "quickjs"} ->
"quickjs";
{_, InvalidJsEngine} ->
io:format(standard_error, "Unsupported default JS engine ~p~n", [InvalidJsEngine]),
erlang:halt(1);
false ->
"spidermonkey"
end.
WithSpidermonkey = case {lists:keyfind(with_spidermonkey, 1, CouchConfig), JsEngine} of
{{_, "false"}, "spidermonkey"} ->
io:format(standard_error, "Spidermonkey is disabled, select another default js_enigine ~n", []),
erlang:halt(1);
{{_, "false"}, _} ->
false;
{{_, "true"}, _} ->
true
end.
SMVsn = case lists:keyfind(spidermonkey_version, 1, CouchConfig) of
{_, "1.8.5"} ->
"1.8.5";
{_, "60"} ->
"60";
{_, "68"} ->
"68";
{_, "78"} ->
"78";
{_, "86"} ->
"86";
{_, "91"} ->
"91";
undefined ->
"91";
{_, Unsupported} ->
io:format(standard_error, "Unsupported SpiderMonkey version: ~s~n", [Unsupported]),
erlang:halt(1);
false ->
"91"
end.
ConfigH = [
{"SM185", ""},
{"HAVE_JS_GET_STRING_CHARS_AND_LENGTH", "1"},
{"JSSCRIPT_TYPE", "JSObject*"},
{"COUCHJS_NAME", "\"" ++ CouchJSName++ "\""},
{"PACKAGE", "\"apache-couchdb\""},
{"PACKAGE_BUGREPORT", "\"https://github.com/apache/couchdb/issues\""},
{"PACKAGE_NAME", "\"Apache CouchDB\""},
{"PACKAGE_STRING", "\"Apache CouchDB " ++ Version ++ "\""},
{"PACKAGE_VERSION", "\"" ++ Version ++ "\""}
].
CouchJSConfig = case SMVsn of
"78" ->
"priv/couch_js/86/config.h";
"91" ->
"priv/couch_js/86/config.h";
_ ->
"priv/couch_js/" ++ SMVsn ++ "/config.h"
end.
ConfigSrc = [["#define ", K, " ", V, $\n] || {K, V} <- ConfigH].
ConfigBin = iolist_to_binary(ConfigSrc).
case WithSpidermonkey of
true -> ok = CopyIfDifferent(CouchJSConfig, ConfigBin);
false -> ok
end.
MD5Config = case lists:keyfind(erlang_md5, 1, CouchConfig) of
{erlang_md5, true} ->
[{d, 'ERLANG_MD5', true}];
_ ->
[]
end.
ProperConfig = case code:lib_dir(proper) of
{error, bad_name} -> [];
_ -> [{d, 'WITH_PROPER'}]
end.
% The include directories (parameters for the `-I` C compiler flag) are
% considered in the `configure` script as a pre-check for their existence.
% Please keep them in sync.
{JS_CFLAGS, JS_LDFLAGS} = case os:type() of
{win32, _} when SMVsn == "1.8.5" ->
{
"/DXP_WIN",
"mozjs185-1.0.lib"
};
{unix, _} when SMVsn == "1.8.5" ->
{
"-DXP_UNIX -I/usr/include/js -I/usr/local/include/js",
"-L/usr/local/lib -lmozjs185 -lm"
};
{win32, _} when SMVsn == "60" ->
{
"/DXP_WIN",
"mozjs-60.lib"
};
{unix, darwin} when SMVsn == "60" ->
{
"-DXP_UNIX -I/usr/include/mozjs-60 -I/usr/local/include/mozjs-60 -std=c++14",
"-L/usr/local/lib -lmozjs-60 -lm -std=c++14 -lc++"
};
{unix, _} when SMVsn == "60" ->
{
"-DXP_UNIX -I/usr/include/mozjs-60 -I/usr/local/include/mozjs-60 -std=c++14 -Wno-invalid-offsetof",
"-L/usr/local/lib -std=c++14 -lmozjs-60 -lm"
};
{unix, _} when SMVsn == "68" ->
{
"-DXP_UNIX -I/usr/include/mozjs-68 -I/usr/local/include/mozjs-68 -std=c++14 -Wno-invalid-offsetof",
"-L/usr/local/lib -std=c++14 -lmozjs-68 -lm"
};
{unix, _} when SMVsn == "78" ->
{
"-DXP_UNIX -I/usr/include/mozjs-78 -I/usr/local/include/mozjs-78 -std=c++17 -Wno-invalid-offsetof",
"-L/usr/local/lib -std=c++17 -lmozjs-78 -lm"
};
{unix, _} when SMVsn == "86" ->
{
"-DXP_UNIX -I/usr/include/mozjs-86 -I/usr/local/include/mozjs-86 -I/opt/homebrew/include/mozjs-86/ -std=c++17 -Wno-invalid-offsetof",
"-L/usr/local/lib -L /opt/homebrew/lib/ -std=c++17 -lmozjs-86 -lm"
};
{unix, _} when SMVsn == "91" ->
{
"$CFLAGS -DXP_UNIX -I/usr/include/mozjs-91 -I/usr/local/include/mozjs-91 -I/opt/homebrew/include/mozjs-91/ -std=c++17 -Wno-invalid-offsetof",
"$LDFLAGS -L/usr/local/lib -L /opt/homebrew/lib/ -std=c++17 -lmozjs-91 -lm"
};
{win32, _} when SMVsn == "91" ->
{
"/std:c++17 /DXP_WIN",
"$LDFLAGS mozjs-91.lib"
}
end.
CouchJSSrc = case SMVsn of
"1.8.5" -> ["priv/couch_js/1.8.5/*.c"];
"60" -> ["priv/couch_js/60/*.cpp"];
"68" -> ["priv/couch_js/68/*.cpp"];
"78" -> ["priv/couch_js/86/*.cpp"];
"86" -> ["priv/couch_js/86/*.cpp"];
"91" -> ["priv/couch_js/86/*.cpp"]
end.
CouchJSEnv = case SMVsn of
"1.8.5" ->
[
{"CFLAGS", JS_CFLAGS},
{"LDFLAGS", JS_LDFLAGS}
];
_ ->
[
{"CXXFLAGS", JS_CFLAGS},
{"LDFLAGS", JS_LDFLAGS}
]
end.
IcuEnv = [{"DRV_CFLAGS", "$DRV_CFLAGS -DPIC -O2 -fno-common"},
{"DRV_LDFLAGS", "$DRV_LDFLAGS -lm -licuuc -licudata -licui18n -lpthread"},
{"LDFLAGS", "$LDFLAGS"},
{"CFLAGS", "$CFLAGS"}].
IcuDarwinEnv = [{"CFLAGS", "-DXP_UNIX -I/usr/local/opt/icu4c/include -I/opt/homebrew/opt/icu4c/include"},
{"LDFLAGS", "-L/usr/local/opt/icu4c/lib -L/opt/homebrew/opt/icu4c/lib"}].
IcuBsdEnv = [{"CFLAGS", "-DXP_UNIX -I/usr/local/include"},
{"LDFLAGS", "-L/usr/local/lib"}].
IcuWinEnv = [{"CFLAGS", "$DRV_CFLAGS /DXP_WIN"},
{"LDFLAGS", "$LDFLAGS icuin.lib icudt.lib icuuc.lib"}].
ComparePath = "priv/couch_ejson_compare.so".
CompareSrc = ["priv/couch_ejson_compare/*.c"].
SpidermonkeySpecs = case WithSpidermonkey of
true -> [{".*", CouchJSPath, CouchJSSrc, [{env, CouchJSEnv}]}];
false -> []
end.
BaseSpecs = SpidermonkeySpecs ++ [
% ejson_compare
{"darwin", ComparePath, CompareSrc, [{env, IcuEnv ++ IcuDarwinEnv}]},
{"linux", ComparePath, CompareSrc, [{env, IcuEnv}]},
{"bsd", ComparePath, CompareSrc, [{env, IcuEnv ++ IcuBsdEnv}]},
{"win32", ComparePath, CompareSrc, [{env, IcuWinEnv}]}
].
SpawnSpec = [
{"priv/couchspawnkillable", ["priv/spawnkillable/*.c"]}
].
%% hack required until switch to enc/rebar3
PortEnvOverrides = [
{"win32", "EXE_LINK_CXX_TEMPLATE",
"$LINKER $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS /OUT:$PORT_OUT_FILE"}
].
PortSpecs = case os:type() of
{win32, _} ->
BaseSpecs ++ SpawnSpec;
_ ->
{ok, CSK} = file:read_file("priv/spawnkillable/couchspawnkillable.sh"),
ok = CopyIfDifferent("priv/couchspawnkillable", CSK),
os:cmd("chmod +x priv/couchspawnkillable"),
BaseSpecs
end.
PlatformDefines = [
{platform_define, "win32", 'WINDOWS'}
].
AddConfig = [
{port_specs, PortSpecs},
{erl_opts, PlatformDefines ++ [
{d, 'COUCHDB_VERSION', Version},
{d, 'COUCHDB_GIT_SHA', GitSha},
{d, 'COUCHDB_JS_ENGINE', JsEngine},
{d, 'COUCHDB_WITH_SPIDERMONKEY', WithSpidermonkey},
{d, 'COUCHDB_SPIDERMONKEY_VERSION', SMVsn},
{i, "../"}
] ++ MD5Config ++ ProperConfig},
{port_env, PortEnvOverrides},
{eunit_compile_opts, PlatformDefines}
].
lists:foldl(fun({K, V}, CfgAcc) ->
case lists:keyfind(K, 1, CfgAcc) of
{K, Existent} when is_list(Existent) andalso is_list(V) ->
lists:keystore(K, 1, CfgAcc, {K, Existent ++ V});
false ->
lists:keystore(K, 1, CfgAcc, {K, V})
end
end, CONFIG, AddConfig).