From 20e0509d4e04fada3019639bc82d78b89f06b0fc Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 13 Aug 2013 17:14:11 +0200 Subject: erts: Add option to include nifs statically Both crypto and asn1 are supported. --- erts/configure.in | 14 ++++++- erts/doc/src/erl_nif.xml | 2 + erts/emulator/Makefile.in | 36 +++++++++++++--- erts/emulator/beam/erl_nif.c | 18 +++++--- erts/emulator/beam/erl_nif.h | 15 +++++-- erts/emulator/beam/global.h | 6 +++ erts/emulator/beam/utils.c | 21 ++++++++++ erts/emulator/utils/make_driver_tab | 55 ++++++++++++++++++++++++ lib/Makefile | 27 ++++++------ lib/asn1/Makefile | 2 + lib/asn1/c_src/Makefile | 38 ++++++++++++++--- lib/asn1/c_src/asn1_erl_nif.c | 84 ++++++++++++++++++------------------- lib/asn1/src/asn1rt_nif.erl | 2 +- lib/crypto/Makefile | 1 + lib/crypto/c_src/Makefile.in | 34 +++++++++++++++ make/otp_ded.mk.in | 1 + make/otp_subdir.mk | 4 +- make/run_make.mk | 2 +- 18 files changed, 282 insertions(+), 80 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 upgrade will be called to initialize the library. unload is called to release the library. They are all described individually below.

+

If compiling a nif for static inclusion via --enable-static-nifs you + have to define STATIC_ERLANG_NIF before the ERL_NIF_INIT declaration.

