From cba174d597a5c4a47ab7fd040b5650e23dd0b52c Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Thu, 27 Oct 2016 19:08:02 -0400 Subject: [PATCH] Add support for statically-built plug-ins MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit ./configure --disable-shared BUILT_IN_PLUGINS=1 Signed-off-by: Jérémie Galarneau --- configure.ac | 13 +++ converter/Makefile.am | 4 + converter/babeltrace.c | 6 ++ .../plugin/component-factory-internal.h | 27 ++++++ include/babeltrace/plugin/component-factory.h | 9 ++ include/babeltrace/plugin/plugin-internal.h | 8 +- include/babeltrace/plugin/plugin-macros.h | 23 ++++- include/babeltrace/plugin/plugin-system.h | 3 +- lib/plugin-system/component-factory.c | 84 ++++++++++++++----- lib/plugin-system/plugin.c | 83 ++++++++++++------ 10 files changed, 203 insertions(+), 57 deletions(-) diff --git a/configure.ac b/configure.ac index afc696d9..1c49db81 100644 --- a/configure.ac +++ b/configure.ac @@ -315,6 +315,16 @@ AS_IF([test "x$_enable_debug_info" = xyes], [ AC_DEFINE([ENABLE_DEBUG_INFO], [1], [Define to 1 if you enable the 'debug info' feature]) ], []) +AC_ARG_VAR([BUILT_IN_PLUGINS], [Statically-link in-tree plug-ins into the babeltrace binary]) +AS_IF([test "x$BUILT_IN_PLUGINS" != x], [ +# Built-in plug-ins are only available when the --disable-shared --enable-static options are used. + AS_IF([test "x$enable_static" != "xyes"], [AC_MSG_ERROR(--enable-static must be used to bundle plug-ins in the babeltrace executable)]) + AS_IF([test "x$enable_shared" = "xyes"], [AC_MSG_ERROR(--disable-shared must be used to bundle plug-ins in the babeltrace executable)]) + built_in_plugins=yes + AC_DEFINE([BT_BUILT_IN_PLUGINS], [1], [Define to 1 to register plug-in attributes in static executable sections]) +]) +AM_CONDITIONAL([BUILT_IN_PLUGINS], [test "x$built_in_plugins" = "xyes"]) + PKG_CHECK_MODULES(GMODULE, [gmodule-2.0 >= 2.0.0]) LIBS="$LIBS $GMODULE_LIBS" @@ -442,6 +452,9 @@ PPRINT_PROP_BOOL([Python bindings doc], $value) test "x$_enable_debug_info" = "xyes" && value=1 || value=0 PPRINT_PROP_BOOL([Debug information output], $value) +# built-in plug-ins enabled/disabled +test "x$built_in_plugins" = "xyes" && value=1 || value=0 +PPRINT_PROP_BOOL([Built-in plug-ins], $value) report_bindir="`eval eval echo $bindir`" report_libdir="`eval eval echo $libdir`" diff --git a/converter/Makefile.am b/converter/Makefile.am index 5909e2a3..a0eafaa0 100644 --- a/converter/Makefile.am +++ b/converter/Makefile.am @@ -25,6 +25,10 @@ if ENABLE_DEBUG_INFO babeltrace_LDADD += $(top_builddir)/lib/libdebug-info.la endif +if BUILT_IN_PLUGINS +babeltrace_LDFLAGS += -Wl,--whole-archive,$(top_builddir)/plugins/ctf/.libs/libbabeltrace-plugin-ctf.a,$(top_builddir)/plugins/text/.libs/libbabeltrace-plugin-ctf-text.a,$(top_builddir)/plugins/muxer/.libs/libbabeltrace-plugin-muxer.a,--no-whole-archive +endif + babeltrace_log_SOURCES = babeltrace-log.c babeltrace_log_LDADD = \ diff --git a/converter/babeltrace.c b/converter/babeltrace.c index 1c696545..d619066d 100644 --- a/converter/babeltrace.c +++ b/converter/babeltrace.c @@ -302,6 +302,12 @@ int main(int argc, char **argv) goto end; } + ret = bt_component_factory_load_static(component_factory); + if (ret) { + fprintf(stderr, "Failed to load static plugins.\n"); + goto end; + } + print_component_classes_found(component_factory); source_class = bt_component_factory_get_component_class( component_factory, "ctf", BT_COMPONENT_TYPE_SOURCE, diff --git a/include/babeltrace/plugin/component-factory-internal.h b/include/babeltrace/plugin/component-factory-internal.h index 9cb07ec2..10a2b787 100644 --- a/include/babeltrace/plugin/component-factory-internal.h +++ b/include/babeltrace/plugin/component-factory-internal.h @@ -36,6 +36,33 @@ #include #include +#define SECTION_BEGIN(_name) &__start_##_name +#define SECTION_END(_name) &__stop_##_name + +#define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name)) + +#define DECLARE_SECTION(_type, _name) \ + extern _type const __start_##_name __attribute((weak)); \ + extern _type const __stop_##_name __attribute((weak)) + +#define DECLARE_PLUG_IN_SECTIONS \ + DECLARE_SECTION(bt_plugin_register_func, __plugin_register_funcs); \ + DECLARE_SECTION(const char *, __plugin_names); \ + DECLARE_SECTION(const char *, __plugin_authors); \ + DECLARE_SECTION(const char *, __plugin_licenses); \ + DECLARE_SECTION(const char *, __plugin_descriptions) + +#define PRINT_SECTION(_printer, _name) \ + _printer("Section " #_name " [%p - %p], (%zu elements)\n", \ + SECTION_BEGIN(_name), SECTION_END(_name), SECTION_ELEMENT_COUNT(_name)) + +#define PRINT_PLUG_IN_SECTIONS(_printer) \ + PRINT_SECTION(_printer, __plugin_register_funcs); \ + PRINT_SECTION(_printer, __plugin_names); \ + PRINT_SECTION(_printer, __plugin_authors); \ + PRINT_SECTION(_printer, __plugin_licenses); \ + PRINT_SECTION(_printer, __plugin_descriptions) + struct bt_component_factory { struct bt_object base; /** Array of pointers to struct bt_component_class */ diff --git a/include/babeltrace/plugin/component-factory.h b/include/babeltrace/plugin/component-factory.h index a36d6b72..95c5767b 100644 --- a/include/babeltrace/plugin/component-factory.h +++ b/include/babeltrace/plugin/component-factory.h @@ -138,6 +138,15 @@ extern enum bt_component_factory_status bt_component_factory_load( extern enum bt_component_factory_status bt_component_factory_load_recursive( struct bt_component_factory *factory, const char *path); +/** + * Load and register Babeltrace plugins statically-linked to the executable. + * + * @param factory A component factory instance + * @returns One of #bt_component_factory_status values + */ +extern enum bt_component_factory_status bt_component_factory_load_static( + struct bt_component_factory *factory); + extern enum bt_component_factory_status bt_component_factory_register_source_component_class( struct bt_component_factory *factory, const char *name, diff --git a/include/babeltrace/plugin/plugin-internal.h b/include/babeltrace/plugin/plugin-internal.h index 75343239..b33eb2e3 100644 --- a/include/babeltrace/plugin/plugin-internal.h +++ b/include/babeltrace/plugin/plugin-internal.h @@ -51,13 +51,15 @@ struct bt_plugin { const char *license; const char *description; GString *path; - bt_plugin_init_func init; - bt_plugin_exit_func exit; + bt_plugin_register_func _register; GModule *module; }; BT_HIDDEN -struct bt_plugin *bt_plugin_create(GModule *module, const char *path); +struct bt_plugin *bt_plugin_create_from_module(GModule *module, const char *path); + +BT_HIDDEN +struct bt_plugin *bt_plugin_create_from_static(size_t i); BT_HIDDEN enum bt_component_status bt_plugin_register_component_classes( diff --git a/include/babeltrace/plugin/plugin-macros.h b/include/babeltrace/plugin/plugin-macros.h index 4fb107f9..f94c3579 100644 --- a/include/babeltrace/plugin/plugin-macros.h +++ b/include/babeltrace/plugin/plugin-macros.h @@ -30,14 +30,29 @@ #include #include +#include -/* A plugin must define the __bt_plugin_init symbol */ +#ifndef BT_BUILT_IN_PLUGINS + +#define BT_PLUGIN_REGISTER(_x) bt_plugin_register_func __bt_plugin_register = (_x) #define BT_PLUGIN_NAME(_x) const char __bt_plugin_name[] = (_x) #define BT_PLUGIN_AUTHOR(_x) const char __bt_plugin_author[] = (_x) #define BT_PLUGIN_LICENSE(_x) const char __bt_plugin_license[] = (_x) #define BT_PLUGIN_DESCRIPTION(_x) const char __bt_plugin_description[] = (_x) -#define BT_PLUGIN_INIT(_x) bt_plugin_init_func __bt_plugin_init = (_x) -#define BT_PLUGIN_EXIT(_x) bt_plugin_exit_func __bt_plugin_exit = (_x) + +#else /* BT_BUILT_IN_PLUGINS */ + +/* + * Statically-linked plug-in symbol types are stored in separate sections and + * which are read using the bt_component_factory interface. + */ +#define BT_PLUGIN_REGISTER(_x) static bt_plugin_register_func __attribute__((section("__plugin_register_funcs"), used)) __plugin_register = (_x) +#define BT_PLUGIN_NAME(_x) static const char *__plugin_name __attribute__((section("__plugin_names"), used)) = (_x) +#define BT_PLUGIN_AUTHOR(_x) static const char *__plugin_author __attribute__((section("__plugin_authors"), used)) = (_x) +#define BT_PLUGIN_LICENSE(_x) static const char *__plugin_license __attribute__((section("__plugin_licenses"), used)) = (_x) +#define BT_PLUGIN_DESCRIPTION(_x) static const char *__plugin_description __attribute__((section("__plugin_descriptions"), used)) = (_x) + +#endif /* BT_BUILT_IN_PLUGINS */ #define BT_PLUGIN_COMPONENT_CLASSES_BEGIN \ static enum bt_component_status __bt_plugin_register_component_classes( \ @@ -60,6 +75,6 @@ return BT_COMPONENT_STATUS_OK; \ } \ \ - BT_PLUGIN_INIT(__bt_plugin_register_component_classes); \ + BT_PLUGIN_REGISTER(__bt_plugin_register_component_classes); \ #endif /* BABELTRACE_PLUGIN_MACROS_H */ diff --git a/include/babeltrace/plugin/plugin-system.h b/include/babeltrace/plugin/plugin-system.h index 70b67cfd..e471a0dd 100644 --- a/include/babeltrace/plugin/plugin-system.h +++ b/include/babeltrace/plugin/plugin-system.h @@ -43,9 +43,8 @@ struct bt_component; struct bt_component_factory; struct bt_value; -typedef enum bt_component_status (*bt_plugin_init_func)( +typedef enum bt_component_status (*bt_plugin_register_func)( struct bt_component_factory *factory); -typedef void (*bt_plugin_exit_func)(void); /** * Component private data deallocation function type. diff --git a/lib/plugin-system/component-factory.c b/lib/plugin-system/component-factory.c index 8fe32f81..471b4b87 100644 --- a/lib/plugin-system/component-factory.c +++ b/lib/plugin-system/component-factory.c @@ -48,6 +48,8 @@ #define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \ sizeof(LIBTOOL_PLUGIN_SUFFIX)) +DECLARE_PLUG_IN_SECTIONS; + /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */ static struct dirent *alloc_dirent(const char *path) @@ -65,13 +67,36 @@ struct dirent *alloc_dirent(const char *path) return entry; } +static +enum bt_component_factory_status init_plugin( + struct bt_component_factory *factory, struct bt_plugin *plugin) +{ + enum bt_component_status component_status; + enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK; + + BT_MOVE(factory->current_plugin, plugin); + component_status = bt_plugin_register_component_classes( + factory->current_plugin, factory); + BT_PUT(factory->current_plugin); + if (component_status != BT_COMPONENT_STATUS_OK) { + switch (component_status) { + case BT_COMPONENT_STATUS_NOMEM: + ret = BT_COMPONENT_FACTORY_STATUS_NOMEM; + break; + default: + ret = BT_COMPONENT_FACTORY_STATUS_ERROR; + break; + } + } + return ret; +} + static enum bt_component_factory_status bt_component_factory_load_file(struct bt_component_factory *factory, const char *path) { enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK; - enum bt_component_status component_status; size_t path_len; GModule *module; struct bt_plugin *plugin; @@ -112,33 +137,17 @@ bt_component_factory_load_file(struct bt_component_factory *factory, goto end; } - /* Load plugin and make sure it defines the required entry points */ - plugin = bt_plugin_create(module, path); + /* Load plugin and make sure it defines the required entry points. */ + plugin = bt_plugin_create_from_module(module, path); if (!plugin) { ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN; if (!g_module_close(module)) { - printf_error("Module close error: %s", + printf_error("Module close error: %s\n", g_module_error()); } goto end; } - - BT_MOVE(factory->current_plugin, plugin); - component_status = bt_plugin_register_component_classes( - factory->current_plugin, factory); - BT_PUT(factory->current_plugin); - if (component_status != BT_COMPONENT_STATUS_OK) { - switch (component_status) { - case BT_COMPONENT_STATUS_NOMEM: - ret = BT_COMPONENT_FACTORY_STATUS_NOMEM; - break; - default: - ret = BT_COMPONENT_FACTORY_STATUS_ERROR; - break; - } - - goto end; - } + ret = init_plugin(factory, plugin); end: return ret; } @@ -398,6 +407,39 @@ enum bt_component_factory_status bt_component_factory_load( return _bt_component_factory_load(factory, path, false); } +enum bt_component_factory_status bt_component_factory_load_static( + struct bt_component_factory *factory) +{ + size_t count, i; + enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK; + + PRINT_PLUG_IN_SECTIONS(printf_verbose); + + count = SECTION_ELEMENT_COUNT(__plugin_register_funcs); + if (SECTION_ELEMENT_COUNT(__plugin_register_funcs) != count || + SECTION_ELEMENT_COUNT(__plugin_names) != count || + SECTION_ELEMENT_COUNT(__plugin_authors) != count || + SECTION_ELEMENT_COUNT(__plugin_licenses) != count || + SECTION_ELEMENT_COUNT(__plugin_descriptions) != count) { + printf_error("Some statically-linked plug-ins do not define all mandatory symbols\n"); + ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN; + goto end; + } + printf_verbose("Detected %zu statically-linked plug-ins\n", count); + + for (i = 0; i < count; i++) { + struct bt_plugin *plugin = bt_plugin_create_from_static(i); + + if (!plugin) { + continue; + } + + (void) init_plugin(factory, plugin); + } +end: + return ret; +} + static enum bt_component_factory_status add_component_class(struct bt_component_factory *factory, const char *name, diff --git a/lib/plugin-system/plugin.c b/lib/plugin-system/plugin.c index 8bc0fc09..d6aca933 100644 --- a/lib/plugin-system/plugin.c +++ b/lib/plugin-system/plugin.c @@ -29,15 +29,17 @@ #include #include #include +#include #include #define PLUGIN_SYMBOL_NAME "__bt_plugin_name" #define PLUGIN_SYMBOL_AUTHOR "__bt_plugin_author" #define PLUGIN_SYMBOL_LICENSE "__bt_plugin_license" -#define PLUGIN_SYMBOL_INIT "__bt_plugin_init" -#define PLUGIN_SYMBOL_EXIT "__bt_plugin_exit" +#define PLUGIN_SYMBOL_REGISTER "__bt_plugin_register" #define PLUGIN_SYMBOL_DESCRIPTION "__bt_plugin_description" +DECLARE_PLUG_IN_SECTIONS; + static void bt_plugin_destroy(struct bt_object *obj) { @@ -46,23 +48,22 @@ void bt_plugin_destroy(struct bt_object *obj) assert(obj); plugin = container_of(obj, struct bt_plugin, base); - if (plugin->exit) { - plugin->exit(); - } - if (plugin->module) { if (!g_module_close(plugin->module)) { - printf_error("Module close error: %s", + printf_error("Module close error: %s\n", g_module_error()); } } - g_string_free(plugin->path, TRUE); + if (plugin->path) { + g_string_free(plugin->path, TRUE); + } g_free(plugin); } BT_HIDDEN -struct bt_plugin *bt_plugin_create(GModule *module, const char *path) +struct bt_plugin *bt_plugin_create_from_module(GModule *module, + const char *path) { struct bt_plugin *plugin = NULL; gpointer symbol = NULL; @@ -95,32 +96,60 @@ struct bt_plugin *bt_plugin_create(GModule *module, const char *path) PLUGIN_SYMBOL_LICENSE, g_module_name(module)); goto error; } - if (!g_module_symbol(module, PLUGIN_SYMBOL_INIT, &symbol)) { - printf_error("Unable to resolve plugin symbol %s from %s", - PLUGIN_SYMBOL_INIT, g_module_name(module)); + if (!g_module_symbol(module, PLUGIN_SYMBOL_AUTHOR, + (gpointer *) &plugin->author)) { + printf_verbose("Unable to resolve plugin symbol %s from %s\n", + PLUGIN_SYMBOL_AUTHOR, g_module_name(module)); + goto error; + } + if (!g_module_symbol(module, PLUGIN_SYMBOL_DESCRIPTION, + (gpointer *) &plugin->description)) { + printf_verbose("Unable to resolve plugin symbol %s from %s\n", + PLUGIN_SYMBOL_DESCRIPTION, + g_module_name(module)); + goto error; + } + if (!g_module_symbol(module, PLUGIN_SYMBOL_REGISTER, &symbol)) { + printf_verbose("Unable to resolve plugin symbol %s from %s\n", + PLUGIN_SYMBOL_REGISTER, g_module_name(module)); goto error; } else { - plugin->init = *((bt_plugin_init_func *) symbol); - if (!plugin->init) { - printf_error("NULL %s symbol target", - PLUGIN_SYMBOL_INIT); + plugin->_register = *((bt_plugin_register_func *) symbol); + if (!plugin->_register) { + printf_verbose("NULL %s symbol target\n", + PLUGIN_SYMBOL_REGISTER); goto error; } } - /* Optional */ - if (g_module_symbol(module, PLUGIN_SYMBOL_EXIT, - (gpointer *) &symbol)) { - plugin->exit = *((bt_plugin_exit_func *) symbol); + return plugin; +error: + BT_PUT(plugin); + return plugin; +} + +BT_HIDDEN +struct bt_plugin *bt_plugin_create_from_static(size_t i) +{ + struct bt_plugin *plugin = NULL; + + plugin = g_new0(struct bt_plugin, 1); + if (!plugin) { + goto error; } - g_module_symbol(module, PLUGIN_SYMBOL_AUTHOR, - (gpointer *) &plugin->author); - g_module_symbol(module, PLUGIN_SYMBOL_DESCRIPTION, - (gpointer *) &plugin->description); + bt_object_init(plugin, bt_plugin_destroy); + plugin->_register = (SECTION_BEGIN(__plugin_register_funcs))[i]; + if (!plugin->_register) { + goto error; + } + plugin->name = (SECTION_BEGIN(__plugin_names))[i]; + plugin->author = (SECTION_BEGIN(__plugin_authors))[i]; + plugin->license = (SECTION_BEGIN(__plugin_licenses))[i]; + plugin->description = (SECTION_BEGIN(__plugin_descriptions))[i]; return plugin; error: - BT_PUT(plugin); + BT_PUT(plugin); return plugin; } @@ -129,7 +158,7 @@ enum bt_component_status bt_plugin_register_component_classes( struct bt_plugin *plugin, struct bt_component_factory *factory) { assert(plugin && factory); - return plugin->init(factory); + return plugin->_register(factory); } const char *bt_plugin_get_name(struct bt_plugin *plugin) @@ -149,7 +178,7 @@ const char *bt_plugin_get_license(struct bt_plugin *plugin) const char *bt_plugin_get_path(struct bt_plugin *plugin) { - return plugin ? plugin->path->str : NULL; + return (plugin && plugin->path) ? plugin->path->str : NULL; } const char *bt_plugin_get_description(struct bt_plugin *plugin) -- 2.34.1