From: Simon Marchi Date: Tue, 5 Nov 2024 17:17:52 +0000 (-0500) Subject: bt2: generate native extension as C++ X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=4eb1d52dcae2;p=babeltrace.git bt2: generate native extension as C++ Make SWIG generate the native code in C++ rather than C. The differences in the generated file (`native_bt.cpp`, previously `native_bt.c`) are not significant (use of C++-style casts instead of C-style casts, use of new/delete instead malloc/free, etc), but it will allow us to use C++ in the typemap code. It will help to integrate better with other utils that are or will be written in C++. Unfortunately, this requires more distutils hackery. It looks like distutils (both the copies distributed with CPython < 3.12 and the copy in setuptools < 72.2.0) doesn't have good support for building objects from C++ files that will end up in shared objects. The `compiler_so` executable gets used, defined here [1] as using the C compiler. If using a recent enough compiler that defaults to C++11, it works (when calling `gcc` or `clang`, rather than `g++` or `clang++` they understand that you want to compile C++ based on the file suffix). But on an older system (e.g. SLES12) with gcc 4.8, we get errors like: In file included from bt2/native_bt.cpp:3296:0: /babeltrace/src/bindings/python/bt2/bt2/native_bt_autodisc.i.h: In function 'bt_value* bt_bt2_auto_discover_source_components(const bt_value*, const bt_plugin_set*)': /babeltrace/src/bindings/python/bt2/bt2/native_bt_autodisc.i.h:118:9: warning: 'auto' changes meaning in C++11; please remove it [-Wc++0x-compat] const auto autodisc_result = static_cast( ^ Things appear to have improved in setuptools 72.2.0 [2], where there's now a `compiler_so_cxx` executable that uses the C++ compiler. This release doesn't appear widely available in Linux distros right now (for instance Arch is still at 69.5.1), and we need to support distutils all the way back to Python 3.4 anyway. The new distutils hackery is inspired by this blog post [3]. The idea is to override the `build_extensions()` method of `distutils.command.build_ext.build_ext` method to set the executables on the `distutils.ccompiler.CCompiler` instance. Because this way of doing things overrides the flags previously determined by distutils, we can handle here the other hacks: - the hack to force our CFLAGS over sysconfig's CFLAGS (which now becomes CXXFLAGS because C++) - the hack to manually convert the include paths form on MinGW I add to the `compiler_so_cxx` command the result of `sysconfig.get_config_var("CCSHARED")`, which is analogous to what is done in [2]. On Linux, for instance, this contains `-fPIC`, which is necessary to produce objects files intended to be used in shared objects. [1] https://github.com/pypa/setuptools/blob/v72.1.0/setuptools/_distutils/sysconfig.py#L355-L357 [2] https://github.com/pypa/setuptools/blob/v72.2.0/setuptools/_distutils/sysconfig.py#L360-L363 [3] https://shwina.github.io/custom-compiler-linker-extensions/ Change-Id: I5999292d3a14948ef5f675a924e2360bc4d73f13 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/13431 --- diff --git a/src/autodisc/autodisc.h b/src/autodisc/autodisc.h index 6a51111c..f090682f 100644 --- a/src/autodisc/autodisc.h +++ b/src/autodisc/autodisc.h @@ -15,6 +15,10 @@ #include #undef __BT_IN_BABELTRACE_H +#ifdef __cplusplus +extern "C" { +#endif + struct auto_source_discovery { /* Array of `struct auto_source_discovery_result *`. */ GPtrArray *results; @@ -71,4 +75,8 @@ auto_source_discovery_status auto_discover_source_components( struct auto_source_discovery *auto_disc, const bt_interrupter *interrupter); +#ifdef __cplusplus +} +#endif + #endif /* BABELTRACE_AUTODISC_AUTODISC_H */ diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am index 718486fc..4819d421 100644 --- a/src/bindings/python/bt2/Makefile.am +++ b/src/bindings/python/bt2/Makefile.am @@ -56,8 +56,8 @@ SWIG_INTERFACE_FILES = \ # Non-generated files built into the native library. STATIC_NATIVE_LIB_SRCS = \ - bt2/logging.c \ - bt2/logging.h + bt2/logging.cpp \ + bt2/logging.hpp STATIC_BINDINGS_DEPS = \ bt2/__init__.py \ @@ -105,7 +105,7 @@ STATIC_LIBRARIES_DEPS = \ $(top_builddir)/src/string-format/libstring-format.la GENERATED_BINDINGS_DEPS = \ - bt2/native_bt.c \ + bt2/native_bt.cpp \ bt2/version.py \ setup.py @@ -114,34 +114,28 @@ GENERATED_BINDINGS_DEPS = \ # have renamed this global to `Swig_This_global`. # # Disable -Wshadow for that file. -WARN_CFLAGS = -Wno-shadow +WARN_CXXFLAGS = -Wno-shadow -WARN_CFLAGS += -Wno-null-dereference +WARN_CXXFLAGS += -Wno-null-dereference # Python 3.8 with SWIG 4.0.2 generates a deprecated warning for 'tp_print' # and in general there is not much we can do about deprecations in generated # code. -WARN_CFLAGS += -Wno-deprecated-declarations +WARN_CXXFLAGS += -Wno-deprecated-declarations # Python 3.11 + gcc 12.2.0 gave warnings of this kind in Python.h. -WARN_CFLAGS += -Wno-redundant-decls +WARN_CXXFLAGS += -Wno-redundant-decls # For SWIG generated code -WARN_CFLAGS += -Wno-missing-field-initializers -WARN_CFLAGS += -Wno-unused-parameter +WARN_CXXFLAGS += -Wno-missing-field-initializers +WARN_CXXFLAGS += -Wno-unused-parameter -# SWIG 4.2.0 generates: -# -# #if __cplusplus >=201103L -# -# ... leading to some `-Wundef` warnings when building the extension as C, where -# `__cplusplus` is not defined. -WARN_CFLAGS += -Wno-undef - -BUILD_FLAGS=CC="$(CC)" \ - CFLAGS="$(GLIB_CFLAGS) $(AM_CFLAGS) $(CFLAGS) $(WARN_CFLAGS)" \ - CPPFLAGS="$(AM_CPPFLAGS) $(CPPFLAGS) -I$(srcdir)/bt2" \ - LDFLAGS="$(AM_LDFLAGS) $(LDFLAGS) $(GLIB_LIBS) $(PYTHON_LDFLAGS) $(LIBS)" +BUILD_FLAGS= \ + CC="$(CC)" \ + CXX="$(CXX)" \ + CXXFLAGS="$(GLIB_CFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(WARN_CXXFLAGS)" \ + CPPFLAGS="$(AM_CPPFLAGS) $(CPPFLAGS) -I$(srcdir)/bt2" \ + LDFLAGS="$(AM_LDFLAGS) $(LDFLAGS) $(GLIB_LIBS) $(PYTHON_LDFLAGS) $(LIBS)" SETUP_PY=$(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py @@ -164,8 +158,8 @@ swig_verbose = $(swig_verbose_@AM_V@) swig_verbose_ = $(swig_verbose_@AM_DEFAULT_V@) swig_verbose_0 = @echo " SWIG " $@; -$(builddir)/bt2/native_bt.c: $(SWIG_INTERFACE_FILES) - $(swig_verbose)$(SWIG) -MD -python -I"$(top_srcdir)/include" -o "$@" "$<" +$(builddir)/bt2/native_bt.cpp: $(SWIG_INTERFACE_FILES) + $(swig_verbose)$(SWIG) -c++ -MD -python -I"$(top_srcdir)/include" -o "$@" "$<" -include bt2/native_bt.d @@ -214,7 +208,7 @@ EXTRA_DIST = $(STATIC_BINDINGS_DEPS) $(SWIG_INTERFACE_FILES) $(STATIC_NATIVE_LIB # clean: generated C and Python files (by SWIG) CLEANFILES = \ build-python-bindings.stamp \ - bt2/native_bt.c \ + bt2/native_bt.cpp \ bt2/native_bt.d \ bt2/native_bt.py \ copy-static-deps.stamp diff --git a/src/bindings/python/bt2/bt2/logging.c b/src/bindings/python/bt2/bt2/logging.c deleted file mode 100644 index 1855d0e0..00000000 --- a/src/bindings/python/bt2/bt2/logging.c +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2017 Philippe Proulx - */ - -#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level -#include "logging/log.h" - -BT_LOG_INIT_LOG_LEVEL(bt_python_bindings_bt2_log_level, - "BABELTRACE_PYTHON_BT2_LOG_LEVEL"); diff --git a/src/bindings/python/bt2/bt2/logging.cpp b/src/bindings/python/bt2/bt2/logging.cpp new file mode 100644 index 00000000..c20f292f --- /dev/null +++ b/src/bindings/python/bt2/bt2/logging.cpp @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2017 Philippe Proulx + */ + +#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level +#include "logging/log.h" + +BT_LOG_INIT_LOG_LEVEL(bt_python_bindings_bt2_log_level, "BABELTRACE_PYTHON_BT2_LOG_LEVEL"); diff --git a/src/bindings/python/bt2/bt2/logging.h b/src/bindings/python/bt2/bt2/logging.h deleted file mode 100644 index 9a4efebc..00000000 --- a/src/bindings/python/bt2/bt2/logging.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2017 Philippe Proulx - */ - -#ifndef BABELTRACE_BINDINGS_PYTHON_BT2_BT2_LOGGING_H -#define BABELTRACE_BINDINGS_PYTHON_BT2_BT2_LOGGING_H - -#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level -#include "logging/log.h" - -BT_LOG_LEVEL_EXTERN_SYMBOL(bt_python_bindings_bt2_log_level); - -#endif /* BABELTRACE_BINDINGS_PYTHON_BT2_BT2_LOGGING_H */ diff --git a/src/bindings/python/bt2/bt2/logging.hpp b/src/bindings/python/bt2/bt2/logging.hpp new file mode 100644 index 00000000..d26d7c7c --- /dev/null +++ b/src/bindings/python/bt2/bt2/logging.hpp @@ -0,0 +1,15 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2017 Philippe Proulx + */ + +#ifndef BABELTRACE_BINDINGS_PYTHON_BT2_BT2_LOGGING_HPP +#define BABELTRACE_BINDINGS_PYTHON_BT2_BT2_LOGGING_HPP + +#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level +#include "logging/log.h" + +BT_LOG_LEVEL_EXTERN_SYMBOL(bt_python_bindings_bt2_log_level); + +#endif /* BABELTRACE_BINDINGS_PYTHON_BT2_BT2_LOGGING_HPP */ diff --git a/src/bindings/python/bt2/bt2/native_bt.i b/src/bindings/python/bt2/bt2/native_bt.i index 5914f702..f2b0bebb 100644 --- a/src/bindings/python/bt2/bt2/native_bt.i +++ b/src/bindings/python/bt2/bt2/native_bt.i @@ -12,7 +12,7 @@ %{ #define BT_LOG_TAG "BT2-PY" -#include "logging.h" +#include "logging.hpp" /* * Include before `` because @@ -59,7 +59,7 @@ typedef uint64_t bt_listener_id; * functions on which we apply this typemap don't guarantee that the value of * `temp_value` will be unchanged or valid. */ -%typemap(in, numinputs=0) (const char **) (char *temp_value = (void *) 1) { +%typemap(in, numinputs=0) (const char **) (char *temp_value = reinterpret_cast(1)) { $1 = &temp_value; } @@ -248,6 +248,8 @@ void bt_bt2_exit_handler(void); * This function is defined by SWIG. Declare here to avoid a * -Wmissing-prototypes warning. */ -PyObject *SWIG_init(void); +extern "C" { + PyObject *SWIG_init(void); +} %} diff --git a/src/bindings/python/bt2/bt2/native_bt_autodisc.i.h b/src/bindings/python/bt2/bt2/native_bt_autodisc.i.h index f1629efb..5b856b69 100644 --- a/src/bindings/python/bt2/bt2/native_bt_autodisc.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_autodisc.i.h @@ -115,8 +115,8 @@ bt_value *bt_bt2_auto_discover_source_components(const bt_value *inputs, } for (i = 0; i < auto_disc.results->len; i++) { - struct auto_source_discovery_result *autodisc_result = - g_ptr_array_index(auto_disc.results, i); + const auto autodisc_result = static_cast( + g_ptr_array_index(auto_disc.results, i)); bt_value_array_append_element_status append_element_status; component_info = bt_value_array_create(); diff --git a/src/bindings/python/bt2/bt2/native_bt_component_class.i.h b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h index de11581a..7c93580f 100644 --- a/src/bindings/python/bt2/bt2/native_bt_component_class.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h @@ -255,7 +255,8 @@ bt_component_class_initialize_method_status component_class_init( BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING, log_level, self_component, "Failed to call Python class's _bt_init_from_native() method: " "py-cls-addr=%p", py_cls); - status = py_exc_to_status_component_clear(self_component); + status = static_cast( + py_exc_to_status_component_clear(self_component)); goto end; } @@ -333,8 +334,8 @@ component_class_get_supported_mip_versions( (enum bt_log_level) log_level, BT_LOG_TAG, "Failed to call Python class's _bt_get_supported_mip_versions_from_native() method: " "py-cls-addr=%p", py_cls); - status = py_exc_to_status_component_class_clear(self_component_class, - log_level); + status = static_cast( + py_exc_to_status_component_class_clear(self_component_class, log_level)); goto end; } @@ -343,7 +344,8 @@ component_class_get_supported_mip_versions( * (PyLong) containing the address of a BT unsigned integer * range set object (new reference). */ - ret_range_set = PyLong_AsVoidPtr(py_range_set_addr); + ret_range_set = static_cast( + PyLong_AsVoidPtr(py_range_set_addr)); BT_ASSERT(!PyErr_Occurred()); BT_ASSERT(ret_range_set); @@ -485,7 +487,8 @@ bt_component_class_initialize_method_status component_class_sink_init( static void component_class_finalize(bt_self_component *self_component) { - PyObject *py_comp = bt_self_component_get_data(self_component); + const auto py_comp = static_cast( + bt_self_component_get_data(self_component)); PyObject *py_method_result; BT_ASSERT(py_comp); @@ -642,17 +645,18 @@ bt_message_iterator_class_can_seek_beginning_method_status component_class_can_seek_beginning( bt_self_message_iterator *self_message_iterator, bt_bool *can_seek) { - PyObject *py_iter; PyObject *py_result = NULL; bt_message_iterator_class_can_seek_beginning_method_status status; - py_iter = bt_self_message_iterator_get_data(self_message_iterator); + const auto py_iter = static_cast( + bt_self_message_iterator_get_data(self_message_iterator)); BT_ASSERT(py_iter); py_result = PyObject_CallMethod(py_iter, "_bt_can_seek_beginning_from_native", NULL); if (!py_result) { - status = py_exc_to_status_message_iterator_clear(self_message_iterator); + status = static_cast( + py_exc_to_status_message_iterator_clear(self_message_iterator)); goto end; } @@ -671,18 +675,19 @@ static bt_message_iterator_class_seek_beginning_method_status component_class_seek_beginning(bt_self_message_iterator *self_message_iterator) { - PyObject *py_iter; PyObject *py_result; bt_message_iterator_class_seek_beginning_method_status status; + const auto py_iter = static_cast( + bt_self_message_iterator_get_data(self_message_iterator)); - py_iter = bt_self_message_iterator_get_data(self_message_iterator); BT_ASSERT(py_iter); py_result = PyObject_CallMethod(py_iter, "_bt_seek_beginning_from_native", NULL); if (!py_result) { - status = py_exc_to_status_message_iterator_clear(self_message_iterator); + status = static_cast( + py_exc_to_status_message_iterator_clear(self_message_iterator)); goto end; } @@ -702,17 +707,18 @@ component_class_can_seek_ns_from_origin( bt_self_message_iterator *self_message_iterator, int64_t ns_from_origin, bt_bool *can_seek) { - PyObject *py_iter; PyObject *py_result = NULL; bt_message_iterator_class_can_seek_ns_from_origin_method_status status; + const auto py_iter = static_cast( + bt_self_message_iterator_get_data(self_message_iterator)); - py_iter = bt_self_message_iterator_get_data(self_message_iterator); BT_ASSERT(py_iter); py_result = PyObject_CallMethod(py_iter, "_bt_can_seek_ns_from_origin_from_native", "L", ns_from_origin); if (!py_result) { - status = py_exc_to_status_message_iterator_clear(self_message_iterator); + status = static_cast( + py_exc_to_status_message_iterator_clear(self_message_iterator)); goto end; } @@ -733,17 +739,18 @@ component_class_seek_ns_from_origin( bt_self_message_iterator *self_message_iterator, int64_t ns_from_origin) { - PyObject *py_iter; PyObject *py_result; bt_message_iterator_class_seek_ns_from_origin_method_status status; + const auto py_iter = static_cast( + bt_self_message_iterator_get_data(self_message_iterator)); - py_iter = bt_self_message_iterator_get_data(self_message_iterator); BT_ASSERT(py_iter); py_result = PyObject_CallMethod(py_iter, "_bt_seek_ns_from_origin_from_native", "L", ns_from_origin); if (!py_result) { - status = py_exc_to_status_message_iterator_clear(self_message_iterator); + status = static_cast( + py_exc_to_status_message_iterator_clear(self_message_iterator)); goto end; } @@ -768,21 +775,21 @@ bt_component_class_port_connected_method_status component_class_port_connected( swig_type_info *other_port_swig_type) { bt_component_class_port_connected_method_status status; - PyObject *py_comp = NULL; PyObject *py_self_port_ptr = NULL; PyObject *py_other_port_ptr = NULL; PyObject *py_method_result = NULL; bt_logging_level log_level = get_self_component_log_level( self_component); + const auto py_comp = static_cast( + bt_self_component_get_data(self_component)); - py_comp = bt_self_component_get_data(self_component); BT_ASSERT(py_comp); py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port), self_component_port_swig_type, 0); if (!py_self_port_ptr) { BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, BT_FMT_SWIG_ALLOC_FAILED); - status = __BT_FUNC_STATUS_MEMORY_ERROR; + status = BT_COMPONENT_CLASS_PORT_CONNECTED_METHOD_STATUS_MEMORY_ERROR; goto end; } @@ -791,7 +798,7 @@ bt_component_class_port_connected_method_status component_class_port_connected( if (!py_other_port_ptr) { BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, BT_FMT_SWIG_ALLOC_FAILED); - status = __BT_FUNC_STATUS_MEMORY_ERROR; + status = BT_COMPONENT_CLASS_PORT_CONNECTED_METHOD_STATUS_MEMORY_ERROR; goto end; } @@ -799,7 +806,8 @@ bt_component_class_port_connected_method_status component_class_port_connected( "_bt_port_connected_from_native", "(OiO)", py_self_port_ptr, self_component_port_type, py_other_port_ptr); if (!py_method_result) { - status = py_exc_to_status_component_clear(self_component); + status = static_cast( + py_exc_to_status_component_clear(self_component)); goto end; } @@ -892,17 +900,17 @@ bt_component_class_sink_graph_is_configured_method_status component_class_sink_graph_is_configured( bt_self_component_sink *self_component_sink) { - PyObject *py_comp = NULL; PyObject *py_method_result = NULL; bt_component_class_sink_graph_is_configured_method_status status; bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); - - py_comp = bt_self_component_get_data(self_component); + const auto py_comp = static_cast( + bt_self_component_get_data(self_component)); py_method_result = PyObject_CallMethod(py_comp, "_bt_graph_is_configured_from_native", NULL); if (!py_method_result) { - status = py_exc_to_status_component_clear(self_component); + status = static_cast( + py_exc_to_status_component_clear(self_component)); goto end; } @@ -929,7 +937,8 @@ bt_component_class_query_method_status component_class_query( PyObject *py_query_func = NULL; PyObject *py_object = NULL; PyObject *py_results_addr = NULL; - bt_component_class_query_method_status status = __BT_FUNC_STATUS_OK; + bt_component_class_query_method_status status = + BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK; const bt_query_executor *query_exec = bt_private_query_executor_as_query_executor_const( priv_query_executor); @@ -992,8 +1001,8 @@ bt_component_class_query_method_status component_class_query( py_object, py_params_ptr, method_data ? method_data : Py_None); if (!py_results_addr) { - status = py_exc_to_status_component_class_clear(self_component_class, - log_level); + status = static_cast( + py_exc_to_status_component_class_clear(self_component_class, log_level)); if (status < 0) { #define BT_FMT "Failed to call Python class's _bt_query_from_native() method: py-cls-addr=%p" BT_LOG_WRITE_PRINTF_CUR_LVL(BT_LOG_WARNING, @@ -1011,14 +1020,14 @@ bt_component_class_query_method_status component_class_query( * (PyLong) containing the address of a BT value object (new * reference). */ - *result = PyLong_AsVoidPtr(py_results_addr); + *result = static_cast(PyLong_AsVoidPtr(py_results_addr)); BT_ASSERT(!PyErr_Occurred()); BT_ASSERT(*result); goto end; error: PyErr_Clear(); - status = __BT_FUNC_STATUS_ERROR; + status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR; end: Py_XDECREF(py_params_ptr); @@ -1081,7 +1090,8 @@ component_class_message_iterator_init( bt_self_message_iterator_configuration *config, bt_self_component_port_output *self_component_port_output) { - bt_message_iterator_class_initialize_method_status status = __BT_FUNC_STATUS_OK; + bt_message_iterator_class_initialize_method_status status = + BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK; PyObject *py_comp_cls = NULL; PyObject *py_iter_cls = NULL; PyObject *py_iter_ptr = NULL; @@ -1089,14 +1099,13 @@ component_class_message_iterator_init( PyObject *py_component_port_output_ptr = NULL; PyObject *py_init_method_result = NULL; PyObject *py_iter = NULL; - PyObject *py_comp; bt_self_component *self_component = bt_self_message_iterator_borrow_component( self_message_iterator); bt_logging_level log_level = get_self_component_log_level( self_component); - - py_comp = bt_self_component_get_data(self_component); + const auto py_comp = static_cast( + bt_self_component_get_data(self_component)); /* Find user's Python message iterator class */ py_comp_cls = PyObject_GetAttrString(py_comp, "__class__"); @@ -1204,12 +1213,13 @@ component_class_message_iterator_init( python_error: /* Handling of errors that cause a Python exception to be set. */ - status = py_exc_to_status_message_iterator_clear(self_message_iterator); + status = static_cast( + py_exc_to_status_message_iterator_clear(self_message_iterator)); goto end; error: /* Handling of errors that don't cause a Python exception to be set. */ - status = __BT_FUNC_STATUS_ERROR; + status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR; end: BT_ASSERT(!PyErr_Occurred()); @@ -1228,8 +1238,8 @@ static void component_class_message_iterator_finalize( bt_self_message_iterator *message_iterator) { - PyObject *py_message_iter = bt_self_message_iterator_get_data( - message_iterator); + const auto py_message_iter = static_cast( + bt_self_message_iterator_get_data(message_iterator)); PyObject *py_method_result = NULL; BT_ASSERT(py_message_iter); @@ -1269,14 +1279,16 @@ component_class_message_iterator_next( uint64_t *count) { bt_message_iterator_class_next_method_status status; - PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator); + const auto py_message_iter = static_cast( + bt_self_message_iterator_get_data(message_iterator)); PyObject *py_method_result = NULL; BT_ASSERT_DBG(py_message_iter); py_method_result = PyObject_CallMethod(py_message_iter, "_bt_next_from_native", NULL); if (!py_method_result) { - status = py_exc_to_status_message_iterator_clear(message_iterator); + status = static_cast( + py_exc_to_status_message_iterator_clear(message_iterator)); goto end; } @@ -1285,7 +1297,7 @@ component_class_message_iterator_next( * (PyLong) containing the address of a native message * object (which is now ours). */ - msgs[0] = PyLong_AsVoidPtr(py_method_result); + msgs[0] = static_cast(PyLong_AsVoidPtr(py_method_result)); *count = 1; /* Overflow errors should never happen. */ @@ -1303,7 +1315,7 @@ bt_component_class_sink_consume_method_status component_class_sink_consume(bt_self_component_sink *self_component_sink) { bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); - PyObject *py_comp = bt_self_component_get_data(self_component); + const auto py_comp = static_cast(bt_self_component_get_data(self_component)); PyObject *py_method_result = NULL; bt_component_class_sink_consume_method_status status; @@ -1312,7 +1324,8 @@ component_class_sink_consume(bt_self_component_sink *self_component_sink) py_method_result = PyObject_CallMethod(py_comp, "_user_consume", NULL); if (!py_method_result) { - status = py_exc_to_status_component_clear(self_component); + status = static_cast( + py_exc_to_status_component_clear(self_component)); goto end; } diff --git a/src/bindings/python/bt2/bt2/native_bt_event_class.i b/src/bindings/python/bt2/bt2/native_bt_event_class.i index b7f05bb8..a046dd86 100644 --- a/src/bindings/python/bt2/bt2/native_bt_event_class.i +++ b/src/bindings/python/bt2/bt2/native_bt_event_class.i @@ -9,7 +9,7 @@ */ %typemap(in, numinputs=0) (bt_event_class_log_level *) - (bt_event_class_log_level temp = -1) { + (bt_event_class_log_level temp = static_cast(-1)) { $1 = &temp; } diff --git a/src/bindings/python/bt2/bt2/native_bt_graph.i.h b/src/bindings/python/bt2/bt2/native_bt_graph.i.h index 8831e21a..dd51df30 100644 --- a/src/bindings/python/bt2/bt2/native_bt_graph.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_graph.i.h @@ -24,29 +24,29 @@ static bt_graph_listener_func_status port_added_listener( py_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component), component_swig_type, 0); if (!py_component_ptr) { BT_LOGF_STR("Failed to create component SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; + status = BT_GRAPH_LISTENER_FUNC_STATUS_MEMORY_ERROR; goto end; } py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(port), port_swig_type, 0); if (!py_port_ptr) { BT_LOGF_STR("Failed to create port SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; + status = BT_GRAPH_LISTENER_FUNC_STATUS_MEMORY_ERROR; goto end; } - py_res = PyObject_CallFunction(py_callable, "(OiOi)", + py_res = PyObject_CallFunction(static_cast(py_callable), "(OiOi)", py_component_ptr, component_class_type, py_port_ptr, port_type); if (!py_res) { loge_exception_append_cause_clear( "Graph's port added listener (Python)", BT_LOG_OUTPUT_LEVEL); - status = __BT_FUNC_STATUS_ERROR; + status = BT_GRAPH_LISTENER_FUNC_STATUS_ERROR; goto end; } BT_ASSERT(py_res == Py_None); - status = __BT_FUNC_STATUS_OK; + status = BT_GRAPH_LISTENER_FUNC_STATUS_OK; end: Py_XDECREF(py_res); diff --git a/src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h b/src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h index aaa88fca..13b9a093 100644 --- a/src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h @@ -51,10 +51,12 @@ static PyObject *bt_bt2_get_user_component_from_user_msg_iter( bt_self_message_iterator *self_message_iterator) { bt_self_component *self_component = bt_self_message_iterator_borrow_component(self_message_iterator); - PyObject *py_comp; BT_ASSERT_DBG(self_component); - py_comp = bt_self_component_get_data(self_component); + + const auto py_comp = static_cast( + bt_self_component_get_data(self_component)); + BT_ASSERT_DBG(py_comp); /* Return new reference */ diff --git a/src/bindings/python/bt2/bt2/native_bt_port.i b/src/bindings/python/bt2/bt2/native_bt_port.i index 1a0a50a5..c0b72076 100644 --- a/src/bindings/python/bt2/bt2/native_bt_port.i +++ b/src/bindings/python/bt2/bt2/native_bt_port.i @@ -14,7 +14,7 @@ %typemap(out) void * { Py_INCREF($1); - $result = $1; + $result = static_cast($1); } %include diff --git a/src/bindings/python/bt2/bt2/native_bt_trace.i.h b/src/bindings/python/bt2/bt2/native_bt_trace.i.h index bccdf875..f6dd64e0 100644 --- a/src/bindings/python/bt2/bt2/native_bt_trace.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_trace.i.h @@ -20,7 +20,8 @@ trace_destroyed_listener(const bt_trace *trace, void *py_callable) bt_common_abort(); } - py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_ptr); + py_res = PyObject_CallFunction(static_cast(py_callable), "(O)", + py_trace_ptr); if (!py_res) { logw_exception_clear(BT_LOG_OUTPUT_LEVEL); goto end; diff --git a/src/bindings/python/bt2/bt2/native_bt_trace_class.i.h b/src/bindings/python/bt2/bt2/native_bt_trace_class.i.h index 201801da..3f293086 100644 --- a/src/bindings/python/bt2/bt2/native_bt_trace_class.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_trace_class.i.h @@ -20,7 +20,8 @@ trace_class_destroyed_listener(const bt_trace_class *trace_class, void *py_calla bt_common_abort(); } - py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_class_ptr); + py_res = PyObject_CallFunction(static_cast(py_callable), "(O)", + py_trace_class_ptr); if (!py_res) { logw_exception_clear(BT_LOG_OUTPUT_LEVEL); goto end; diff --git a/src/bindings/python/bt2/bt2/native_bt_value.i.h b/src/bindings/python/bt2/bt2/native_bt_value.i.h index 650515f3..c391aa9c 100644 --- a/src/bindings/python/bt2/bt2/native_bt_value.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_value.i.h @@ -14,13 +14,13 @@ struct bt_value_map_get_keys_data { static bt_value_map_foreach_entry_const_func_status bt_value_map_get_keys_cb( const char *key, const struct bt_value *object, void *data) { - int status; - struct bt_value_map_get_keys_data *priv_data = data; + const auto priv_data = static_cast(data); + bt_value_array_append_element_status status = + bt_value_array_append_string_element(priv_data->keys, key); - status = bt_value_array_append_string_element(priv_data->keys, key); - BT_ASSERT(status == __BT_FUNC_STATUS_OK || - status == __BT_FUNC_STATUS_MEMORY_ERROR); - return status; + BT_ASSERT(status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK || + status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_MEMORY_ERROR); + return static_cast(status); } static struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj) diff --git a/src/bindings/python/bt2/setup.py.in b/src/bindings/python/bt2/setup.py.in index 411f715b..a8059aed 100644 --- a/src/bindings/python/bt2/setup.py.in +++ b/src/bindings/python/bt2/setup.py.in @@ -11,8 +11,11 @@ import subprocess # Distutils was removed in Python 3.12, use setuptools as an alternative. if sys.version_info >= (3, 12): from setuptools import setup, Extension + from setuptools.command.build_ext import build_ext else: from distutils.core import setup, Extension + from distutils.command.build_ext import build_ext + # Starting with Debian's Python 3.10, the default install scheme is # 'posix_local' which is a Debian specific scheme based on 'posix_prefix' but @@ -59,10 +62,6 @@ def getenv_assert(name: str): return value -def get_cflags(): - return getenv_assert("CFLAGS") - - # distutils performs a similar transformation step on LDSHARED on # darwin to use the overridden CC as the default command for LDSHARED # (see distutils' customize_compiler() step in the sysconfig module). @@ -85,7 +84,6 @@ def get_ldshared(): def our_get_config_vars(*args): overridden_config_vars_funcs = { - "CFLAGS": get_cflags, "LDSHARED": get_ldshared, } @@ -126,27 +124,73 @@ def cygpath_m(path: str): return path -# On MinGW systems, check CFLAGS and CPPFLAGS for absolute include paths -# (starts with '-I/') and convert them to valid Windows paths using cygpath. -if is_mingw(): - for flagvar in ["CFLAGS", "CPPFLAGS"]: - cur_flags = getenv_assert(flagvar) - new_flags = "" - for flag in cur_flags.split(): - if flag.startswith("-I/"): - flag = "-I{}".format(cygpath_m(flag[2:])) +# On MinGW systems, convert absolute include paths (starting with '-I/') +# in 'flags' to valid Windows paths using cygpath. On other systems, +# return 'flags' as-is. +def transform_include_paths_if_mingw(flags: str): + if not is_mingw(): + return flags + + return " ".join( + ( + "-I{}".format(cygpath_m(flag[2:])) if flag.startswith("-I/") else flag + for flag in flags.split() + ) + ) - new_flags += " {}".format(flag) - os.environ[flagvar] = new_flags +class custom_build_ext(build_ext): + def build_extensions(self): + # There are multiple issues handled simultaneously here: + # + # - distutils (at least before setuptools 72.2.0) doesn't + # handle well building shared objects from C++ source files. + # It will attempt to compile them using the C compiler. Set + # the executable used to compile C++ source files that will + # end up in shared objects so that it uses the C++ compiler + # defined by the `CXX` environment variable. + # + # - The CPPFLAGS and CXXFLAGS provided by sysconfig may not + # work with the compiler we tell distutils to use. We + # therefore also force our own flags (the call to + # `set_executable()` below overrides any flags previously + # found by distutils). + # + # - On MSYS2, some include paths need to be converted from + # Unix to Windows form. + + cxxflags = transform_include_paths_if_mingw(getenv_assert("CXXFLAGS")) + cppflags = transform_include_paths_if_mingw(getenv_assert("CPPFLAGS")) + cxx = getenv_assert("CXX") + + self.compiler.set_executable( + ( + # setuptools >= 72.2.0 uses the `compiler_so_cxx` + # attribute: + # + # https://github.com/pypa/setuptools/commit/2c937116cc0dcd9b26b6070e89a3dc5dcbedc2ae + # + # This version of setuptools seems to have better support + # for building shared objects from C++ source files, but + # we override the executable anyway, for consistency. + "compiler_so_cxx" + if hasattr(self.compiler, "compiler_so_cxx") + else "compiler_so" + ), + "{} {} {} {}".format( + cxx, sysconfig.get_config_var("CCSHARED"), cxxflags, cppflags + ), + ) + + super().build_extensions() def main(): babeltrace_ext = Extension( "bt2._native_bt", sources=[ - "bt2/native_bt.c", - cygpath_m("@srcdir@/bt2/logging.c"), + "bt2/native_bt.cpp", + cygpath_m("@srcdir@/bt2/logging.cpp"), ], libraries=["babeltrace2", "glib-2.0"], extra_objects=[ @@ -177,6 +221,7 @@ def main(): "License :: OSI Approved :: The MIT License", "Programming Language :: Python :: 3" "Topic :: System :: Logging", ], + cmdclass={"build_ext": custom_build_ext}, ) # After the installation, we check that the install directory is included in diff --git a/src/py-common/py-common.h b/src/py-common/py-common.h index 6ba19590..cb64a640 100644 --- a/src/py-common/py-common.h +++ b/src/py-common/py-common.h @@ -15,6 +15,10 @@ #include "common/macros.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Formats the Python traceback `py_exc_tb` using traceback.format_tb, from the * Python standard library, and return it as a Gstring. @@ -46,4 +50,8 @@ GString *bt_py_common_format_exception(PyObject *py_exc_type, */ GString *bt_py_common_format_current_exception(int log_level); +#ifdef __cplusplus +} +#endif + #endif /* BABELTRACE_PY_COMMON_PY_COMMON_H */ diff --git a/src/string-format/format-error.h b/src/string-format/format-error.h index 799c397f..5380f18e 100644 --- a/src/string-format/format-error.h +++ b/src/string-format/format-error.h @@ -12,6 +12,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + gchar *format_bt_error_cause( const bt_error_cause *error_cause, unsigned int columns, @@ -24,4 +28,8 @@ gchar *format_bt_error( bt_logging_level log_level, enum bt_common_color_when use_colors); +#ifdef __cplusplus +} +#endif + #endif /* BABELTRACE_STRING_FORMAT_FORMAT_ERROR_H */