aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/configure.in14
-rw-r--r--erts/doc/src/erl_nif.xml2
-rw-r--r--erts/emulator/Makefile.in36
-rw-r--r--erts/emulator/beam/erl_nif.c18
-rw-r--r--erts/emulator/beam/erl_nif.h15
-rwxr-xr-xerts/emulator/beam/global.h6
-rw-r--r--erts/emulator/beam/utils.c21
-rwxr-xr-xerts/emulator/utils/make_driver_tab55
8 files changed, 150 insertions, 17 deletions
diff --git a/erts/configure.in b/erts/configure.in
index 64436e933c..3b4417d10e 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -419,6 +419,11 @@ else
esac
fi
+AC_ARG_ENABLE(static-nifs,
+AS_HELP_STRING([--enable-static-nifs], [link nifs statically. If yes then all nifs in all Erlang/OTP applications will be statically linked into the main binary. It is also possible to give a list of nifs that should be linked statically. The list should be a comma seperated and contain the absolute path to a .a archive for each nif that is to be statically linked. The name of the .a archive has to be the same as the name of the nif. Note that you have to link any external dependencies that the nifs have to the main binary, so for the crypto nif you want to pass LIBS=-lcrypto to configure.]),
+ STATIC_NIFS="$enableval",
+ STATIC_NIFS=no)
+AC_SUBST(STATIC_NIFS)
dnl ----------------------------------------------------------------------
dnl Checks for programs.
@@ -457,7 +462,7 @@ dnl
extra_flags="-I${ERL_TOP}/erts/$host $OTP_EXTRA_FLAGS"
CFLAGS="$CFLAGS $extra_flags"
-DEBUG_CFLAGS="-g $CPPFLAGS $extra_flags"
+DEBUG_CFLAGS="-g $CPPFLAGS $extra_flags $DEBUG_CFLAGS"
DEBUG_FLAGS=-g
dnl
@@ -3597,6 +3602,7 @@ fi
DED_EMU_THR_DEFS=$EMU_THR_DEFS
DED_CFLAGS="$CFLAGS $CPPFLAGS"
if test "x$GCC" = xyes; then
+ DED_STATIC_CFLAGS="$DED_CFLAGS"
DED_CFLAGS="$DED_CFLAGS -fPIC"
fi
@@ -3604,11 +3610,14 @@ DED_EXT=so
case $host_os in
win32) DED_EXT=dll;;
darwin*)
- DED_CFLAGS="$DED_CFLAGS -fno-common";;
+ DED_CFLAGS="$DED_CFLAGS -fno-common"
+ DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -fno-common";;
*)
;;
esac
+DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -DSTATIC_ERLANG_NIF -DSTATIC_ERLANG_DRIVER"
+
# If DED_LD is set in environment, we expect all DED_LD* variables
# to be specified (cross compiling)
if test "x$DED_LD" = "x"; then
@@ -3718,6 +3727,7 @@ fi
AC_SUBST(DED_EXT)
AC_SUBST(DED_SYS_INCLUDE)
AC_SUBST(DED_CFLAGS)
+AC_SUBST(DED_STATIC_CFLAGS)
AC_SUBST(DED_LD)
AC_SUBST(DED_LDFLAGS)
AC_SUBST(DED_LD_FLAG_RUNTIME_LIBRARY_PATH)
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index 01651aa83f..7ac8181d47 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -330,6 +330,8 @@ ok
<c>upgrade</c> will be called to initialize the library.
<c>unload</c> is called to release the library. They are all
described individually below.</p>
+ <p>If compiling a nif for static inclusion via --enable-static-nifs you
+ have to define STATIC_ERLANG_NIF before the ERL_NIF_INIT declaration.</p>
</item>
<tag><marker id="load"/>int (*load)(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)</tag>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 9751982103..db5642b9c3 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -136,6 +136,19 @@ endif
endif
endif
+STATIC_NIFS=@STATIC_NIFS@
+ifneq ($(STATIC_NIFS),no)
+ifeq ($(STATIC_NIFS),yes)
+STATIC_NIFS=$(ERL_TOP)/lib/asn1/priv/lib/$(TARGET)/asn1rt_nif.a \
+ $(ERL_TOP)/lib/crypto/priv/lib/$(TARGET)/crypto$(TYPEMARKER).a
+endif
+comma:=,
+space:=
+space+=
+STATIC_NIFS:=$(subst $(comma),$(space),$(STATIC_NIFS))
+endif
+
+
#
# NOTE: When adding a new type update ERL_BUILD_TYPE_MARKER in sys/unix/sys.c
#
@@ -557,8 +570,8 @@ $(TARGET)/erl_version.h: ../vsn.mk
GENERATE += $(TARGET)/erl_version.h
# driver table
-$(TTF_DIR)/driver_tab.c: Makefile.in
- $(gen_verbose)LANG=C $(PERL) utils/make_driver_tab -o $@ $(DRV_OBJS)
+$(TTF_DIR)/driver_tab.c: Makefile.in utils/make_driver_tab
+ $(gen_verbose)LANG=C $(PERL) utils/make_driver_tab -o $@ $(STATIC_NIF_LIBS) $(DRV_OBJS)
GENERATE += $(TTF_DIR)/driver_tab.c
@@ -797,6 +810,17 @@ endif
DRV_OBJS += $(OBJDIR)/ttsl_drv.o
+ifneq ($(STATIC_NIFS),no)
+STATIC_NIF_LIBS = $(STATIC_NIFS)
+DEPLIBS += $(STATIC_NIF_LIBS)
+
+$(STATIC_NIF_LIBS):
+ $(MAKE) BUILD_STATIC_LIBS=1 TYPE=$(TYPE) -C $(ERL_TOP)/lib/ static_lib
+
+else
+STATIC_NIF_LIBS=
+endif
+
ifeq ($(ERTS_ENABLE_KERNEL_POLL),yes)
OS_OBJS += $(OBJDIR)/erl_poll.kp.o \
$(OBJDIR)/erl_check_io.kp.o \
@@ -935,18 +959,18 @@ $(OBJDIR)/hipe_arm.o: hipe/hipe_arm.c
# ----------------------------------------------------------------------
# The emulator itself
+#
ifeq ($(TARGET), win32)
# Only the basic erlang to begin with eh?
$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
$(ld_verbose)$(PURIFY) $(LD) -dll -def:sys/$(ERLANG_OSTYPE)/erl.def -implib:$(BINDIR)/erl_dll.lib -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
- $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(LIBS)
+ $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(STATIC_NIF_LIBS) $(LIBS)
else
-
-
$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
$(ld_verbose)$(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
- $(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(LIBS)
+ $(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) \
+ $(STATIC_NIF_LIBS) $(LIBS)
endif
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 48f8be8dd3..673012a9af 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1213,7 +1213,8 @@ static void close_lib(struct erl_module_nif* lib)
lib->entry->unload(&env, lib->priv_data);
post_nif_noproc(&env);
}
- erts_sys_ddll_close(lib->handle);
+ if (!erts_is_static_nif(lib->handle))
+ erts_sys_ddll_close(lib->handle);
lib->handle = NULL;
}
@@ -1564,7 +1565,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
static const char upgrade[] = "upgrade";
char* lib_name = NULL;
void* handle = NULL;
- void* init_func;
+ void* init_func = NULL;
ErlNifEntry* entry = NULL;
ErlNifEnv env;
int len, i, err;
@@ -1577,6 +1578,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
int veto;
struct erl_module_nif* lib = NULL;
int reload_warning = 0;
+ char tmp_buf[255];
len = list_length(BIF_ARG_1);
if (len < 0) {
@@ -1613,13 +1615,18 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
mod=erts_get_module(mod_atom, erts_active_code_ix());
ASSERT(mod != NULL);
+ init_func = erts_static_nif_get_nif_init(erts_basename(lib_name,tmp_buf));
+ if (init_func != NULL)
+ handle = init_func;
+
if (!in_area(caller, mod->curr.code, mod->curr.code_length)) {
ASSERT(in_area(caller, mod->old.code, mod->old.code_length));
ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old "
"module '%T' not allowed", mod_atom);
}
- else if ((err=erts_sys_ddll_open2(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) {
+ else if (init_func == NULL &&
+ (err=erts_sys_ddll_open2(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) {
const char slogan[] = "Failed to load NIF library";
if (strstr(errdesc.str, lib_name) != NULL) {
ret = load_nif_error(BIF_P, "load_failed", "%s: '%s'", slogan, errdesc.str);
@@ -1628,7 +1635,8 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ret = load_nif_error(BIF_P, "load_failed", "%s %s: '%s'", slogan, lib_name, errdesc.str);
}
}
- else if (erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) {
+ else if (init_func == NULL &&
+ erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) {
ret = load_nif_error(BIF_P, bad_lib, "Failed to find library init"
" function: '%s'", errdesc.str);
@@ -1784,7 +1792,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
if (lib != NULL) {
erts_free(ERTS_ALC_T_NIF, lib);
}
- if (handle != NULL) {
+ if (handle != NULL && !erts_is_static_nif(handle)) {
erts_sys_ddll_close(handle);
}
erts_sys_ddll_free_error(&errdesc);
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index 8006741a63..5f4dc21d5c 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -168,7 +168,7 @@ extern TWinDynNifCallbacks WinDynNifCallbacks;
# undef ERL_NIF_API_FUNC_DECL
#endif
-#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) && !defined(STATIC_ERLANG_DRIVER)
+#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) && !defined(STATIC_ERLANG_DRIVER) && !defined(STATIC_ERLANG_NIF)
# define ERL_NIF_API_FUNC_MACRO(NAME) (WinDynNifCallbacks.NAME)
# include "erl_nif_api_funcs.h"
/* note that we have to keep ERL_NIF_API_FUNC_MACRO defined */
@@ -180,15 +180,22 @@ extern TWinDynNifCallbacks WinDynNifCallbacks;
# undef ERL_NIF_API_FUNC_DECL
#endif
-
#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
# define ERL_NIF_INIT_GLOB TWinDynNifCallbacks WinDynNifCallbacks;
-# define ERL_NIF_INIT_DECL(MODNAME) __declspec(dllexport) ErlNifEntry* nif_init(TWinDynNifCallbacks* callbacks)
+# ifdef STATIC_ERLANG_NIF
+# define ERL_NIF_INIT_DECL(MODNAME) __declspec(dllexport) ErlNifEntry* MODNAME ## _nif_init(TWinDynNifCallbacks* callbacks)
+# else
+# define ERL_NIF_INIT_DECL(MODNAME) __declspec(dllexport) ErlNifEntry* nif_init(TWinDynNifCallbacks* callbacks)
+# endif
# define ERL_NIF_INIT_BODY memcpy(&WinDynNifCallbacks,callbacks,sizeof(TWinDynNifCallbacks))
#else
# define ERL_NIF_INIT_GLOB
# define ERL_NIF_INIT_BODY
-# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* nif_init(void)
+# ifdef STATIC_ERLANG_NIF
+# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* MODNAME ## _nif_init(void)
+# else
+# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* nif_init(void)
+# endif
#endif
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 7f7b6f5d1e..2acc86cf42 100755
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -852,11 +852,17 @@ Port *erts_get_heart_port(void);
void erts_lcnt_enable_io_lock_count(int enable);
#endif
+/* driver_tab.c */
+typedef void *(*ErtsStaticNifInitFPtr)(void);
+ErtsStaticNifInitFPtr erts_static_nif_get_nif_init(const char *name);
+int erts_is_static_nif(void *handle);
+
/* erl_drv_thread.c */
void erl_drv_thr_init(void);
/* utils.c */
void erts_cleanup_offheap(ErlOffHeap *offheap);
+const char *erts_basename(const char* path, char* buff);
Uint64 erts_timestamp_millis(void);
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index c71f8f0712..6293286c75 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -4019,6 +4019,27 @@ erts_smp_ensure_later_interval_acqb(erts_interval_t *icp, Uint64 ic)
#endif
}
+const char *erts_basename(const char* path, char* buff) {
+ /* This function is not compliant with bash basename. Edge cases like "//"
+ and "/path//" do not work properly.
+ */
+ int i;
+ int len = strlen(path);
+ const char *basename = path;
+ for (i = 0; path[i] != '\0'; i++) {
+ if (path[i] == '/') {
+ if (path[i+1] == '\0') {
+ memcpy(buff,basename,len - (basename-path));
+ buff[len - (basename-path)-1] = '\0';
+ basename = buff;
+ break;
+ } else { basename = path+i;}
+ }
+ }
+ if (basename == path)
+ return path;
+ return basename+1;
+}
/*
* A millisecond timestamp without time correction where there's no hrtime
diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab
index fbbfa3e49e..06928a3a4a 100755
--- a/erts/emulator/utils/make_driver_tab
+++ b/erts/emulator/utils/make_driver_tab
@@ -27,7 +27,9 @@ use File::Basename;
# usage: make_driver_tab [-o filename] drivers...
my $file = "";
+my $nif = "";
my @drivers = ();
+my @nifs = ();
while (@ARGV) {
my $d = shift;
@@ -35,6 +37,12 @@ while (@ARGV) {
$file = shift or die("-o requires argument");
next;
}
+ if ( $d =~ /^.*\.a$/ ) {
+ $d = basename $d;
+ $d =~ s/\.a$//; # strip .a
+ push(@nifs, $d);
+ next;
+ }
$d = basename $d;
$d =~ s/drv(\..*|)$//; # strip drv.* or just drv
push(@drivers, $d);
@@ -52,6 +60,7 @@ print <<EOF;
#include <stdio.h>
#include "global.h"
+
EOF
# "extern" declarations
@@ -68,4 +77,50 @@ foreach (@drivers) {
print " NULL\n};\n";
+print <<EOF;
+
+typedef struct ErtsStaticNifEntry_ {
+ const char *nif_name;
+ ErtsStaticNifInitFPtr nif_init;
+} ErtsStaticNifEntry;
+
+EOF
+
+# prototypes
+foreach (@nifs) {
+ my $d = ${_};
+ $d =~ s/\.debug//; # strip .debug
+ print "void *".$d."_nif_init(void);\n";
+}
+
+# The array itself
+print "static ErtsStaticNifEntry static_nif_tab[DRIVER_TAB_SIZE] =\n{\n";
+
+foreach (@nifs) {
+ my $d = ${_};
+ $d =~ s/\.debug//; # strip .debug
+ print "{\"${_}\",&".$d."_nif_init},\n";
+}
+
+print " {NULL,NULL}\n};\n";
+
+print <<EOF;
+ErtsStaticNifInitFPtr erts_static_nif_get_nif_init(const char *name) {
+ int i;
+ for (i = 0; static_nif_tab[i].nif_name != NULL; i++)
+ if (strcmp(name,static_nif_tab[i].nif_name) == 0)
+ return static_nif_tab[i].nif_init;
+ return NULL;
+}
+
+int erts_is_static_nif(void *handle) {
+ int i;
+ for (i = 0; static_nif_tab[i].nif_name != NULL; i++)
+ if (((void*)static_nif_tab[i].nif_init) == handle)
+ return 1;
+ return 0;
+}
+
+EOF
+
# That's it