1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-21 06:55:39 +00:00

Add dynamic module module support

* configure.ac: Add '--with-modules' option.  Conditionally add
  dynlib.o and module.o to the list of objects.  Add any system
  specific flags to the linker flags to support dynamic libraries.
* m4/ax_gcc_var_attribute.m4: Add autoconf extension to test gcc
  attributes.
* src/Makefile.in: Conditionally add module objects and linker flags.
* src/alloc.c (garbage_collect_1): protect module local values from
  GC.
* src/lisp.h: Add 'module_init' and 'syms_of_module' prototypes.
* src/emacs_module.h: New header file included by modules.  Public
  module API.
* src/module.c: New module implementation file.

Co-authored-by: Philipp Stephani <phst@google.com>
This commit is contained in:
Aurélien Aptel 2015-11-16 00:47:04 +01:00 committed by Ted Zlatanov
parent f69cd6bfa1
commit 307e76c799
8 changed files with 1628 additions and 3 deletions

View File

@ -353,6 +353,7 @@ OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support])
OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
OPTION_DEFAULT_ON([zlib],[don't compile with zlib decompression support])
OPTION_DEFAULT_OFF([modules],[compile with dynamic modules support])
AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB],
[use a file notification library (LIB one of: yes, gfile, inotify, w32, no)])],
@ -2191,6 +2192,9 @@ LIBS="$LIBS_SYSTEM $LIBS"
dnl FIXME replace main with a function we actually want from this library.
AC_CHECK_LIB(Xbsd, main, LD_SWITCH_X_SITE="$LD_SWITCH_X_SITE -lXbsd")
dnl Check for C11 threads.
AC_CHECK_HEADERS_ONCE(threads.h)
dnl Check for the POSIX thread library.
LIB_PTHREAD=
AC_CHECK_HEADERS_ONCE(pthread.h)
@ -3285,6 +3289,48 @@ if test "${HAVE_ZLIB}" = "yes"; then
fi
AC_SUBST(LIBZ)
### Dynamic modules support
LIBMODULES=
HAVE_MODULES=no
MODULES_OBJ=
MODULES_SUFFIX=
if test "${with_modules}" != "no"; then
if test "$opsys" = "gnu-linux"; then
LIBMODULES="-ldl"
MODULES_SUFFIX=".so"
HAVE_MODULES=yes
elif test "$opsys" = "cygwin"; then
# XXX: not tested
LIBMODULES="-lcygwin"
MODULES_SUFFIX=".dll"
HAVE_MODULES=yes
elif test "$opsys" = "darwin"; then
MODULES_SUFFIX=".so"
HAVE_MODULES=yes
elif test "$opsys" = "mingw32"; then
MODULES_SUFFIX=".dll"
HAVE_MODULES=yes
else
# BSD system have dlopen in the libc
AC_CHECK_FUNC(dlopen, [MODULES_SUFFIX=".so"]
[HAVE_MODULES=yes], [])
fi
if test "${HAVE_MODULES}" = no; then
AC_MSG_ERROR([Dynamic modules are not supported on your system])
fi
fi
if test "${HAVE_MODULES}" = yes; then
MODULES_OBJ="dynlib.o module.o"
AC_DEFINE(HAVE_MODULES, 1, [Define to 1 if dynamic modules are enabled])
AC_DEFINE_UNQUOTED(MODULES_SUFFIX, "$MODULES_SUFFIX", [System extension for dynamic libraries])
fi
AC_SUBST(MODULES_OBJ)
AC_SUBST(LIBMODULES)
AX_GCC_VAR_ATTRIBUTE(cleanup)
AC_CHECK_FUNCS(dladdr)
### Use -lpng if available, unless '--with-png=no'.
HAVE_PNG=no
LIBPNG=
@ -5175,7 +5221,7 @@ optsep=
emacs_config_features=
for opt in XAW3D XPM JPEG TIFF GIF PNG RSVG CAIRO IMAGEMAGICK SOUND GPM DBUS \
GCONF GSETTINGS NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT \
LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS X_TOOLKIT X11 NS; do
LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS X_TOOLKIT X11 NS MODULES; do
case $opt in
NOTIFY|ACL) eval val=\${${opt}_SUMMARY} ;;
@ -5223,6 +5269,7 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D
Does Emacs use -lotf? ${HAVE_LIBOTF}
Does Emacs use -lxft? ${HAVE_XFT}
Does Emacs directly use zlib? ${HAVE_ZLIB}
Does Emacs has dynamic modules support? ${HAVE_MODULES}
Does Emacs use toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS}
"])

