From 6fbd4105b92d0da8b3c5818a5b7c5b07850f4a01 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Wed, 8 Mar 2017 14:00:07 -0500 Subject: [PATCH] Put Python plugin support in a separate shared object MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This is to make the work of packagers easier for libbabeltrace not to depend on libpython, even if you need Python plugin support. With this patch, python.c's constructor tries to open the new Python plugin provider shared object. If it fails, Python plugin support is disabled, but shared object plugins can still be loaded. The new BUILT_IN_PYTHON_PLUGIN_SUPPORT configure variable, if set to 1, makes the build embed the Python plugin provider into libbabeltrace (like before this patch). Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- Makefile.am | 20 ++- configure.ac | 15 ++ include/Makefile.am | 2 - include/babeltrace/babeltrace-internal.h | 3 + include/babeltrace/plugin/plugin-internal.h | 105 ++++++++++++- .../plugin/plugin-python-disabled-internal.h | 41 ----- .../babeltrace/plugin/plugin-so-internal.h | 3 - ...al.h => python-plugin-provider-internal.h} | 19 +-- lib/Makefile.am | 4 + lib/plugin/Makefile.am | 7 +- lib/plugin/plugin-so.c | 3 +- lib/plugin/plugin.c | 142 +++++------------- python-plugin-provider/Makefile.am | 7 + .../python-plugin-provider.c | 10 +- 14 files changed, 202 insertions(+), 179 deletions(-) delete mode 100644 include/babeltrace/plugin/plugin-python-disabled-internal.h rename include/babeltrace/plugin/{plugin-python-enabled-internal.h => python-plugin-provider-internal.h} (77%) create mode 100644 python-plugin-provider/Makefile.am rename lib/plugin/plugin-python.c => python-plugin-provider/python-plugin-provider.c (98%) diff --git a/Makefile.am b/Makefile.am index 4b517db7..1d66b1d4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,25 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = include common types compat lib formats plugins converter bindings tests doc extras +SUBDIRS = \ + include \ + common \ + types \ + compat + +if WITH_PYTHON_PLUGINS +SUBDIRS += python-plugin-provider +endif + +SUBDIRS += \ + lib \ + formats \ + plugins \ + converter \ + bindings \ + tests \ + doc \ + extras dist_doc_DATA = ChangeLog LICENSE mit-license.txt gpl-2.0.txt \ std-ext-lib.txt README diff --git a/configure.ac b/configure.ac index d48be53b..0f318214 100644 --- a/configure.ac +++ b/configure.ac @@ -376,6 +376,16 @@ AS_IF([test "x$BUILT_IN_PLUGINS" != x], [ ]) AM_CONDITIONAL([BUILT_IN_PLUGINS], [test "x$built_in_plugins" = "xyes"]) +AC_ARG_VAR([BUILT_IN_PYTHON_PLUGIN_SUPPORT], [Statically-link Python plugin support into the babeltrace binary]) +AS_IF([test "x$BUILT_IN_PYTHON_PLUGIN_SUPPORT" != 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 Python plugin support in the babeltrace executable)]) + AS_IF([test "x$enable_shared" = "xyes"], [AC_MSG_ERROR(--disable-shared must be used to bundle Python plugin support in the babeltrace executable)]) + built_in_python_plugin_support=yes + AC_DEFINE([BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT], [1], [Define to 1 to register plug-in attributes in static executable sections]) +]) +AM_CONDITIONAL([BUILT_IN_PYTHON_PLUGIN_SUPPORT], [test "x$built_in_python_plugin_support" = "xyes"]) + PKG_CHECK_MODULES(GMODULE, [gmodule-2.0 >= 2.0.0]) LIBS="$LIBS $GMODULE_LIBS" @@ -496,6 +506,7 @@ AC_CONFIG_FILES([ plugins/utils/Makefile plugins/utils/dummy/Makefile plugins/utils/trimmer/Makefile + python-plugin-provider/Makefile babeltrace.pc babeltrace-ctf.pc ]) @@ -571,6 +582,10 @@ PPRINT_PROP_BOOL([Python bindings tests], $value) test "x$enable_python_plugins" = "xyes" && value=1 || value=0 PPRINT_PROP_BOOL([Python plugin support], $value) +# built-in Python plugin support enabled/disabled +test "x$built_in_python_plugin_support" = "xyes" && value=1 || value=0 +PPRINT_PROP_BOOL([Built-in Python plugin support], $value) + # debug info enabled/disabled test "x$_enable_debug_info" = "xyes" && value=1 || value=0 PPRINT_PROP_BOOL([Debug information output], $value) diff --git a/include/Makefile.am b/include/Makefile.am index ba2ad2bf..b4d86ecc 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -126,8 +126,6 @@ noinst_HEADERS = \ babeltrace/mmap-align.h \ babeltrace/plugin/plugin-internal.h \ babeltrace/plugin/plugin-so-internal.h \ - babeltrace/plugin/plugin-python-enabled-internal.h \ - babeltrace/plugin/plugin-python-disabled-internal.h \ babeltrace/component/component-class-internal.h \ babeltrace/component/connection-internal.h \ babeltrace/component/port-internal.h \ diff --git a/include/babeltrace/babeltrace-internal.h b/include/babeltrace/babeltrace-internal.h index c3ed6f97..535f9909 100644 --- a/include/babeltrace/babeltrace-internal.h +++ b/include/babeltrace/babeltrace-internal.h @@ -180,6 +180,9 @@ extern bool babeltrace_verbose, babeltrace_debug; #define BT_CTF_MAJOR 1 #define BT_CTF_MINOR 8 +#define __STRINGIFY(x) #x +#define TOSTRING(x) __STRINGIFY(x) + struct bt_trace_descriptor; struct trace_collection { GPtrArray *array; /* struct bt_trace_descriptor */ diff --git a/include/babeltrace/plugin/plugin-internal.h b/include/babeltrace/plugin/plugin-internal.h index eb72e944..9b66836f 100644 --- a/include/babeltrace/plugin/plugin-internal.h +++ b/include/babeltrace/plugin/plugin-internal.h @@ -69,10 +69,111 @@ struct bt_plugin { /* Value depends on the specific plugin type */ void *spec_data; + void (*destroy_spec_data)(struct bt_plugin *); }; -BT_HIDDEN -struct bt_plugin *bt_plugin_create_empty(enum bt_plugin_type type); +static inline +void bt_plugin_destroy(struct bt_object *obj) +{ + struct bt_plugin *plugin; + + assert(obj); + plugin = container_of(obj, struct bt_plugin, base); + + if (plugin->destroy_spec_data) { + plugin->destroy_spec_data(plugin); + } + + if (plugin->comp_classes) { + g_ptr_array_free(plugin->comp_classes, TRUE); + } + + if (plugin->info.name) { + g_string_free(plugin->info.name, TRUE); + } + + if (plugin->info.path) { + g_string_free(plugin->info.path, TRUE); + } + + if (plugin->info.description) { + g_string_free(plugin->info.description, TRUE); + } + + if (plugin->info.author) { + g_string_free(plugin->info.author, TRUE); + } + + if (plugin->info.license) { + g_string_free(plugin->info.license, TRUE); + } + + if (plugin->info.version.extra) { + g_string_free(plugin->info.version.extra, TRUE); + } + + g_free(plugin); +} + +static inline +struct bt_plugin *bt_plugin_create_empty(enum bt_plugin_type type) +{ + struct bt_plugin *plugin = NULL; + + plugin = g_new0(struct bt_plugin, 1); + if (!plugin) { + goto error; + } + + bt_object_init(plugin, bt_plugin_destroy); + plugin->type = type; + + /* Create empty array of component classes */ + plugin->comp_classes = + g_ptr_array_new_with_free_func((GDestroyNotify) bt_put); + if (!plugin->comp_classes) { + goto error; + } + + /* Create empty info */ + plugin->info.name = g_string_new(NULL); + if (!plugin->info.name) { + goto error; + } + + plugin->info.path = g_string_new(NULL); + if (!plugin->info.path) { + goto error; + } + + plugin->info.description = g_string_new(NULL); + if (!plugin->info.description) { + goto error; + } + + plugin->info.author = g_string_new(NULL); + if (!plugin->info.author) { + goto error; + } + + plugin->info.license = g_string_new(NULL); + if (!plugin->info.license) { + goto error; + } + + plugin->info.version.extra = g_string_new(NULL); + if (!plugin->info.version.extra) { + goto error; + } + + goto end; + +error: + BT_PUT(plugin); + +end: + return plugin; +} static inline void bt_plugin_set_path(struct bt_plugin *plugin, const char *path) diff --git a/include/babeltrace/plugin/plugin-python-disabled-internal.h b/include/babeltrace/plugin/plugin-python-disabled-internal.h deleted file mode 100644 index dec6fc13..00000000 --- a/include/babeltrace/plugin/plugin-python-disabled-internal.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef BABELTRACE_PLUGIN_PLUGIN_PYTHON_DISABLED_INTERNAL_H -#define BABELTRACE_PLUGIN_PLUGIN_PYTHON_DISABLED_INTERNAL_H - -/* - * BabelTrace - Babeltrace Plug-in Interface - * - * Copyright 2017 Philippe Proulx - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -struct bt_plugin; - -static inline -struct bt_plugin **bt_plugin_python_create_all_from_file(const char *path) -{ - return NULL; -} - -static inline -void bt_plugin_python_destroy_spec_data(struct bt_plugin *plugin) -{ -} - -#endif /* BABELTRACE_PLUGIN_PLUGIN_PYTHON_DISABLED_INTERNAL_H */ diff --git a/include/babeltrace/plugin/plugin-so-internal.h b/include/babeltrace/plugin/plugin-so-internal.h index 4e3bc866..e2dd51c0 100644 --- a/include/babeltrace/plugin/plugin-so-internal.h +++ b/include/babeltrace/plugin/plugin-so-internal.h @@ -64,7 +64,4 @@ BT_HIDDEN int bt_plugin_so_on_add_component_class(struct bt_plugin *plugin, struct bt_component_class *comp_class); -BT_HIDDEN -void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin); - #endif /* BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H */ diff --git a/include/babeltrace/plugin/plugin-python-enabled-internal.h b/include/babeltrace/plugin/python-plugin-provider-internal.h similarity index 77% rename from include/babeltrace/plugin/plugin-python-enabled-internal.h rename to include/babeltrace/plugin/python-plugin-provider-internal.h index b1d0345f..acf913ff 100644 --- a/include/babeltrace/plugin/plugin-python-enabled-internal.h +++ b/include/babeltrace/plugin/python-plugin-provider-internal.h @@ -1,9 +1,7 @@ -#ifndef BABELTRACE_PLUGIN_PLUGIN_PYTHON_ENABLED_INTERNAL_H -#define BABELTRACE_PLUGIN_PLUGIN_PYTHON_ENABLED_INTERNAL_H +#ifndef BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H +#define BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H -/* - * BabelTrace - Babeltrace Plug-in Interface - * +/* * * Copyright 2017 Philippe Proulx * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -25,14 +23,9 @@ * SOFTWARE. */ -struct bt_plugin; +#include -BT_HIDDEN +extern struct bt_plugin **bt_plugin_python_create_all_from_file(const char *path); -static inline -void bt_plugin_python_destroy_spec_data(struct bt_plugin *plugin) -{ -} - -#endif /* BABELTRACE_PLUGIN_PLUGIN_PYTHON_ENABLED_INTERNAL_H */ +#endif /* BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H */ diff --git a/lib/Makefile.am b/lib/Makefile.am index c47d581b..0ba33f39 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -34,3 +34,7 @@ libbabeltrace_la_LIBADD = \ component/libcomponent.la \ plugin/libplugin.la \ $(top_builddir)/common/libbabeltrace-common.la + +if BUILT_IN_PYTHON_PLUGIN_SUPPORT +libbabeltrace_la_LIBADD += $(top_builddir)/python-plugin-provider/libbabeltrace-python-plugin-provider.la +endif diff --git a/lib/plugin/Makefile.am b/lib/plugin/Makefile.am index 355a31f8..467bbc52 100644 --- a/lib/plugin/Makefile.am +++ b/lib/plugin/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = $(PYTHON_INCLUDE) $(PACKAGE_CFLAGS) -I$(top_srcdir)/include +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include noinst_LTLIBRARIES = libplugin.la @@ -6,8 +6,3 @@ noinst_LTLIBRARIES = libplugin.la libplugin_la_SOURCES = \ plugin.c \ plugin-so.c - -if WITH_PYTHON_PLUGINS -libplugin_la_SOURCES += plugin-python.c -libplugin_la_LDFLAGS = $(PYTHON_LIBS) -endif diff --git a/lib/plugin/plugin-so.c b/lib/plugin/plugin-so.c index 24478f1f..96f21458 100644 --- a/lib/plugin/plugin-so.c +++ b/lib/plugin/plugin-so.c @@ -188,7 +188,7 @@ end: return shared_lib_handle; } -BT_HIDDEN +static void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin) { struct bt_plugin_so_spec_data *spec = plugin->spec_data; @@ -642,6 +642,7 @@ struct bt_plugin *bt_plugin_so_create_empty( goto error; } + plugin->destroy_spec_data = bt_plugin_so_destroy_spec_data; plugin->spec_data = g_new0(struct bt_plugin_so_spec_data, 1); if (!plugin->spec_data) { goto error; diff --git a/lib/plugin/plugin.c b/lib/plugin/plugin.c index 0e628890..83f628cd 100644 --- a/lib/plugin/plugin.c +++ b/lib/plugin/plugin.c @@ -27,6 +27,7 @@ * SOFTWARE. */ +#include #include #include #include @@ -38,118 +39,46 @@ #include #include -#ifdef WITH_PYTHON_PLUGINS -# include -#else -# include -#endif +#define PYTHON_PLUGIN_PROVIDER_FILENAME "libbabeltrace-python-plugin-provider." G_MODULE_SUFFIX +#define PYTHON_PLUGIN_PROVIDER_SYM_NAME bt_plugin_python_create_all_from_file +#define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR TOSTRING(PYTHON_PLUGIN_PROVIDER_SYM_NAME) +#ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT +#include static -void bt_plugin_destroy(struct bt_object *obj) -{ - struct bt_plugin *plugin; - - assert(obj); - plugin = container_of(obj, struct bt_plugin, base); - - if (plugin->type == BT_PLUGIN_TYPE_SO) { - bt_plugin_so_destroy_spec_data(plugin); - } else if (plugin->type == BT_PLUGIN_TYPE_PYTHON) { - bt_plugin_python_destroy_spec_data(plugin); - } else { - assert(false); - } - - if (plugin->comp_classes) { - g_ptr_array_free(plugin->comp_classes, TRUE); - } - - if (plugin->info.name) { - g_string_free(plugin->info.name, TRUE); - } - - if (plugin->info.path) { - g_string_free(plugin->info.path, TRUE); - } - - if (plugin->info.description) { - g_string_free(plugin->info.description, TRUE); - } - - if (plugin->info.author) { - g_string_free(plugin->info.author, TRUE); - } +struct bt_plugin **(*bt_plugin_python_create_all_from_file_sym)(const char *path) = + bt_plugin_python_create_all_from_file; +#else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */ +static GModule *python_plugin_provider_module; +static +struct bt_plugin **(*bt_plugin_python_create_all_from_file_sym)(const char *path); - if (plugin->info.license) { - g_string_free(plugin->info.license, TRUE); +__attribute__((constructor)) static +void init_python_plugin_provider(void) { + python_plugin_provider_module = + g_module_open(PYTHON_PLUGIN_PROVIDER_FILENAME, + G_MODULE_BIND_LOCAL); + if (!python_plugin_provider_module) { + printf_warning("Cannot find `%s`: Python plugin support is disabled\n", + PYTHON_PLUGIN_PROVIDER_FILENAME); + return; } - if (plugin->info.version.extra) { - g_string_free(plugin->info.version.extra, TRUE); + if (!g_module_symbol(python_plugin_provider_module, + PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR, + (gpointer) &bt_plugin_python_create_all_from_file_sym)) { + printf_warning("Cannot find the Python plugin provider loading symbole: Python plugin support is disabled\n"); } - - g_free(plugin); } -BT_HIDDEN -struct bt_plugin *bt_plugin_create_empty(enum bt_plugin_type type) -{ - struct bt_plugin *plugin = NULL; - - plugin = g_new0(struct bt_plugin, 1); - if (!plugin) { - goto error; - } - - bt_object_init(plugin, bt_plugin_destroy); - plugin->type = type; - - /* Create empty array of component classes */ - plugin->comp_classes = - g_ptr_array_new_with_free_func((GDestroyNotify) bt_put); - if (!plugin->comp_classes) { - goto error; - } - - /* Create empty info */ - plugin->info.name = g_string_new(NULL); - if (!plugin->info.name) { - goto error; - } - - plugin->info.path = g_string_new(NULL); - if (!plugin->info.path) { - goto error; - } - - plugin->info.description = g_string_new(NULL); - if (!plugin->info.description) { - goto error; - } - - plugin->info.author = g_string_new(NULL); - if (!plugin->info.author) { - goto error; - } - - plugin->info.license = g_string_new(NULL); - if (!plugin->info.license) { - goto error; - } - - plugin->info.version.extra = g_string_new(NULL); - if (!plugin->info.version.extra) { - goto error; +__attribute__((destructor)) static +void fini_python_plugin_provider(void) { + if (python_plugin_provider_module) { + (void) g_module_close(python_plugin_provider_module); + python_plugin_provider_module = NULL; } - - goto end; - -error: - BT_PUT(plugin); - -end: - return plugin; } +#endif struct bt_plugin **bt_plugin_create_all_from_static(void) { @@ -172,9 +101,12 @@ struct bt_plugin **bt_plugin_create_all_from_file(const char *path) goto end; } - plugins = bt_plugin_python_create_all_from_file(path); - if (plugins) { - goto end; + /* Try Python plugins if support is available */ + if (bt_plugin_python_create_all_from_file_sym) { + plugins = bt_plugin_python_create_all_from_file_sym(path); + if (plugins) { + goto end; + } } end: diff --git a/python-plugin-provider/Makefile.am b/python-plugin-provider/Makefile.am new file mode 100644 index 00000000..f4776760 --- /dev/null +++ b/python-plugin-provider/Makefile.am @@ -0,0 +1,7 @@ +AM_CFLAGS = $(PYTHON_INCLUDE) $(PACKAGE_CFLAGS) -I$(top_srcdir)/include + +lib_LTLIBRARIES = libbabeltrace-python-plugin-provider.la + +libbabeltrace_python_plugin_provider_la_SOURCES = python-plugin-provider.c +libbabeltrace_python_plugin_provider_la_LDFLAGS = \ + -version-info $(BABELTRACE_LIBRARY_VERSION) $(PYTHON_LIBS) diff --git a/lib/plugin/plugin-python.c b/python-plugin-provider/python-plugin-provider.c similarity index 98% rename from lib/plugin/plugin-python.c rename to python-plugin-provider/python-plugin-provider.c index fc897ee3..20892fca 100644 --- a/lib/plugin/plugin-python.c +++ b/python-plugin-provider/python-plugin-provider.c @@ -1,7 +1,7 @@ /* - * plugin-python.c + * python-plugin-provider.c * - * Babeltrace Plugin (Python) + * Babeltrace Python plugin provider * * Copyright 2017 Philippe Proulx * @@ -28,11 +28,11 @@ #include #include #include -#include -#include #include #include #include +#include +#include #define PYTHON_PLUGIN_FILE_PREFIX "bt_plugin_" #define PYTHON_PLUGIN_FILE_PREFIX_LEN (sizeof(PYTHON_PLUGIN_FILE_PREFIX) - 1) @@ -344,7 +344,7 @@ end: return plugin; } -BT_HIDDEN +G_MODULE_EXPORT struct bt_plugin **bt_plugin_python_create_all_from_file(const char *path) { struct bt_plugin **plugins = NULL; -- 2.34.1