Add support for statically-built plug-ins
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 27 Oct 2016 23:08:02 +0000 (19:08 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sat, 27 May 2017 18:09:06 +0000 (14:09 -0400)
./configure --disable-shared BUILT_IN_PLUGINS=1

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
configure.ac
converter/Makefile.am
converter/babeltrace.c
include/babeltrace/plugin/component-factory-internal.h
include/babeltrace/plugin/component-factory.h
include/babeltrace/plugin/plugin-internal.h
include/babeltrace/plugin/plugin-macros.h
include/babeltrace/plugin/plugin-system.h
lib/plugin-system/component-factory.c
lib/plugin-system/plugin.c

index afc696d910d479d0f85b2a13cf313982af23b484..1c49db8152092247c7010dd09580c4a05f9961c7 100644 (file)
@@ -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`"
index 5909e2a3a7ff2dc7b412b0567d3b4cde183bc206..a0eafaa05ab00fb3b1d8f41f5886e0070db50656 100644 (file)
@@ -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 = \
index 1c696545e92c35f176d5251e89797643b2a6692a..d619066d84b5722720200be4cd72b3eddee09729 100644 (file)
@@ -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,
index 9cb07ec22f526ea79ed3e809f49f1fc728768773..10a2b7872b77a7794784cec53dd4df77b10210e9 100644 (file)
 #include <babeltrace/plugin/plugin.h>
 #include <glib.h>
 
+#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 */
index a36d6b72eae2a189d583677c600bd09e589dff2e..95c5767bdfd2c87aa7b2086ac7a7a9f19df95fda 100644 (file)
@@ -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,
index 75343239563a4b4bb51ab250ad2e0c300c435f63..b33eb2e37dd5fb5eb0cc6d92fc0348ed995373ac 100644 (file)
@@ -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(
index 4fb107f938943092ee0440fd307a66fc57025ed1..f94c35793fac543e93f40472176a704c14fd7e40 100644 (file)
 
 #include <babeltrace/plugin/component-factory.h>
 #include <babeltrace/plugin/component.h>
+#include <babeltrace/plugin/plugin.h>
 
-/* 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 */
index 70b67cfddf5c6b78c6aca7364d9877feb9ffe548..e471a0dd0c382293dd27605954e98b6117e66ba1 100644 (file)
@@ -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.
index 8fe32f816647531c37b08a3121c3f09089aa50e5..471b4b877a26b350ce261c83a8a1f345e40019f9 100644 (file)
@@ -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,
index 8bc0fc09c3f049af24ed1c854a08012afdc8baa8..d6aca93356afc00ed108bb92472fd21afaca43a5 100644 (file)
 #include <babeltrace/compiler.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/plugin/plugin-internal.h>
+#include <babeltrace/plugin/component-factory-internal.h>
 #include <glib.h>
 
 #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)
This page took 0.03253 seconds and 4 git commands to generate.