int (*load)(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) 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 < #include "global.h" + EOF # "extern" declarations @@ -68,4 +77,50 @@ foreach (@drivers) { print " NULL\n};\n"; +print <data; @@ -502,7 +502,7 @@ int per_realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) { return ASN1_OK; } -int per_insert_most_sign_bits(int no_bits, unsigned char val, +static int per_insert_most_sign_bits(int no_bits, unsigned char val, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; @@ -523,7 +523,7 @@ int per_insert_most_sign_bits(int no_bits, unsigned char val, return ASN1_OK; } -int per_insert_least_sign_bits(int no_bits, unsigned char val, +static int per_insert_least_sign_bits(int no_bits, unsigned char val, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; int ret = 0; @@ -552,7 +552,7 @@ int per_insert_least_sign_bits(int no_bits, unsigned char val, /* per_pad_bits adds no_bits bits in the buffer that output_ptr points at. */ -int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { +static int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; int ret = 0; @@ -575,7 +575,7 @@ int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { The unused parameter tells how many bits that are not set in the actual byte in the output buffer. If desired_no is more bits than the input buffer has in no_bytes bytes, then zero bits is padded.*/ -int per_insert_bits_as_bits(int desired_no, int no_bytes, +static int per_insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char val; @@ -615,7 +615,7 @@ int per_insert_bits_as_bits(int desired_no, int no_bytes, } /* per_insert_octets_as_bits_exact_len */ -int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, +static int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, unsigned char **in_ptr, unsigned char **ptr, int *unused) { int ret = 0; int ret2 = 0; @@ -653,7 +653,7 @@ int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, otherwise the function returns ASN1_ERROR. The output buffer is concatenated without alignment. */ -int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, +static int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -693,7 +693,7 @@ int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, into the output buffer, *output_ptr. Before the first byte is inserted the input buffer is aligned. */ -int per_insert_octets(int no_bytes, unsigned char **input_ptr, +static int per_insert_octets(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -718,7 +718,7 @@ int per_insert_octets(int no_bytes, unsigned char **input_ptr, /* per_insert_octets_unaligned inserts bytes from the input buffer, *input_ptr, into the output buffer, *output_ptr.No alignment is done. */ -int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, +static int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -742,7 +742,7 @@ int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, return no_bytes; } -int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, +static int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused, int in_unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -835,7 +835,7 @@ int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, * is the empty binary. * If some error occured during the decoding of the in_buf an error is returned. */ -int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, +static int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, int in_buf_len, unsigned int *err_pos) { int maybe_ret; int ib_index = 0; @@ -857,7 +857,7 @@ int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, return ASN1_OK; } -int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, +static int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, int *ib_index, int in_buf_len) { int maybe_ret; int form; @@ -889,7 +889,7 @@ int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, * decode_tag decodes the BER encoded tag in in_buf and creates an * nif term tag */ -int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, +static int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, int in_buf_len, int *ib_index) { int tag_no, tmp_tag, form; @@ -936,7 +936,7 @@ int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, * in_buf and puts the value part in the decode_buf as an Erlang * nif term into value */ -int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, +static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, int *ib_index, int form, int in_buf_len) { int maybe_ret; unsigned int len = 0; @@ -1012,7 +1012,7 @@ struct ber_encode_mem_chunk { char *curr; }; -int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) { +static int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) { const ERL_NIF_TERM *tv; unsigned int form; @@ -1087,7 +1087,7 @@ int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned i return ASN1_OK; } -int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form, +static int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form, mem_chunk_t **curr, unsigned int *count) { unsigned int class_tag_no, head_tag; if (!enif_get_uint(env, tag, &class_tag_no)) @@ -1122,7 +1122,7 @@ int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form, } } -int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) { +static int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) { if (size < 128) { if (ber_check_memory(curr, 1u)) return ASN1_ERROR; @@ -1150,7 +1150,7 @@ int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) { return ASN1_OK; } -mem_chunk_t *ber_new_chunk(unsigned int length) { +static mem_chunk_t *ber_new_chunk(unsigned int length) { mem_chunk_t *new = enif_alloc(sizeof(mem_chunk_t)); if (new == NULL) return NULL; @@ -1165,7 +1165,7 @@ mem_chunk_t *ber_new_chunk(unsigned int length) { return new; } -void ber_free_chunks(mem_chunk_t *chunk) { +static void ber_free_chunks(mem_chunk_t *chunk) { mem_chunk_t *curr, *next = chunk; while (next != NULL) { curr = next; @@ -1175,7 +1175,7 @@ void ber_free_chunks(mem_chunk_t *chunk) { } } -int ber_check_memory(mem_chunk_t **curr, unsigned int needed) { +static int ber_check_memory(mem_chunk_t **curr, unsigned int needed) { mem_chunk_t *new; if ((*curr)->curr-needed >= (*curr)->top) return ASN1_OK; diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl index c1879e3dcf..1a44f1a27c 100644 --- a/lib/asn1/src/asn1rt_nif.erl +++ b/lib/asn1/src/asn1rt_nif.erl @@ -30,7 +30,7 @@ -define(ASN1_NIF_VSN,1). load_nif() -> - LibBaseName = "asn1_erl_nif", + LibBaseName = "asn1rt_nif", PrivDir = code:priv_dir(asn1), LibName = case erlang:system_info(build_type) of opt -> diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile index 13eebea6a9..2adcfd7f31 100644 --- a/lib/crypto/Makefile +++ b/lib/crypto/Makefile @@ -24,6 +24,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # SUB_DIRECTORIES = src c_src doc/src +static_lib: SUB_DIRECTORIES = c_src include vsn.mk VSN = $(CRYPTO_VSN) diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index a20ddff05c..124d088056 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -70,6 +70,10 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN) CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o CALLBACK_OBJS = $(OBJDIR)/crypto_callback$(TYPEMARKER).o NIF_MAKEFILE = $(PRIVDIR)/Makefile +CRYPTO_STATIC_OBJS = $(OBJDIR)/crypto_static$(TYPEMARKER).o\ + $(OBJDIR)/crypto_callback_static$(TYPEMARKER).o + +NIF_ARCHIVE = $(LIBDIR)/crypto$(TYPEMARKER).a ifeq ($(findstring win32,$(TARGET)), win32) NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).dll @@ -97,7 +101,24 @@ CALLBACK_OBJS = CALLBACK_LIB = endif +ifeq ($(USING_VC),yes) +AR_OUT=-out: +AR_FLAGS= +else +AR_OUT= +ifeq ($(V),0) +AR_FLAGS=rc +else +AR_FLAGS=rcv +endif +endif + +ifndef RANLIB +RANLIB=true +endif + ALL_CFLAGS = $(TYPE_FLAGS) $(EXTRA_FLAGS) $(INCLUDES) +ALL_STATIC_CFLAGS = $(DED_STATIC_CFLAGS) $(INCLUDES) # ---------------------------------------------------- # Targets @@ -107,6 +128,8 @@ _create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR)) debug opt valgrind: $(NIF_LIB) $(CALLBACK_LIB) +static_lib: $(NIF_ARCHIVE) + $(OBJDIR)/%$(TYPEMARKER).o: %.c $(V_at)$(INSTALL_DIR) $(OBJDIR) $(V_CC) -c -o $@ $(ALL_CFLAGS) $< @@ -115,6 +138,14 @@ $(LIBDIR)/crypto$(TYPEMARKER).so: $(CRYPTO_OBJS) $(V_at)$(INSTALL_DIR) $(LIBDIR) $(V_LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB) +$(OBJDIR)/%_static$(TYPEMARKER).o: %.c + $(V_at)$(INSTALL_DIR) $(OBJDIR) + $(V_CC) -c -o $@ $(ALL_STATIC_CFLAGS) $< + +$(LIBDIR)/crypto$(TYPEMARKER).a: $(CRYPTO_STATIC_OBJS) + $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(CRYPTO_STATIC_OBJS) + $(V_RANLIB) $@ + $(LIBDIR)/crypto$(TYPEMARKER).dll: $(CRYPTO_OBJS) $(V_at)$(INSTALL_DIR) $(LIBDIR) $(V_LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(CRYPTO_OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) @@ -145,8 +176,11 @@ else rm -f $(LIBDIR)/crypto_callback.valgrind.so endif rm -f $(OBJDIR)/crypto.o + rm -f $(OBJDIR)/crypto_static.o rm -f $(OBJDIR)/crypto.debug.o + rm -f $(OBJDIR)/crypto_static.debug.o rm -f $(OBJDIR)/crypto.valgrind.o + rm -f $(OBJDIR)/crypto_static.valgrind.o rm -f $(OBJDIR)/crypto_callback.o rm -f $(OBJDIR)/crypto_callback.debug.o rm -f $(OBJDIR)/crypto_callback.valgrind.o diff --git a/make/otp_ded.mk.in b/make/otp_ded.mk.in index 0c9a8a087f..c534209a25 100644 --- a/make/otp_ded.mk.in +++ b/make/otp_ded.mk.in @@ -38,6 +38,7 @@ DED_THR_DEFS = @DED_THR_DEFS@ DED_EMU_THR_DEFS = @DED_EMU_THR_DEFS@ DED_WARN_FLAGS = @WFLAGS@ DED_CFLAGS = @WERRORFLAGS@ @WFLAGS@ @DED_EMU_THR_DEFS@ @DED_CFLAGS@ +DED_STATIC_CFLAGS = @WERRORFLAGS@ @WFLAGS@ @DED_EMU_THR_DEFS@ @DED_STATIC_CFLAGS@ DED_LIBS = @LIBS@ DED_EXT = @DED_EXT@ ERLANG_OSTYPE = @ERLANG_OSTYPE@ diff --git a/make/otp_subdir.mk b/make/otp_subdir.mk index 07294c272d..f31ab05c87 100644 --- a/make/otp_subdir.mk +++ b/make/otp_subdir.mk @@ -19,12 +19,12 @@ # Make include file for otp .PHONY: debug opt release docs release_docs tests release_tests \ - clean depend valgrind + clean depend valgrind static_lib # # Targets that don't affect documentation directories # -opt debug release docs release_docs tests release_tests clean depend valgrind: +opt debug release docs release_docs tests release_tests clean depend valgrind static_lib: @set -e ; \ app_pwd=`pwd` ; \ if test -f vsn.mk; then \ diff --git a/make/run_make.mk b/make/run_make.mk index bb0da6743c..01ab257006 100644 --- a/make/run_make.mk +++ b/make/run_make.mk @@ -37,7 +37,7 @@ plain smp frag smp_frag: $(make_verbose)$(MAKE) -f $(TARGET)/Makefile FLAVOR=$@ clean generate depend docs release release_spec release_docs release_docs_spec \ - tests release_tests release_tests_spec: + tests release_tests release_tests_spec static_lib: $(make_verbose)$(MAKE) -f $(TARGET)/Makefile $@ -- cgit v1.2.3 From 94d174949635cd4e641daaac0a7df98ea35f2c55 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 15 Aug 2013 17:04:52 +0200 Subject: erts: Add support for static linked-in drivers None of the OTP linked-in driver are supported --- erts/configure.in | 6 ++++++ erts/doc/src/driver_entry.xml | 2 ++ erts/emulator/Makefile.in | 42 ++++++++++++++++++++++++++++--------- erts/emulator/beam/erl_driver.h | 14 +++++++++---- erts/emulator/beam/global.h | 1 + erts/emulator/beam/io.c | 1 + erts/emulator/utils/make_driver_tab | 42 ++++++++++++++++++++++++++++++++----- 7 files changed, 89 insertions(+), 19 deletions(-) diff --git a/erts/configure.in b/erts/configure.in index 3b4417d10e..4e60b27ee9 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -425,6 +425,12 @@ AS_HELP_STRING([--enable-static-nifs], [link nifs statically. If yes then all ni STATIC_NIFS=no) AC_SUBST(STATIC_NIFS) +AC_ARG_ENABLE(static-drivers, +AS_HELP_STRING([--enable-static-drivers], [comma seperated list of linked-in drivers to link statically with the main binary. The list should contain the absolute path to a .a archive for each driver that is to be statically linked. The name of the .a archive has to be the same as the name of the driver.]), + STATIC_DRIVERS="$enableval", + STATIC_DRIVERS=no) +AC_SUBST(STATIC_DRIVERS) + dnl ---------------------------------------------------------------------- dnl Checks for programs. dnl ---------------------------------------------------------------------- diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml index 69a4dea466..48dfcb09b1 100644 --- a/erts/doc/src/driver_entry.xml +++ b/erts/doc/src/driver_entry.xml @@ -110,6 +110,8 @@

