From b466ccc6137f2255220c87f74baf86a67884a3d8 Mon Sep 17 00:00:00 2001 From: "Gary V. Vaughan" Date: Fri, 20 Sep 2013 16:01:31 +0700 Subject: modules: allow only a single function access point. Exporting non-function symbols barely works on Windows, so change the module loading API to use a single function access point which is then responsible for calling back to install symbols and macros. * m4/m4module.h, m4/m4module.c (m4_install_builtins) (m4_install_macros): New APIs for saving builtins and macros into the module struct. * m4/m4module.c (install_macro_table, install_builtin_table): Adjust accordingly. (m4__module_open): Simplify accordingly. * m4/m4private.h (BUILTIN_SYMBOL, MACRO_SYMBOL): Remove. * modules/gnu.c, modules/import.c, modules/m4.c, modules/modtest.c, modules/mpeval.c, modules/shadow.c, modules/time.c, modules/traditional.c (m4_builtin_table, m4_macro_table): Make static, and remove LTX symbol mangling macros. (M4INIT_HANDLER): Call m4_install_builtins and/or m4_install_macros. * tests/options.at: Now that init_func is always called, adjust expected debug output. Signed-off-by: Gary V. Vaughan --- m4/m4module.h | 3 + m4/m4private.h | 3 +- m4/module.c | 151 +++++++++++++++++++++++++------------------------- modules/gnu.c | 16 +++--- modules/import.c | 8 ++- modules/m4.c | 8 ++- modules/modtest.c | 10 ++-- modules/mpeval.c | 16 +++--- modules/shadow.c | 19 ++----- modules/stdlib.c | 14 +++-- modules/time.c | 13 +++-- modules/traditional.c | 10 ++-- tests/options.at | 2 + 13 files changed, 147 insertions(+), 126 deletions(-) diff --git a/m4/m4module.h b/m4/m4module.h index a6bd5139..92710a7e 100644 --- a/m4/m4module.h +++ b/m4/m4module.h @@ -237,6 +237,9 @@ extern m4_module * m4_module_load (m4 *, const char *, m4_obstack *); extern void * m4_module_import (m4 *, const char *, const char *, m4_obstack *); +extern void m4_install_builtins (m4*, m4_module *, const m4_builtin*); +extern void m4_install_macros (m4*, m4_module *, const m4_macro*); + extern const char * m4_get_module_name (const m4_module *); extern m4_module * m4_module_next (m4_module *); diff --git a/m4/m4private.h b/m4/m4private.h index 29f2bfe9..35957223 100644 --- a/m4/m4private.h +++ b/m4/m4private.h @@ -173,8 +173,6 @@ extern void m4__builtin_print (m4_obstack *, const m4__builtin *, bool, /* --- MODULE MANAGEMENT --- */ -#define BUILTIN_SYMBOL "m4_builtin_table" -#define MACRO_SYMBOL "m4_macro_table" #define INIT_SYMBOL "m4_init_module" /* Representation of a loaded m4 module. */ @@ -182,6 +180,7 @@ struct m4_module { lt_dlhandle handle; /* All ltdl module information. */ m4__builtin *builtins; /* Sorted array of builtins. */ + m4_macro *macros; /* Unsorted array of macros. */ size_t builtins_len; /* Number of builtins. */ }; diff --git a/m4/module.c b/m4/module.c index ebedcffe..a2215f0e 100644 --- a/m4/module.c +++ b/m4/module.c @@ -39,10 +39,17 @@ * libdld or lt_dlpreload from libtool if shared libraries are not * available on the host machine. * - * An M4 module will usually define an external symbol called - * `m4_builtin_table'. This symbol points to a table of `m4_builtin'. - * The table is saved as libltdl caller data and each definition therein - * is added to the symbol table. + * An M4 module will usually define an external symbol named after the + * basename of the loadable module: + * + * void + * mymod_LTX_m4_init_module (m4 *context, m4_module *module, + * m4_obstack *obs) + * + * The function is only called the first time the module is included + * and generally uses either `m4_install_builtins' or + * `m4_install_macros' (or both!) to register whatever builtins and + * macros are provided by the module. * * To load a module, call m4_module_load(), which searches for the * module in directories from M4PATH. The search path is initialized @@ -50,20 +57,10 @@ * time default where the modules shipped with M4 itself are installed. * `m4_module_load' returns NULL on failure, or else an opaque module * handle for the newly mapped vm segment containing the module code. - * If the module is not already loaded, m4_module_load() retrieves its - * value for the symbol `m4_builtin_table', which is installed using - * set_module_builtin_table(). - * - * In addition to builtin functions, you can also define static macro - * expansions in the `m4_macro_table' symbol. If you define this symbol - * in your modules, it should be an array of `m4_macro's, mapping macro - * names to the expansion text. Any macros defined in `m4_macro_table' - * are installed into the M4 symbol table with set_module_macro_table(). - * - * Each time a module is loaded, the module function prototyped as - * "M4INIT_HANDLER ()" is called, if defined. Any value - * stored in OBS by this function becomes the expansion of the macro - * which called it. + * If the module is not already loaded, m4_module_load() the builtins + * and macros registered by `mymod_LTX_m4_init_module' are installed + * into the symbol table using `install_builtin_table' and `install_ + * macro_table' respectively. **/ #define MODULE_SELF_NAME "!myself!" @@ -73,8 +70,9 @@ static const char* module_dlerror (void); static void install_builtin_table (m4*, m4_module *); static void install_macro_table (m4*, m4_module *); -static int m4__module_interface (lt_dlhandle handle, - const char *id_string); +static int compare_builtin_CB (const void *a, const void *b); +static int m4__module_interface (lt_dlhandle handle, + const char *id_string); static lt_dlinterface_id iface_id = NULL; @@ -117,6 +115,36 @@ m4_module_import (m4 *context, const char *module_name, return symbol_address; } +void +m4_install_builtins (m4 *context, m4_module *module, const m4_builtin *bp) +{ + assert (context); + assert (module); + assert (bp); + + const m4_builtin *tmp; + m4__builtin *builtin; + for (tmp = bp; tmp->name; tmp++) + module->builtins_len++; + module->builtins = (m4__builtin *) xnmalloc (module->builtins_len, + sizeof *module->builtins); + for (builtin = module->builtins; bp->name != NULL; bp++, builtin++) + { + /* Sanity check that builtins meet the required interface. */ + assert (bp->min_args <= bp->max_args); + assert (bp->min_args > 0 || + (bp->flags & (M4_BUILTIN_BLIND|M4_BUILTIN_SIDE_EFFECT)) == 0); + assert (bp->max_args || + (bp->flags & M4_BUILTIN_FLATTEN_ARGS) == 0); + assert ((bp->flags & ~M4_BUILTIN_FLAGS_MASK) == 0); + memcpy (&builtin->builtin, bp, sizeof *bp); + builtin->builtin.name = xstrdup (bp->name); + builtin->module = module; + } + qsort (module->builtins, module->builtins_len, + sizeof *module->builtins, compare_builtin_CB); +} + static void install_builtin_table (m4 *context, m4_module *module) { @@ -144,6 +172,16 @@ install_builtin_table (m4 *context, m4_module *module) m4_get_module_name (module)); } +void +m4_install_macros (m4 *context, m4_module *module, const m4_macro *mp) +{ + assert (context); + assert (module); + assert (mp); + + module->macros = (m4_macro *) mp; +} + static void install_macro_table (m4 *context, m4_module *module) { @@ -152,7 +190,7 @@ install_macro_table (m4 *context, m4_module *module) assert (context); assert (module); - mp = (const m4_macro *) lt_dlsym (module->handle, MACRO_SYMBOL); + mp = module->macros; if (mp) { @@ -174,7 +212,7 @@ install_macro_table (m4 *context, m4_module *module) m4_debug_message (context, M4_DEBUG_TRACE_MODULE, _("module %s: macros loaded"), - m4_get_module_name (module)); + m4_get_module_name (module)); } } @@ -209,9 +247,7 @@ m4__module_interface (lt_dlhandle handle, const char *id_string) return 0; /* A valid m4 module must provide at least one of these symbols. */ - return !(lt_dlsym (handle, INIT_SYMBOL) - || lt_dlsym (handle, BUILTIN_SYMBOL) - || lt_dlsym (handle, MACRO_SYMBOL)); + return !(lt_dlsym (handle, INIT_SYMBOL)); } @@ -379,46 +415,10 @@ m4__module_open (m4 *context, const char *name, m4_obstack *obs) { void *old; const char *err; - const m4_builtin *bp; module = (m4_module *) xzalloc (sizeof *module); module->handle = handle; - /* TODO - change module interface to return function pointer - that supplies both table and length of table, rather than - returning data pointer that must have a sentinel - entry? */ - bp = (m4_builtin *) lt_dlsym (module->handle, BUILTIN_SYMBOL); - if (bp) - { - const m4_builtin *tmp; - m4__builtin *builtin; - for (tmp = bp; tmp->name; tmp++) - module->builtins_len++; - module->builtins = - (m4__builtin *) xnmalloc (module->builtins_len, - sizeof *module->builtins); - for (builtin = module->builtins; bp->name != NULL; - bp++, builtin++) - { - /* Sanity check that builtins meet the required - interface. */ - assert (bp->min_args <= bp->max_args); - assert (bp->min_args > 0 - || (bp->flags & (M4_BUILTIN_BLIND - | M4_BUILTIN_SIDE_EFFECT)) == 0); - assert (bp->max_args - || (bp->flags & M4_BUILTIN_FLATTEN_ARGS) == 0); - assert ((bp->flags & ~M4_BUILTIN_FLAGS_MASK) == 0); - - memcpy (&builtin->builtin, bp, sizeof *bp); - builtin->builtin.name = xstrdup (bp->name); - builtin->module = module; - } - } - qsort (module->builtins, module->builtins_len, - sizeof *module->builtins, compare_builtin_CB); - /* clear out any stale errors, since we have to use lt_dlerror to distinguish between success and failure. */ @@ -429,23 +429,22 @@ m4__module_open (m4 *context, const char *name, m4_obstack *obs) if (err) m4_error (context, EXIT_FAILURE, 0, NULL, _("unable to load module `%s': %s"), name, err); - } - /* Find and run any initializing function in the opened module, - each time the module is opened. */ - init_func = (m4_module_init_func *) lt_dlsym (handle, INIT_SYMBOL); - if (init_func) - { - init_func (context, module, obs); + /* Find and run any initializing function in the opened module, + the first time the module is opened. */ + init_func = (m4_module_init_func *) lt_dlsym (handle, INIT_SYMBOL); + if (init_func) + { + init_func (context, module, obs); - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: init hook called"), name); - } - else if (!lt_dlsym (handle, BUILTIN_SYMBOL) - && !lt_dlsym (handle, MACRO_SYMBOL)) - { - m4_error (context, EXIT_FAILURE, 0, NULL, - _("module `%s' has no entry points"), name); + m4_debug_message (context, M4_DEBUG_TRACE_MODULE, + _("module %s: init hook called"), name); + } + else + { + m4_error (context, EXIT_FAILURE, 0, NULL, + _("module `%s' has no entry point"), name); + } } m4_debug_message (context, M4_DEBUG_TRACE_MODULE, diff --git a/modules/gnu.c b/modules/gnu.c index ae3024f7..5c9b0eed 100644 --- a/modules/gnu.c +++ b/modules/gnu.c @@ -32,11 +32,6 @@ #include "spawn-pipe.h" #include "wait-process.h" -/* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table gnu_LTX_m4_builtin_table -#define m4_macro_table gnu_LTX_m4_macro_table - - /* Maintain each of the builtins implemented in this modules along with their details in a single table for easy maintenance. @@ -70,7 +65,7 @@ /* Generate a table for mapping m4 symbol names to handler functions. */ -const m4_builtin m4_builtin_table[] = +static const m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) @@ -83,7 +78,7 @@ const m4_builtin m4_builtin_table[] = /* A table for mapping m4 symbol names to simple expansion text. */ -const m4_macro m4_macro_table[] = +static const m4_macro m4_macro_table[] = { /* name text min max */ #if UNIX @@ -102,6 +97,13 @@ const m4_macro m4_macro_table[] = }; +M4INIT_HANDLER (gnu) +{ + m4_install_builtins (context, module, m4_builtin_table); + m4_install_macros (context, module, m4_macro_table); +} + + /* Regular expressions. Reuse re_registers among multiple re_pattern_buffer allocations to reduce malloc usage. */ diff --git a/modules/import.c b/modules/import.c index ebce6e45..679a50d5 100644 --- a/modules/import.c +++ b/modules/import.c @@ -41,7 +41,7 @@ builtin_functions #undef BUILTIN -const m4_builtin m4_builtin_table[] = +static const m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) @@ -53,6 +53,12 @@ const m4_builtin m4_builtin_table[] = }; +M4INIT_HANDLER (import) +{ + m4_install_builtins (context, module, m4_builtin_table); +} + + typedef bool export_test_func (const char *); typedef bool no_such_func (const char *); diff --git a/modules/m4.c b/modules/m4.c index f9449fe0..ecae4c3a 100644 --- a/modules/m4.c +++ b/modules/m4.c @@ -39,8 +39,6 @@ #include /* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table m4_LTX_m4_builtin_table - #define m4_set_sysval m4_LTX_m4_set_sysval #define m4_sysval_flush m4_LTX_m4_sysval_flush #define m4_dump_symbols m4_LTX_m4_dump_symbols @@ -127,6 +125,12 @@ const m4_builtin m4_builtin_table[] = }; +M4INIT_HANDLER (m4) +{ + m4_install_builtins (context, module, m4_builtin_table); +} + + /* The rest of this file is code for builtins and expansion of user defined macros. All the functions for builtins have a prototype as: diff --git a/modules/modtest.c b/modules/modtest.c index 385049b4..75450f7e 100644 --- a/modules/modtest.c +++ b/modules/modtest.c @@ -29,9 +29,6 @@ #endif /* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table modtest_LTX_m4_builtin_table -#define m4_macro_table modtest_LTX_m4_macro_table - #define export_test modtest_LTX_export_test extern bool export_test (const char *foo); @@ -44,7 +41,7 @@ extern bool export_test (const char *foo); builtin_functions #undef BUILTIN -const m4_builtin m4_builtin_table[] = +static const m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) @@ -55,7 +52,7 @@ const m4_builtin m4_builtin_table[] = { NULL, NULL, 0, 0, 0 }, }; -const m4_macro m4_macro_table[] = +static const m4_macro m4_macro_table[] = { /* name text min max */ { "__test__", "`modtest'", 0, 0 }, @@ -73,6 +70,9 @@ M4INIT_HANDLER (modtest) { const char *s = "Test module loaded.\n"; + m4_install_builtins (context, module, m4_builtin_table); + m4_install_macros (context, module, m4_macro_table); + /* Don't depend on OBS so that the traces are the same when used directly, or via a frozen file. */ fputs (s, stderr); diff --git a/modules/mpeval.c b/modules/mpeval.c index 7928a281..49afd765 100644 --- a/modules/mpeval.c +++ b/modules/mpeval.c @@ -32,11 +32,6 @@ # include #endif -/* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table mpeval_LTX_m4_builtin_table -#define m4_macro_table mpeval_LTX_m4_macro_table - - /* Maintain each of the builtins implemented in this modules along with their details in a single table for easy maintenance. @@ -106,7 +101,7 @@ /* Generate a table for mapping m4 symbol names to handler functions. */ -const m4_builtin m4_builtin_table[] = +static const m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) @@ -119,7 +114,7 @@ const m4_builtin m4_builtin_table[] = /* A table for mapping m4 symbol names to simple expansion text. */ -const m4_macro m4_macro_table[] = +static const m4_macro m4_macro_table[] = { /* name text min max */ { "__mpeval__", "", 0, 0 }, @@ -127,6 +122,13 @@ const m4_macro m4_macro_table[] = }; +M4INIT_HANDLER (mpeval) +{ + m4_install_builtins (context, module, m4_builtin_table); + m4_install_macros (context, module, m4_macro_table); +} + + /* GMP defines mpq_t as a 1-element array of struct. Therefore, `mpq_t' is not compatible with `const mpq_t'. */ typedef mpq_t number; diff --git a/modules/shadow.c b/modules/shadow.c index 529425c4..53829937 100644 --- a/modules/shadow.c +++ b/modules/shadow.c @@ -28,10 +28,6 @@ # include "m4private.h" #endif -/* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table shadow_LTX_m4_builtin_table -#define m4_macro_table shadow_LTX_m4_macro_table - /* function macros blind side minargs maxargs */ #define builtin_functions \ BUILTIN (shadow, false, false, false, 0, -1 ) \ @@ -42,7 +38,7 @@ builtin_functions #undef BUILTIN -const m4_builtin m4_builtin_table[] = +static const m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) @@ -53,7 +49,7 @@ const m4_builtin m4_builtin_table[] = { NULL, NULL, 0, 0, 0 }, }; -const m4_macro m4_macro_table[] = +static const m4_macro m4_macro_table[] = { /* name text min max */ { "__test__", "`shadow'", 0, 0 }, @@ -64,16 +60,13 @@ const m4_macro m4_macro_table[] = M4INIT_HANDLER (shadow) { - static bool loaded = false; - const char *s = "Shadow module loaded."; - /* Only display the message on first load. */ - if (obs && !loaded) - { - loaded = true; + if (obs) obstack_grow (obs, s, strlen (s)); - } + + m4_install_builtins (context, module, m4_builtin_table); + m4_install_macros (context, module, m4_macro_table); } diff --git a/modules/stdlib.c b/modules/stdlib.c index d8f839cf..b01326df 100644 --- a/modules/stdlib.c +++ b/modules/stdlib.c @@ -36,12 +36,9 @@ # include "m4private.h" #endif -/* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table stdlib_LTX_m4_builtin_table - /* function macros blind side minargs maxargs */ #define builtin_functions \ - BUILTIN (getcwd, false, false, false, 0, 0 ) \ + BUILTIN (getcwd, false, false, false, 0, 0 ) \ BUILTIN (getenv, false, true, false, 1, 1 ) \ BUILTIN (getlogin, false, false, false, 0, 0 ) \ BUILTIN (getpid, false, false, false, 0, 0 ) \ @@ -61,7 +58,7 @@ builtin_functions #undef BUILTIN -const m4_builtin m4_builtin_table[] = +static const m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) @@ -71,6 +68,13 @@ const m4_builtin m4_builtin_table[] = { NULL, NULL, 0, 0, 0 }, }; + + +M4INIT_HANDLER (stdlib) +{ + m4_install_builtins (context, module, m4_builtin_table); +} + /** * getcwd() diff --git a/modules/time.c b/modules/time.c index 573d14df..39db75fe 100644 --- a/modules/time.c +++ b/modules/time.c @@ -34,9 +34,6 @@ # include "m4private.h" #endif -/* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table time_LTX_m4_builtin_table - /* function macros blind side minargs maxargs */ #define builtin_functions \ BUILTIN (currenttime, false, false, false, 0, 0 ) \ @@ -61,7 +58,7 @@ # endif #undef BUILTIN -const m4_builtin m4_builtin_table[] = +static const m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) @@ -77,6 +74,14 @@ const m4_builtin m4_builtin_table[] = { NULL, NULL, 0, 0, 0 }, }; + + +M4INIT_HANDLER (time) +{ + m4_install_builtins (context, module, m4_builtin_table); +} + + /** * currenttime() diff --git a/modules/traditional.c b/modules/traditional.c index cb9a32bd..88a4966b 100644 --- a/modules/traditional.c +++ b/modules/traditional.c @@ -28,11 +28,8 @@ # include "m4private.h" #endif -/* Rename exported symbols for dlpreload()ing. */ -#define m4_macro_table traditional_LTX_m4_macro_table - /* A table for mapping m4 symbol names to simple expansion text. */ -const m4_macro m4_macro_table[] = +static const m4_macro m4_macro_table[] = { /* name text min max */ #if UNIX @@ -47,3 +44,8 @@ const m4_macro m4_macro_table[] = { "__traditional__", "", 0, 0 }, { NULL, NULL, 0, 0 }, }; + +M4INIT_HANDLER (traditional) +{ + m4_install_macros (context, module, m4_macro_table); +} diff --git a/tests/options.at b/tests/options.at index 5848fa80..8503f8fc 100644 --- a/tests/options.at +++ b/tests/options.at @@ -423,9 +423,11 @@ dnl Test all flags. AT_CHECK_M4([-dV in], [0], [[3 0 ]], [[m4debug: module m4: opening file +m4debug: module m4: init hook called m4debug: module m4: opened m4debug: module m4: builtins loaded m4debug: module gnu: opening file +m4debug: module gnu: init hook called m4debug: module gnu: opened m4debug: module gnu: builtins loaded m4debug: module gnu: macros loaded -- cgit v1.2.1