Added NIF -> FFI bridge
This commit is contained in:
18
Makefile
Normal file
18
Makefile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
CC=gcc
|
||||||
|
CFLAGS=
|
||||||
|
OBJ = ffi_nif.o
|
||||||
|
TARGET = ffi_nif.so
|
||||||
|
LIBS += -ldl -lffi
|
||||||
|
ERTS_INCLUDE_PATH=/home/josh/Playground/erlangs/erts-6.0/include
|
||||||
|
DIR=c_src
|
||||||
|
|
||||||
|
$(DIR)/%.o: $(DIR)/%.c $(DEPS)
|
||||||
|
$(CC) -c -o $@ $< $(CFLAGS) -I$(ERTS_INCLUDE_PATH)
|
||||||
|
|
||||||
|
$(TARGET): $(DIR)/$(OBJ)
|
||||||
|
$(CC) -shared -o $@ $^ $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
.PHONY : $(TARGET)
|
||||||
|
|
||||||
|
clean :
|
||||||
|
$(RM) $(DIR)/*.o *.so
|
||||||
136
c_src/ffi_nif.c
Normal file
136
c_src/ffi_nif.c
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <erl_nif.h>
|
||||||
|
#include <ffi.h>
|
||||||
|
|
||||||
|
#define MAXLEN 1024
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VOID = 0,
|
||||||
|
STRING,
|
||||||
|
INT
|
||||||
|
} TYPE;
|
||||||
|
|
||||||
|
static void call(int argc, ffi_type **args, void **values, ffi_type* returnType) {
|
||||||
|
ffi_cif cif;
|
||||||
|
int returnValue;
|
||||||
|
|
||||||
|
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argc, returnType, args) == FFI_OK) {
|
||||||
|
ffi_call(&cif, (void*)puts, &returnValue, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ERL_NIF_TERM nif_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
|
||||||
|
{
|
||||||
|
char library[MAXLEN],
|
||||||
|
function[MAXLEN];
|
||||||
|
|
||||||
|
int argumentsLength, valuesLength, returnType, returnValue, i;
|
||||||
|
|
||||||
|
ErlNifCharEncoding encoding = ERL_NIF_LATIN1;
|
||||||
|
|
||||||
|
if (!enif_get_atom(env, argv[0], library, MAXLEN, encoding)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_atom(env, argv[1], function, MAXLEN, encoding)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_list_length(env, argv[2], &argumentsLength)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_int(env, argv[3], &returnType)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_list_length(env, argv[4], &valuesLength)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valuesLength != argumentsLength) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
ffi_type *ffiArgs[argumentsLength], *ffiReturnType = &ffi_type_sint;
|
||||||
|
int args[argumentsLength];
|
||||||
|
void *ffiValues[valuesLength];
|
||||||
|
ERL_NIF_TERM head, tail = argv[2];
|
||||||
|
uint type;
|
||||||
|
|
||||||
|
for (i=0;enif_get_list_cell(env, tail, &head, &tail);i++) {
|
||||||
|
ffi_type *ffiType;
|
||||||
|
|
||||||
|
enif_get_uint(env, head, &type);
|
||||||
|
|
||||||
|
args[i] = type;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case VOID:
|
||||||
|
ffiType = &ffi_type_void;
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
ffiType = &ffi_type_pointer;
|
||||||
|
break;
|
||||||
|
case INT:
|
||||||
|
ffiType = &ffi_type_sint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffiArgs[i] = ffiType;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail = argv[4];
|
||||||
|
|
||||||
|
int intData;
|
||||||
|
char charData[MAXLEN];
|
||||||
|
char *s = charData;
|
||||||
|
|
||||||
|
for (i=0;enif_get_list_cell(env, tail, &head, &tail);i++) {
|
||||||
|
type = args[i];
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case VOID:
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
enif_get_string(env, head, charData, MAXLEN, encoding);
|
||||||
|
|
||||||
|
ffiValues[i] = &s;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case INT:
|
||||||
|
enif_get_int(env, head, &intData);
|
||||||
|
|
||||||
|
ffiValues[i] = &intData;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (returnType) {
|
||||||
|
case VOID:
|
||||||
|
ffiReturnType = &ffi_type_void;
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
ffiReturnType = &ffi_type_pointer;
|
||||||
|
break;
|
||||||
|
case INT:
|
||||||
|
ffiReturnType = &ffi_type_sint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s.%s() %d %d\n", library, function, argumentsLength, returnType);
|
||||||
|
|
||||||
|
call(argumentsLength, ffiArgs, ffiValues, ffiReturnType);
|
||||||
|
|
||||||
|
returnValue = 100;
|
||||||
|
|
||||||
|
return enif_make_int(env, returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErlNifFunc nif_funcs[] = {
|
||||||
|
{"nif_call", 5, nif_call}
|
||||||
|
};
|
||||||
|
|
||||||
|
ERL_NIF_INIT(Elixir.FFI, nif_funcs, NULL, NULL, NULL, NULL)
|
||||||
BIN
c_src/ffi_nif.o
Normal file
BIN
c_src/ffi_nif.o
Normal file
Binary file not shown.
Reference in New Issue
Block a user