I'm having problems linking Erlang to a shared C library (dylib on Mac) using erlang.mk
, and would really like a small amount of help
I'm running a Mac M1 with Erlang installed via kerl
The C library is called Sunvox, a small software synth
https://warmplace.ru/soft/sunvox/sunvox_lib.php
My c_src
structure is as follows -
jhw@my-MacBook-Air myapp % ls -l -R c_src
total 16
drwxr-xr-x 4 jhw staff 128 26 Aug 16:26 sunvox
-rw-r--r-- 1 jhw staff 782 26 Aug 17:04 sunvox_nif.c
c_src/sunvox:
total 0
drwxr-xr-x 3 jhw staff 96 26 Aug 17:15 include
drwxr-xr-x 3 jhw staff 96 26 Aug 16:35 lib
c_src/sunvox/include:
total 104
-rw-r--r--@ 1 jhw staff 49805 26 Aug 16:31 sunvox.h
c_src/sunvox/lib:
total 1504
-rwxr-xr-x@ 1 jhw staff 767321 26 Aug 16:35 libsunvox.dylib
I have been careful to use the ARM version of the dylib
, not the x86 version
c_src/sunvox_nif.c
looks as follows -
jhw@my-MacBook-Air myapp % more c_src/sunvox_nif.c
#include "erl_nif.h"
#include "sunvox.h"
static ERL_NIF_TERM nif_sv_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
int res = sv_init(0, 44100, 2048, 0);
if (res != 0) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, res));
}
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM nif_sv_deinit(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
int res = sv_deinit();
if (res != 0) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, res));
}
return enif_make_atom(env, "ok");
}
static ErlNifFunc nif_funcs[] = {
{"sv_init", 0, nif_sv_init},
{"sv_deinit", 0, nif_sv_deinit}
};
ERL_NIF_INIT(sunvox_nif, nif_funcs, NULL, NULL, NULL, NULL)
My Makefile
looks as follows -
PROJECT = myapp
PROJECT_DESCRIPTION = An Erlang server to wrap the Sunvox developer library as a simple DJing service
PROJECT_VERSION = 0.1.0
CFLAGS += -I$(CURDIR)/c_src/sunvox/include
LDFLAGS += -L$(CURDIR)/c_src/sunvox/lib -lsunvox
C_SRC_TYPE = shared
C_SRC_DIR = $(CURDIR)/c_src
C_SRC_OUTPUT = $(CURDIR)/priv/$(PROJECT)
BUILD_DEPS += relx
include erlang.mk
DYLD_LIBRARY_PATH
is set as follows -
#!/usr/bin/env bash
export DYLD_LIBRARY_PATH=$HOME/work/myapp/c_src/sunvox/lib
Running make clean && make
does the following -
jhw@my-MacBook-Air myapp % make clean && make
erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
GEN clean-app
GEN clean-c_src
GEN coverdata-clean
erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
DEPEND myapp.d
ERLC myapp_app.erl myapp_sunvox_server.erl myapp_sup.erl
APP myapp
C sunvox_nif.c
LD myapp.so
Undefined symbols for architecture arm64:
"_enif_make_atom", referenced from:
_nif_sv_init in sunvox_nif.o
_nif_sv_deinit in sunvox_nif.o
"_enif_make_int", referenced from:
_nif_sv_init in sunvox_nif.o
_nif_sv_deinit in sunvox_nif.o
"_enif_make_tuple", referenced from:
_enif_make_tuple2 in sunvox_nif.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [/Users/jhw/work/myapp/priv/myapp.so] Error 1
I thought it was an erlang.mk
issue but the author of that library says the linker directive in the Makefile
isn't working properly on the M1 -
https://github.com/ninenines/erlang.mk/issues/989
Unfortunately I am not a C expert :(
Can anyone tell me what I need to do to the Makefile
to make this NIF
compile properly on Mac M1?
Thank you