When the driver has passed the driver_entry over to the emulator, the driver is not allowed to modify the driver_entry.

+

If compiling a driver for static inclusion via --enable-static-drivers you + have to define STATIC_ERLANG_DRIVER before the DRIVER_INIT declaration.

Do not declare the driver_entry const. This since the emulator needs to modify the handle, and the handle2 diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index db5642b9c3..048e92baad 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -136,18 +136,27 @@ endif endif endif +comma:=, +space:= +space+= + 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 +STATIC_DRIVERS=@STATIC_DRIVERS@ +ifneq ($(STATIC_DRIVERS),no) +ifeq ($(STATIC_DRIVERS),yes) +STATIC_DRIVERS= +endif +STATIC_DRIVERS:=$(subst $(comma),$(space),$(STATIC_DRIVERS)) +endif + # # NOTE: When adding a new type update ERL_BUILD_TYPE_MARKER in sys/unix/sys.c @@ -571,7 +580,7 @@ GENERATE += $(TARGET)/erl_version.h # driver table $(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) + $(gen_verbose)LANG=C $(PERL) utils/make_driver_tab -o $@ -nifs $(STATIC_NIF_LIBS) -drivers $(DRV_OBJS) $(STATIC_DRIVER_LIBS) GENERATE += $(TTF_DIR)/driver_tab.c @@ -813,14 +822,25 @@ endif 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 - +COMPILE_STATIC_LIBS = yes else STATIC_NIF_LIBS= endif +ifneq ($(STATIC_DRIVERS),no) +STATIC_DRIVER_LIBS = $(STATIC_DRIVERS) +DEPLIBS += $(STATIC_DRIVER_LIBS) +COMPILE_STATIC_LIBS = yes +else +STATIC_DRIVER_LIBS= +endif + +ifeq ($(COMPILE_STATIC_LIBS),yes) + +$(STATIC_NIF_LIBS) $(STATIC_DRIVER_LIBS): + $(MAKE) BUILD_STATIC_LIBS=1 TYPE=$(TYPE) -C $(ERL_TOP)/lib/ static_lib +endif + ifeq ($(ERTS_ENABLE_KERNEL_POLL),yes) OS_OBJS += $(OBJDIR)/erl_poll.kp.o \ $(OBJDIR)/erl_check_io.kp.o \ @@ -965,12 +985,14 @@ 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) $(STATIC_NIF_LIBS) $(LIBS) + $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(STATIC_NIF_LIBS) \ + $(STATIC_DRIVER_LIBS) $(LIBS) else $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) + echo $(DEPLIBS) $(ld_verbose)$(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \ $(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) \ - $(STATIC_NIF_LIBS) $(LIBS) + $(STATIC_NIF_LIBS) $(STATIC_DRIVER_LIBS) $(LIBS) endif diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index e280563de1..f43f5a766e 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -365,17 +365,23 @@ typedef struct erl_drv_entry { * It must initialize a ErlDrvEntry structure and return a pointer to it. */ +#ifdef STATIC_ERLANG_DRIVER +# define ERLANG_DRIVER_NAME(NAME) NAME ## _driver_init +#else +# define ERLANG_DRIVER_NAME(NAME) driver_init +#endif + /* For windows dynamic drivers */ #ifndef ERL_DRIVER_TYPES_ONLY #if defined(__WIN32__) # define DRIVER_INIT(DRIVER_NAME) \ - __declspec(dllexport) ErlDrvEntry* driver_init(void); \ - __declspec(dllexport) ErlDrvEntry* driver_init(void) + __declspec(dllexport) ErlDrvEntry* ERLANG_DRIVER_NAME(DRIVER_NAME)(void); \ + __declspec(dllexport) ErlDrvEntry* ERLANG_DRIVER_NAME(DRIVER_NAME)(void) #else # define DRIVER_INIT(DRIVER_NAME) \ - ErlDrvEntry* driver_init(void); \ - ErlDrvEntry* driver_init(void) + ErlDrvEntry* ERLANG_DRIVER_NAME(DRIVER_NAME)(void); \ + ErlDrvEntry* ERLANG_DRIVER_NAME(DRIVER_NAME)(void) #endif #define ERL_DRV_BUSY_MSGQ_DISABLED (~((ErlDrvSizeT) 0)) diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 2acc86cf42..ef34f5b221 100755 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -856,6 +856,7 @@ void erts_lcnt_enable_io_lock_count(int enable); typedef void *(*ErtsStaticNifInitFPtr)(void); ErtsStaticNifInitFPtr erts_static_nif_get_nif_init(const char *name); int erts_is_static_nif(void *handle); +void erts_init_static_drivers(void); /* erl_drv_thread.c */ void erl_drv_thr_init(void); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index c1e66b59af..fb39c18d9d 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -2765,6 +2765,7 @@ void erts_init_io(int port_tab_size, init_driver(&fd_driver, &fd_driver_entry, NULL); init_driver(&vanilla_driver, &vanilla_driver_entry, NULL); init_driver(&spawn_driver, &spawn_driver_entry, NULL); + erts_init_static_drivers(); for (dp = driver_tab; *dp != NULL; dp++) erts_add_driver_entry(*dp, NULL, 1); diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab index 06928a3a4a..3eedef21a7 100755 --- a/erts/emulator/utils/make_driver_tab +++ b/erts/emulator/utils/make_driver_tab @@ -28,8 +28,10 @@ use File::Basename; my $file = ""; my $nif = ""; -my @drivers = (); +my @emu_drivers = (); +my @static_drivers = (); my @nifs = (); +my $mode = 1; while (@ARGV) { my $d = shift; @@ -37,15 +39,28 @@ while (@ARGV) { $file = shift or die("-o requires argument"); next; } + if ( $d =~ /^-nifs$/ ) { + $mode = 2; + next; + } + if ( $d =~ /^-drivers$/ ) { + $mode = 1; + next; + } if ( $d =~ /^.*\.a$/ ) { $d = basename $d; $d =~ s/\.a$//; # strip .a - push(@nifs, $d); + if ($mode == 1) { + push(@static_drivers, $d); + } + if ($mode == 2) { + push(@nifs, $d); + } next; } $d = basename $d; $d =~ s/drv(\..*|)$//; # strip drv.* or just drv - push(@drivers, $d); + push(@emu_drivers, $d); } # Did we want output to a file? @@ -64,19 +79,36 @@ print < Date: Mon, 19 Aug 2013 11:56:01 +0200 Subject: erts: Document --enable-static-nif/driver --- HOWTO/INSTALL.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md index fa1b9d2e89..9ea50ce86c 100644 --- a/HOWTO/INSTALL.md +++ b/HOWTO/INSTALL.md @@ -296,6 +296,18 @@ Some of the available `configure` options are: you can build using a fallback implementation based on mutexes or spinlocks. Performance of the SMP runtime system will however suffer immensely without an implementation for native atomic memory accesses. +* `--enable-static-{nifs,drivers}` - To allow usage of nifs and drivers on OSs + that do not support dynamic linking of libraries it is possible to statically + link nifs and drivers with the main Erlang VM binary. This is done by passing + a comma seperated list to the archives that you want to statically link. e.g. + `--enable-static-nifs=/home/$USER/my_nif.a`. The path has to be absolute and the + name of the archive has to be the same as the module, i.e. `my_nif` in the + example above. This is also true for drivers, but then it is the driver name + that has to be the same as the filename. You also have to define + `STATIC_ERLANG_{NIF,DRIVER}` when compiling the .o files for the nif/driver. + If your nif/driver depends on some other dynamic library, you now have to link + that to the Erlang VM binary. This is easily achived by passing `LIBS=-llibname` + to configure. If you or your system has special requirements please read the `Makefile` for additional configuration information. -- cgit v1.2.3