0

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

Justin
  • 4,649
  • 6
  • 33
  • 71

0 Answers0