Add erlang binding (#54)
* add erlang support * add erlang support for windows * add erlang ci for linux and windows
This commit is contained in:
parent
683210d02f
commit
a362da640a
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@ -46,6 +46,15 @@ jobs:
|
|||||||
cd rust
|
cd rust
|
||||||
cargo build --verbose
|
cargo build --verbose
|
||||||
cargo test --verbose
|
cargo test --verbose
|
||||||
|
- uses: erlef/setup-beam@v1
|
||||||
|
with:
|
||||||
|
otp-version: 26.2
|
||||||
|
rebar3-version: "3.22.1"
|
||||||
|
- name: build-test-erlang
|
||||||
|
run: |
|
||||||
|
cd erlang
|
||||||
|
rebar3 compile
|
||||||
|
rebar3 eunit
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
@ -124,6 +133,15 @@ jobs:
|
|||||||
cd rust
|
cd rust
|
||||||
cargo build --verbose
|
cargo build --verbose
|
||||||
cargo test --verbose
|
cargo test --verbose
|
||||||
|
- uses: erlef/setup-beam@v1
|
||||||
|
with:
|
||||||
|
otp-version: 26.2
|
||||||
|
rebar3-version: "3.22.1"
|
||||||
|
- name: build-test-erlang
|
||||||
|
run: |
|
||||||
|
cd erlang
|
||||||
|
rebar3 compile
|
||||||
|
rebar3 eunit
|
||||||
|
|
||||||
qemu:
|
qemu:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
39
README.md
39
README.md
@ -183,6 +183,45 @@ end
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
### ruapu with Erlang
|
||||||
|
|
||||||
|
<table>
|
||||||
|
|
||||||
|
<tr><td>
|
||||||
|
|
||||||
|
Compile ruapu library
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# from source code
|
||||||
|
rebar3 compile
|
||||||
|
```
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Use ruapu in Erlang `rebar3 shell`
|
||||||
|
|
||||||
|
```erlang
|
||||||
|
ruapu:rua().
|
||||||
|
{ok,["neon","vfpv4","asimdrdm","asimdhp","asimddp",
|
||||||
|
"asimdfhm","bf16","i8mm","pmull","crc32","aes","sha1",
|
||||||
|
"sha2","sha3","sha512","amx"]}
|
||||||
|
> ruapu:supports("neon").
|
||||||
|
true
|
||||||
|
> ruapu:supports(neon).
|
||||||
|
true
|
||||||
|
> ruapu:supports(<<"neon">>).
|
||||||
|
true
|
||||||
|
> ruapu:supports("avx2").
|
||||||
|
false
|
||||||
|
> ruapu:supports(avx2).
|
||||||
|
false
|
||||||
|
> ruapu:supports(<<"avx2">>).
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Github-hosted runner result (Linux)</summary>
|
<summary>Github-hosted runner result (Linux)</summary>
|
||||||
|
|
||||||
|
22
erlang/.gitignore
vendored
Normal file
22
erlang/.gitignore
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.rebar3
|
||||||
|
_*
|
||||||
|
.eunit
|
||||||
|
*.o
|
||||||
|
*.beam
|
||||||
|
*.plt
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.erlang.cookie
|
||||||
|
ebin
|
||||||
|
log
|
||||||
|
erl_crash.dump
|
||||||
|
.rebar
|
||||||
|
logs
|
||||||
|
_build
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
rebar3.crashdump
|
||||||
|
*~
|
||||||
|
doc/
|
||||||
|
priv/
|
||||||
|
_build/
|
84
erlang/CMakeLists.txt
Normal file
84
erlang/CMakeLists.txt
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||||
|
project(ruapu_nif C CXX)
|
||||||
|
|
||||||
|
if(NOT DEFINED PRIV_DIR)
|
||||||
|
if(DEFINED MIX_APP_PATH AND NOT "${MIX_APP_PATH}" STREQUAL "")
|
||||||
|
if(WIN32)
|
||||||
|
string(REPLACE "\\" "/" MIX_APP_PATH "${MIX_APP_PATH}")
|
||||||
|
endif()
|
||||||
|
set(PRIV_DIR "${MIX_APP_PATH}/priv")
|
||||||
|
else()
|
||||||
|
set(PRIV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/priv")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
message(STATUS "Using PRIV_DIR: ${PRIV_DIR}")
|
||||||
|
|
||||||
|
if(DEFINED ERTS_INCLUDE_DIR AND NOT "${ERTS_INCLUDE_DIR}" STREQUAL "")
|
||||||
|
set(ERTS_INCLUDE_DIR "${ERTS_INCLUDE_DIR}")
|
||||||
|
else()
|
||||||
|
set(ERTS_INCLUDE_DIR_ONE_LINER "erl -noshell -eval \"io:format('~ts/erts-~ts/include/', [code:root_dir(), erlang:system_info(version)]), halt().\"")
|
||||||
|
if(WIN32)
|
||||||
|
execute_process(COMMAND powershell -command "${ERTS_INCLUDE_DIR_ONE_LINER}" OUTPUT_VARIABLE ERTS_INCLUDE_DIR)
|
||||||
|
else()
|
||||||
|
execute_process(COMMAND bash -c "${ERTS_INCLUDE_DIR_ONE_LINER}" OUTPUT_VARIABLE ERTS_INCLUDE_DIR)
|
||||||
|
endif()
|
||||||
|
set(ERTS_INCLUDE_DIR "${ERTS_INCLUDE_DIR}")
|
||||||
|
endif()
|
||||||
|
message(STATUS "Using ERTS_INCLUDE_DIR: ${ERTS_INCLUDE_DIR}")
|
||||||
|
|
||||||
|
if(UNIX AND APPLE)
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-flat_namespace -undefined dynamic_lookup")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(DEFINED ENV{TARGET_GCC_FLAGS})
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{TARGET_GCC_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
string(REPLACE "\\" "/" C_SRC "${C_SRC}")
|
||||||
|
endif()
|
||||||
|
set(SOURCE_FILES
|
||||||
|
"${C_SRC}/ruapu.c"
|
||||||
|
)
|
||||||
|
if(POLICY CMP0068)
|
||||||
|
cmake_policy(SET CMP0068 NEW)
|
||||||
|
endif()
|
||||||
|
include_directories("${ERTS_INCLUDE_DIR}")
|
||||||
|
|
||||||
|
add_library(ruapu_nif SHARED
|
||||||
|
${SOURCE_FILES}
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
TARGETS ruapu_nif
|
||||||
|
RUNTIME DESTINATION "${PRIV_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(ruapu_nif PROPERTIES PREFIX "")
|
||||||
|
if(NOT WIN32)
|
||||||
|
set_target_properties(ruapu_nif PROPERTIES SUFFIX ".so")
|
||||||
|
endif()
|
||||||
|
set_target_properties(ruapu_nif PROPERTIES
|
||||||
|
INSTALL_RPATH_USE_LINK_PATH TRUE
|
||||||
|
BUILD_WITH_INSTALL_RPATH TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-but-set-variable -Wno-reorder")
|
||||||
|
elseif(UNIX AND APPLE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-reorder-ctor")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-flat_namespace -undefined dynamic_lookup")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /wd4996 /wd4267 /wd4068")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||||
|
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||||
|
endif()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function -Wno-sign-compare -Wno-unused-parameter -Wno-missing-field-initializers -Wno-deprecated-declarations")
|
||||||
|
endif()
|
21
erlang/Makefile
Normal file
21
erlang/Makefile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
ifndef MIX_APP_PATH
|
||||||
|
MIX_APP_PATH=$(shell pwd)
|
||||||
|
endif
|
||||||
|
|
||||||
|
PRIV_DIR = $(MIX_APP_PATH)/priv
|
||||||
|
RUAPU_SO = $(PRIV_DIR)/ruapu_nif.so
|
||||||
|
C_SRC = $(shell pwd)/c_src
|
||||||
|
|
||||||
|
.DEFAULT_GLOBAL := build
|
||||||
|
|
||||||
|
build: $(RUAPU_SO)
|
||||||
|
@echo > /dev/null
|
||||||
|
|
||||||
|
$(RUAPU_SO): $(C_SRC)/ruapu.c
|
||||||
|
@ cmake -S . -B "$(PRIV_DIR)/cmake_ruapu" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DC_SRC=$(C_SRC) \
|
||||||
|
-DMIX_APP_PATH=$(MIX_APP_PATH) \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=$(PRIV_DIR)
|
||||||
|
@ cmake --build "$(PRIV_DIR)/cmake_ruapu" --config Release
|
||||||
|
@ cp "$(PRIV_DIR)/cmake_ruapu/ruapu_nif.so" $(RUAPU_SO)
|
20
erlang/Makefile.win
Normal file
20
erlang/Makefile.win
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
!IFNDEF MIX_APP_PATH
|
||||||
|
MIX_APP_PATH=$(MAKEDIR)
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
PRIV_DIR = $(MIX_APP_PATH)\priv
|
||||||
|
RUAPU_SO = $(PRIV_DIR)\ruapu_nif.dll
|
||||||
|
C_SRC = $(MAKEDIR)\c_src
|
||||||
|
|
||||||
|
build: $(RUAPU_SO)
|
||||||
|
|
||||||
|
$(RUAPU_SO):
|
||||||
|
@ if not exist "$(PRIV_DIR)" mkdir "$(PRIV_DIR)"
|
||||||
|
@ cmake -G "NMake Makefiles" -B"$(PRIV_DIR)\cmake_ruapu" \
|
||||||
|
-DC_SRC=$(C_SRC) \
|
||||||
|
-DMIX_APP_PATH=$(MIX_APP_PATH) \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=$(PRIV_DIR)
|
||||||
|
@ cmake --build "$(PRIV_DIR)\cmake_ruapu" --config Release
|
||||||
|
@ cmake --install "$(PRIV_DIR)\cmake_ruapu" --config Release
|
||||||
|
|
||||||
|
.PHONY: build
|
135
erlang/c_src/ruapu.c
Normal file
135
erlang/c_src/ruapu.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include <erl_nif.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#define RUAPU_IMPLEMENTATION
|
||||||
|
#include "../../ruapu.h"
|
||||||
|
|
||||||
|
ERL_NIF_TERM atom(ErlNifEnv *env, const char *msg) {
|
||||||
|
ERL_NIF_TERM a;
|
||||||
|
if (enif_make_existing_atom(env, msg, &a, ERL_NIF_LATIN1)) {
|
||||||
|
return a;
|
||||||
|
} else {
|
||||||
|
return enif_make_atom(env, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM error(ErlNifEnv *env, const char *msg) {
|
||||||
|
ERL_NIF_TERM error_atom = atom(env, "error");
|
||||||
|
ERL_NIF_TERM msg_term = enif_make_string(env, msg, ERL_NIF_LATIN1);
|
||||||
|
return enif_make_tuple2(env, error_atom, msg_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM ok(ErlNifEnv *env) { return atom(env, "ok"); }
|
||||||
|
|
||||||
|
ERL_NIF_TERM ok_tuple(ErlNifEnv *env, ERL_NIF_TERM term) {
|
||||||
|
return enif_make_tuple2(env, atom(env, "ok"), term);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_string(ErlNifEnv *env, ERL_NIF_TERM term) {
|
||||||
|
char *result = NULL;
|
||||||
|
unsigned len;
|
||||||
|
int ret = enif_get_list_length(env, term, &len);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
result = (char *)enif_alloc(sizeof(char) * (len + 1));
|
||||||
|
ret = enif_get_string(env, term, result, len + 1, ERL_NIF_LATIN1);
|
||||||
|
if (ret > 0) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
enif_free((void *)result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErlNifBinary bin;
|
||||||
|
ret = enif_inspect_binary(env, term, &bin);
|
||||||
|
if (ret) {
|
||||||
|
result = (char *)enif_alloc(sizeof(char) * (bin.size + 1));
|
||||||
|
if (result == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(result, bin.data, bin.size);
|
||||||
|
result[bin.size] = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_get_atom_length(env, term, &len, ERL_NIF_LATIN1);
|
||||||
|
if (ret) {
|
||||||
|
result = (char *)enif_alloc(sizeof(char) * (len + 1));
|
||||||
|
ret = enif_get_atom(env, term, result, len + 1, ERL_NIF_LATIN1);
|
||||||
|
if (ret) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
enif_free((void *)result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ERL_NIF_TERM nif_supports(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]) {
|
||||||
|
const char *isa = get_string(env, argv[0]);
|
||||||
|
if (isa == NULL) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
int supports = ruapu_supports(isa);
|
||||||
|
enif_free((void *)isa);
|
||||||
|
if (supports) {
|
||||||
|
return atom(env, "true");
|
||||||
|
} else {
|
||||||
|
return atom(env, "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ERL_NIF_TERM nif_rua(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]) {
|
||||||
|
const char *const *supported = ruapu_rua();
|
||||||
|
const char *const *supported_start = supported;
|
||||||
|
uint32_t count = 0;
|
||||||
|
while (*supported_start) {
|
||||||
|
supported_start++;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
ERL_NIF_TERM list = enif_make_list(env, 0, NULL);
|
||||||
|
return ok_tuple(env, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM *terms =
|
||||||
|
(ERL_NIF_TERM *)enif_alloc(sizeof(ERL_NIF_TERM) * count);
|
||||||
|
if (terms == NULL) {
|
||||||
|
return error(env, "enif_alloc failed");
|
||||||
|
}
|
||||||
|
supported_start = supported;
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
terms[i] = enif_make_string(env, *supported_start, ERL_NIF_LATIN1);
|
||||||
|
supported_start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM list = enif_make_list_from_array(env, terms, count);
|
||||||
|
enif_free(terms);
|
||||||
|
return ok_tuple(env, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_load(ErlNifEnv *env, void **_sth1, ERL_NIF_TERM _sth2) {
|
||||||
|
ruapu_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_reload(ErlNifEnv *_sth0, void **_sth1, ERL_NIF_TERM _sth2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_upgrade(ErlNifEnv *_sth0, void **_sth1, void **_sth2,
|
||||||
|
ERL_NIF_TERM _sth3) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErlNifFunc nif_functions[] = {
|
||||||
|
{"supports", 1, nif_supports, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
|
{"rua", 0, nif_rua, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
|
};
|
||||||
|
|
||||||
|
ERL_NIF_INIT(ruapu_nif, nif_functions, on_load, on_reload, on_upgrade, NULL);
|
18
erlang/rebar.config
Normal file
18
erlang/rebar.config
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{erl_opts, [debug_info]}.
|
||||||
|
{deps, []}.
|
||||||
|
|
||||||
|
{pre_hooks,
|
||||||
|
[{"(linux|darwin|solaris)", compile, "make"},
|
||||||
|
{"(freebsd)", compile, "gmake"},
|
||||||
|
{"win32", compile, "nmake /F Makefile.win"}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{project_plugins, [rebar3_ex_doc]}.
|
||||||
|
|
||||||
|
{hex, [
|
||||||
|
{doc, #{provider => ex_doc}}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{ex_doc, [
|
||||||
|
{source_url, "https://github.com/nihui/ruapu"}
|
||||||
|
]}.
|
1
erlang/rebar.lock
Normal file
1
erlang/rebar.lock
Normal file
@ -0,0 +1 @@
|
|||||||
|
[].
|
14
erlang/src/ruapu.app.src
Normal file
14
erlang/src/ruapu.app.src
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{application, ruapu,
|
||||||
|
[{description, "ruapu erlang/otp binding"},
|
||||||
|
{vsn, "0.1.0"},
|
||||||
|
{registered, []},
|
||||||
|
{applications,
|
||||||
|
[kernel,
|
||||||
|
stdlib
|
||||||
|
]},
|
||||||
|
{env,[]},
|
||||||
|
{modules, []},
|
||||||
|
|
||||||
|
{licenses, ["MIT"]},
|
||||||
|
{links, []}
|
||||||
|
]}.
|
32
erlang/src/ruapu.erl
Normal file
32
erlang/src/ruapu.erl
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-module(ruapu).
|
||||||
|
-export([rua/0, supports/1]).
|
||||||
|
|
||||||
|
-ifdef(TEST).
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
%% @doc
|
||||||
|
%%
|
||||||
|
%% Get a list of supported features.
|
||||||
|
-spec rua() -> {ok, [string()]} | {error, string()}.
|
||||||
|
rua() ->
|
||||||
|
ruapu_nif:rua().
|
||||||
|
|
||||||
|
%% @doc
|
||||||
|
%%
|
||||||
|
%% Check if a feature is supported.
|
||||||
|
-spec supports(atom() | string() | binary()) -> boolean().
|
||||||
|
supports(ISA) ->
|
||||||
|
ruapu_nif:supports(ISA).
|
||||||
|
|
||||||
|
-ifdef(EUNIT).
|
||||||
|
rua_test() ->
|
||||||
|
?assertMatch({ok, _}, rua()).
|
||||||
|
|
||||||
|
supports_test() ->
|
||||||
|
?assert(supports(<<"binary_non_exists_feature">>) =:= false),
|
||||||
|
?assert(supports("string_non_exists_feature") =:= false),
|
||||||
|
?assert(supports(atom_non_exists_feature) =:= false),
|
||||||
|
{ok, Features} = rua(),
|
||||||
|
?assert(lists:all(fun(Feature) -> supports(Feature) end, Features)).
|
||||||
|
-endif.
|
30
erlang/src/ruapu_nif.erl
Normal file
30
erlang/src/ruapu_nif.erl
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-module(ruapu_nif).
|
||||||
|
-export([supports/1, rua/0]).
|
||||||
|
|
||||||
|
-on_load(init/0).
|
||||||
|
|
||||||
|
-define(APPNAME, ruapu).
|
||||||
|
-define(LIBNAME, ruapu_nif).
|
||||||
|
|
||||||
|
init() ->
|
||||||
|
SoName = case code:priv_dir(?APPNAME) of
|
||||||
|
{error, bad_name} ->
|
||||||
|
case filelib:is_dir(filename:join(["..", priv])) of
|
||||||
|
true ->
|
||||||
|
filename:join(["..", priv, ?LIBNAME]);
|
||||||
|
_ ->
|
||||||
|
filename:join([priv, ?LIBNAME])
|
||||||
|
end;
|
||||||
|
Dir ->
|
||||||
|
filename:join(Dir, ?LIBNAME)
|
||||||
|
end,
|
||||||
|
erlang:load_nif(SoName, 0).
|
||||||
|
|
||||||
|
not_loaded(Line) ->
|
||||||
|
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
|
||||||
|
|
||||||
|
supports(_ISA) ->
|
||||||
|
not_loaded(?LINE).
|
||||||
|
|
||||||
|
rua() ->
|
||||||
|
not_loaded(?LINE).
|
Loading…
Reference in New Issue
Block a user