141
m4/ax_gcc_var_attribute.m4 Normal file
View File

@ -0,0 +1,141 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_gcc_var_attribute.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_GCC_VAR_ATTRIBUTE(ATTRIBUTE)
#
# DESCRIPTION
#
# This macro checks if the compiler supports one of GCC's variable
# attributes; many other compilers also provide variable attributes with
# the same syntax. Compiler warnings are used to detect supported
# attributes as unsupported ones are ignored by default so quieting
# warnings when using this macro will yield false positives.
#
# The ATTRIBUTE parameter holds the name of the attribute to be checked.
#
# If ATTRIBUTE is supported define HAVE_VAR_ATTRIBUTE_<ATTRIBUTE>.
#
# The macro caches its result in the ax_cv_have_var_attribute_<attribute>
# variable.
#
# The macro currently supports the following variable attributes:
#
# aligned
# cleanup
# common
# nocommon
# deprecated
# mode
# packed
# tls_model
# unused
# used
# vector_size
# weak
# dllimport
# dllexport
# init_priority
#
# Unsuppored variable attributes will be tested against a global integer
# variable and without any arguments given to the attribute itself; the
# result of this check might be wrong or meaningless so use with care.
#
# LICENSE
#
# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 3
AC_DEFUN([AX_GCC_VAR_ATTRIBUTE], [
AS_VAR_PUSHDEF([ac_var], [ax_cv_have_var_attribute_$1])
AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([
m4_case([$1],
[aligned], [
int foo __attribute__(($1(32)));
],
[cleanup], [
int bar(int *t) { return *t; };
],
[common], [
int foo __attribute__(($1));
],
[nocommon], [
int foo __attribute__(($1));
],
[deprecated], [
int foo __attribute__(($1)) = 0;
],
[mode], [
long foo __attribute__(($1(word)));
],
[packed], [
struct bar {
int baz __attribute__(($1));
};
],
[tls_model], [
__thread int bar1 __attribute__(($1("global-dynamic")));
__thread int bar2 __attribute__(($1("local-dynamic")));
__thread int bar3 __attribute__(($1("initial-exec")));
__thread int bar4 __attribute__(($1("local-exec")));
],
[unused], [
int foo __attribute__(($1));
],
[used], [
int foo __attribute__(($1));
],
[vector_size], [
int foo __attribute__(($1(16)));
],
[weak], [
int foo __attribute__(($1));
],
[dllimport], [
int foo __attribute__(($1));
],
[dllexport], [
int foo __attribute__(($1));
],
[init_priority], [
struct bar { bar() {} ~bar() {} };
bar b __attribute__(($1(65535/2)));
],
[
m4_warn([syntax], [Unsupported attribute $1, the test may fail])
int foo __attribute__(($1));
]
)], [
m4_case([$1],
[cleanup], [
int foo __attribute__(($1(bar))) = 0;
foo = foo + 1;
],
[]
)])
],
dnl GCC doesn't exit with an error if an unknown attribute is
dnl provided but only outputs a warning, so accept the attribute
dnl only if no warning were issued.
[AS_IF([test -s conftest.err],
[AS_VAR_SET([ac_var], [no])],
[AS_VAR_SET([ac_var], [yes])])],
[AS_VAR_SET([ac_var], [no])])
])
AS_IF([test yes = AS_VAR_GET([ac_var])],
[AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_VAR_ATTRIBUTE_$1), 1,
[Define to 1 if the system has the `$1' variable attribute])], [])
AS_VAR_POPDEF([ac_var])
])

View File

@ -230,6 +230,11 @@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
LIBZ = @LIBZ@
## system-specific libs for dynamic modules, else empty
LIBMODULES = @LIBMODULES@
## dynlib.o module.o if modules enabled, else empty
MODULES_OBJ = @MODULES_OBJ@
XRANDR_LIBS = @XRANDR_LIBS@
XRANDR_CFLAGS = @XRANDR_CFLAGS@
@ -377,7 +382,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
minibuf.o fileio.o dired.o \
cmds.o casetab.o casefiddle.o indent.o search.o regex.o undo.o \
alloc.o data.o doc.o editfns.o callint.o \
eval.o floatfns.o fns.o font.o print.o lread.o \
eval.o floatfns.o fns.o font.o print.o lread.o $(MODULES_OBJ) \
syntax.o $(UNEXEC_OBJ) bytecode.o \
process.o gnutls.o callproc.o \
region-cache.o sound.o atimer.o \
@ -468,7 +473,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) \
$(GFILENOTIFY_LIBS) $(LIB_MATH) $(LIBZ)
$(GFILENOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES)
$(leimdir)/leim-list.el: bootstrap-emacs$(EXEEXT)
$(MAKE) -C ../leim leim-list.el EMACS="$(bootstrap_exe)"

View File

@ -5574,6 +5574,10 @@ garbage_collect_1 (void *end)
mark_fringe_data ();
#endif
#ifdef HAVE_MODULES
mark_modules ();
#endif
/* Everything is now marked, except for the data in font caches,
undo lists, and finalizers. The first two are compacted by
removing an items which aren't reachable otherwise. */

View File

@ -776,6 +776,10 @@ main (int argc, char **argv)
atexit (close_output_streams);
#ifdef HAVE_MODULES
module_init ();
#endif
sort_args (argc, argv);
argc = 0;
while (argv[argc]) argc++;
@ -1450,6 +1454,11 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
syms_of_terminal ();
syms_of_term ();
syms_of_undo ();
#ifdef HAVE_MODULES
syms_of_module ();
#endif
#ifdef HAVE_SOUND
syms_of_sound ();
#endif

230
src/emacs_module.h Normal file
View File

@ -0,0 +1,230 @@
/*
emacs_module.h - Module API
Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EMACS_MODULE_H
#define EMACS_MODULE_H
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#ifdef __cplusplus
#define EMACS_EXTERN_C_BEGIN extern "C" {
#define EMACS_EXTERN_C_END }
#else
#define EMACS_EXTERN_C_BEGIN
#define EMACS_EXTERN_C_END
#endif
#if defined(__cplusplus) && __cplusplus >= 201103L
#define EMACS_NOEXCEPT noexcept
#else
#define EMACS_NOEXCEPT
#endif
EMACS_EXTERN_C_BEGIN
/* Current environement */
typedef struct emacs_env_25 emacs_env;
/* Opaque structure pointer representing an Emacs Lisp value */
typedef struct emacs_value_tag* emacs_value;
enum emacs_arity {
emacs_variadic_function = -2
};
/* Struct passed to a module init function (emacs_module_init) */
struct emacs_runtime {
/* Structure size (for version checking) */
size_t size;
/* Private data; users should not touch this */
struct emacs_runtime_private *private_members;
/* Returns an environment pointer. */
emacs_env* (*get_environment)(struct emacs_runtime *ert);
};
/* Function prototype for the module init function */
typedef int (*emacs_init_function)(struct emacs_runtime *ert);
/* Function prototype for the module Lisp functions */
typedef emacs_value (*emacs_subr)(emacs_env *env,
int nargs,
emacs_value args[],
void *data);
/* Function prototype for module user-pointer finalizers */
typedef void (*emacs_finalizer_function)(void*);
/* Possible Emacs function call outcomes. */
enum emacs_funcall_exit {
/* Function has returned normally. */
emacs_funcall_exit_return = 0,
/* Function has signaled an error using `signal'. */
emacs_funcall_exit_signal = 1,
/* Function has exit using `throw'. */
emacs_funcall_exit_throw = 2,
};
struct emacs_env_25 {
/*
* Structure size (for version checking)
*/
size_t size;
/* Private data; users should not touch this */
struct emacs_env_private *private_members;
/*
* Memory management
*/
emacs_value (*make_global_ref)(emacs_env *env,
emacs_value any_reference);
void (*free_global_ref)(emacs_env *env,
emacs_value global_reference);
/*
* Non-local exit handling
*/
enum emacs_funcall_exit (*non_local_exit_check)(emacs_env *env);
void (*non_local_exit_clear)(emacs_env *env);
enum emacs_funcall_exit (*non_local_exit_get)(emacs_env *env,
emacs_value *non_local_exit_symbol_out,
emacs_value *non_local_exit_data_out);
void (*non_local_exit_signal)(emacs_env *env,
emacs_value non_local_exit_symbol,
emacs_value non_local_exit_data);
void (*non_local_exit_throw)(emacs_env *env,
emacs_value tag,
emacs_value value);
/*
* Function registration
*/
emacs_value (*make_function)(emacs_env *env,
int min_arity,
int max_arity,
emacs_value (*function)(emacs_env*, int, emacs_value*, void*) EMACS_NOEXCEPT,
const char *documentation,
void *data);
emacs_value (*funcall)(emacs_env *env,
emacs_value function,
int nargs,
emacs_value args[]);
emacs_value (*intern)(emacs_env *env,
const char *symbol_name);
/*
* Type conversion
*/
emacs_value (*type_of)(emacs_env *env,
emacs_value value);
bool (*is_not_nil)(emacs_env *env, emacs_value value);
bool (*eq)(emacs_env *env, emacs_value a, emacs_value b);
int64_t (*extract_integer)(emacs_env *env,
emacs_value value);
emacs_value (*make_integer)(emacs_env *env,
int64_t value);
double (*extract_float)(emacs_env *env,
emacs_value value);
emacs_value (*make_float)(emacs_env *env,
double value);
/*
* Copy the content of the lisp string VALUE to BUFFER as an utf8
* null-terminated string.
*
* SIZE must point to the total size of the buffer. If BUFFER is
* NULL or if SIZE is not big enough, write the required buffer size
* to SIZE and return false.
*
* Note that SIZE must include the last null byte (e.g. "abc" needs
* a buffer of size 4).
*
* Returns true if the string was successfully copied.
*/
bool (*copy_string_contents)(emacs_env *env,
emacs_value value,
char *buffer,
size_t *size_inout);
/*
* Create a lisp string from a utf8 encoded string.
*/
emacs_value (*make_string)(emacs_env *env,
const char *contents, size_t length);
/*
* Embedded pointer type
*/
emacs_value (*make_user_ptr)(emacs_env *env,
void (*fin)(void *) EMACS_NOEXCEPT,
void *ptr);
void* (*get_user_ptr)(emacs_env *env, emacs_value uptr);
void (*set_user_ptr)(emacs_env *env, emacs_value uptr, void *ptr);
void (*(*get_user_finalizer)(emacs_env *env, emacs_value uptr))(void *) EMACS_NOEXCEPT;
void (*set_user_finalizer)(emacs_env *env,
emacs_value uptr,
void (*fin)(void *) EMACS_NOEXCEPT);
/*
* Vector functions
*/
emacs_value (*vec_get) (emacs_env *env,
emacs_value vec,
size_t i);
void (*vec_set) (emacs_env *env,
emacs_value vec,
size_t i,
emacs_value val);
size_t (*vec_size) (emacs_env *env,
emacs_value vec);
};
EMACS_EXTERN_C_END
#endif /* EMACS_MODULE_H */

View File

@ -3916,6 +3916,10 @@ extern bool let_shadows_global_binding_p (Lisp_Object symbol);
/* Defined in alloc.c. */
extern Lisp_Object make_user_ptr (void (*finalizer) (void*), void *p);
/* Defined in module.c. */
extern void module_init (void);
extern void mark_modules (void);
extern void syms_of_module (void);
#endif
/* Defined in editfns.c. */

1185
src/module.c Normal file

File diff suppressed because it is too large Load Diff