diff --git a/patch/ros-rolling-rosidl-generator-py.patch b/patch/ros-rolling-rosidl-generator-py.patch index 81611256d..0cf05c625 100644 --- a/patch/ros-rolling-rosidl-generator-py.patch +++ b/patch/ros-rolling-rosidl-generator-py.patch @@ -1,24 +1,26 @@ diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake -index 2fe245b..f46b674 100644 +index 2fe245b..24eb493 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake -@@ -152,8 +152,14 @@ set_property( - ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} - PROPERTY GENERATED 1) +@@ -35,6 +35,11 @@ set(Python3_FIND_UNVERSIONED_NAMES FIRST) -+# The generated C conversion functions are compiled into each Python extension -+# module below, rather than into a shared library: they use CPython symbols -+# that only a Python interpreter provides. Conversion functions of types from -+# other packages are looked up from those packages' Python message classes at -+# runtime, so no library needs to be exported or linked across packages. - set(_target_name_lib "${rosidl_generate_interfaces_TARGET}__rosidl_generator_py") --add_library(${_target_name_lib} SHARED ${_generated_c_files}) -+add_library(${_target_name_lib} OBJECT ${_generated_c_files}) -+set_target_properties(${_target_name_lib} PROPERTIES POSITION_INDEPENDENT_CODE ON) - target_link_libraries(${_target_name_lib} PRIVATE - ${rosidl_generate_interfaces_TARGET}__rosidl_generator_c) - add_dependencies( -@@ -165,7 +171,7 @@ add_dependencies( + find_package(Python3 REQUIRED COMPONENTS Interpreter Development NumPy) + ++# The Python C bindings library of an interface package is exported in ++# _TARGETS__rosidl_generator_py instead of _TARGETS, so that C/C++ ++# consumers of the interface package don't link it. ++set(rosidl_generator_py_suffix "__rosidl_generator_py") ++ + # Get a list of typesupport implementations from valid rmw implementations. + rosidl_generator_py_get_typesupports(_typesupport_impls) + +@@ -162,10 +167,13 @@ add_dependencies( + ${rosidl_generate_interfaces_TARGET}__rosidl_typesupport_c + ) + ++# This library is only linked by Python extension modules, which get the ++# CPython symbols from the interpreter that loads them, so it links ++# Python3::Module rather than libpython (Python3::Python). target_link_libraries( ${_target_name_lib} PRIVATE Python3::NumPy @@ -27,152 +29,28 @@ index 2fe245b..f46b674 100644 ) target_include_directories(${_target_name_lib} PRIVATE -@@ -242,26 +248,8 @@ foreach(_typesupport_impl ${_typesupport_impls}) - endif() - endforeach() - -- --# Depend on rosidl_generator_py generated targets from our dependencies --foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) -- target_link_libraries(${_target_name_lib} PRIVATE ${${_pkg_name}_TARGETS${rosidl_generator_py_suffix}}) --endforeach() -- - set_target_properties(${_target_name_lib} PROPERTIES COMPILE_OPTIONS "${_extension_compile_flags}") +@@ -257,9 +265,22 @@ if(NOT rosidl_generate_interfaces_SKIP_INSTALL) + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) --if(NOT rosidl_generate_interfaces_SKIP_INSTALL) -- install(TARGETS ${_target_name_lib} -- EXPORT export_${_target_name_lib} -- ARCHIVE DESTINATION lib -- LIBRARY DESTINATION lib -- RUNTIME DESTINATION bin) -- - # Export this target so downstream interface packages can depend on it -- rosidl_export_typesupport_targets("${rosidl_generator_py_suffix}" "${_target_name_lib}") ++ # Export this target so downstream interface packages can depend on it, in ++ # _TARGETS__rosidl_generator_py. Not with ament_export_targets(), which ++ # would also add it to _TARGETS: install the export set and include it ++ # from a config extras file instead, which creates the imported target that ++ # rosidl_export_typesupport_targets() adds to the suffixed list. ++ install( ++ EXPORT export_${_target_name_lib} ++ DESTINATION share/${PROJECT_NAME}/cmake ++ NAMESPACE "${PROJECT_NAME}::" ++ FILE "export_${_target_name_lib}Export.cmake") ++ set(_py_extras_file ++ "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py/${_target_name_lib}-extras.cmake") ++ file(WRITE "${_py_extras_file}" ++ "include(\"\${${PROJECT_NAME}_DIR}/export_${_target_name_lib}Export.cmake\")\n") ++ list(APPEND ${PROJECT_NAME}_CONFIG_EXTRAS "${_py_extras_file}") + rosidl_export_typesupport_targets("${rosidl_generator_py_suffix}" "${_target_name_lib}") - ament_export_targets(export_${_target_name_lib}) --endif() -- - if(BUILD_TESTING AND rosidl_generate_interfaces_ADD_LINTER_TESTS) - if( - NOT _generated_py_files STREQUAL "" OR -diff --git a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em -index d234915..6d1bef1 100644 ---- a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em -+++ b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em -@@ -48,9 +48,7 @@ static void @('__'.join(message.structure.namespaced_type.namespaces + [module_n - @(msg_typename)__destroy(ros_message); - } + endif() --ROSIDL_GENERATOR_C_IMPORT - bool @('__'.join(message.structure.namespaced_type.namespaces + [module_name]))__convert_from_py(PyObject * _pymsg, void * ros_message); --ROSIDL_GENERATOR_C_IMPORT - PyObject * @('__'.join(message.structure.namespaced_type.namespaces + [module_name]))__convert_to_py(void * raw_ros_message); - - -diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em -index 62941b2..76c89bd 100644 ---- a/rosidl_generator_py/resource/_msg_support.c.em -+++ b/rosidl_generator_py/resource/_msg_support.c.em -@@ -158,15 +158,80 @@ type_ = member.type - if isinstance(type_, AbstractNestedType): - type_ = type_.value_type - }@ --@[ if isinstance(type_, NamespacedType)]@ --@[ if type_.namespaces[0] != package_name]@ --ROSIDL_GENERATOR_C_IMPORT --@[ end if]@ -+@[ if isinstance(type_, NamespacedType) and type_.namespaces[0] == package_name]@ - bool @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message); --@[ if type_.namespaces[0] != package_name]@ --ROSIDL_GENERATOR_C_IMPORT --@[ end if]@ - PyObject * @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_to_py(void * raw_ros_message); -+@[ elif isinstance(type_, NamespacedType) and ('converter', *type_.namespaced_name()) not in include_directives]@ -+@{ -+include_directives.add(('converter', *type_.namespaced_name())) -+converter_prefix = '__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]) -+# the Python module is named after the interface file, e.g. _add_two_ints for -+# the AddTwoInts_Request service message -+interface_name = type_.name if type_.namespaces[-1] == 'msg' else type_.name.split('_', 1)[0] -+converter_module = '.'.join(type_.namespaces) + '._' + convert_camel_case_to_lower_case_underscore(interface_name) -+}@ -+@[ if 'converter_lookup' not in include_directives]@ -+@{include_directives.add('converter_lookup')}@ -+// Get a conversion function of a message type from another package from its -+// Python class, which that package's extension module provides it to. -+static void * _rosidl_generator_py__get_converter( -+ const char * module_name, const char * class_name, const char * capsule_name) -+{ -+ PyObject * module = PyImport_ImportModule(module_name); -+ if (!module) { -+ return NULL; -+ } -+ PyObject * pyclass = PyObject_GetAttrString(module, class_name); -+ Py_DECREF(module); -+ if (!pyclass) { -+ return NULL; -+ } -+ PyObject * capsule = PyObject_GetAttrString(pyclass, capsule_name); -+ if (capsule == Py_None) { -+ Py_DECREF(capsule); -+ PyObject * result = PyObject_CallMethod(pyclass, "__import_type_support__", NULL); -+ if (!result) { -+ Py_DECREF(pyclass); -+ return NULL; -+ } -+ Py_DECREF(result); -+ capsule = PyObject_GetAttrString(pyclass, capsule_name); -+ } -+ Py_DECREF(pyclass); -+ if (!capsule) { -+ return NULL; -+ } -+ void * converter = PyCapsule_GetPointer(capsule, NULL); -+ Py_DECREF(capsule); -+ return converter; -+} -+ -+@[ end if]@ -+static bool @(converter_prefix)__convert_from_py(PyObject * _pymsg, void * _ros_message) -+{ -+ static bool (* convert)(PyObject *, void *) = NULL; -+ if (!convert) { -+ convert = (bool (*)(PyObject *, void *))_rosidl_generator_py__get_converter( -+ "@(converter_module)", "@(type_.name)", "_CONVERT_FROM_PY"); -+ if (!convert) { -+ return false; -+ } -+ } -+ return convert(_pymsg, _ros_message); -+} -+ -+static PyObject * @(converter_prefix)__convert_to_py(void * raw_ros_message) -+{ -+ static PyObject * (* convert)(void *) = NULL; -+ if (!convert) { -+ convert = (PyObject * (*)(void *))_rosidl_generator_py__get_converter( -+ "@(converter_module)", "@(type_.name)", "_CONVERT_TO_PY"); -+ if (!convert) { -+ return NULL; -+ } -+ } -+ return convert(raw_ros_message); -+} - @[ end if]@ - @[end for]@ - -@@ -175,7 +240,6 @@ module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.s - class_module = '%s.%s' % ('.'.join(message.structure.namespaced_type.namespaces), module_name) - namespaced_type = message.structure.namespaced_type.name - }@ --ROSIDL_GENERATOR_C_EXPORT - bool @('__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message) - { - // check that the passed message is of the expected Python class -@@ -573,7 +637,6 @@ nested_type = '__'.join(type_.namespaced_name()) - return true; - } - --ROSIDL_GENERATOR_C_EXPORT - PyObject * @('__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]))__convert_to_py(void * raw_ros_message) - { - /* NOTE(esteve): Call constructor of @(message.structure.namespaced_type.name) */ + if(BUILD_TESTING AND rosidl_generate_interfaces_ADD_LINTER_TESTS) diff --git a/tests/ros-rolling-std-msgs.yaml b/tests/ros-rolling-std-msgs.yaml index c4055f0da..2088cfafa 100644 --- a/tests/ros-rolling-std-msgs.yaml +++ b/tests/ros-rolling-std-msgs.yaml @@ -6,16 +6,17 @@ tests: # found in flat namespace '_PyExc_RuntimeError'") and fails to link or load # on Linux when it links Python3::Module # (https://github.com/RoboStack/ros-kilted/issues/76). - # LDFLAGS is cleared so -Wl,--as-needed / -Wl,-dead_strip_dylibs can't hide it. + # cxx-compiler (unlike compiler('cxx')) sets no LDFLAGS, like a user's + # environment, so -Wl,--as-needed / -Wl,-dead_strip_dylibs can't hide it. - if: unix then: script: - - env -u LDFLAGS cmake -S cpp_consumer -B build -G Ninja -DCMAKE_PREFIX_PATH="$PREFIX" + - cmake -S cpp_consumer -B build -G Ninja -DCMAKE_PREFIX_PATH="$PREFIX" - cmake --build build - ./build/std_msgs_cpp_consumer requirements: build: - - ${{ compiler('cxx') }} + - cxx-compiler - cmake - ninja files: @@ -26,4 +27,4 @@ tests: - python -c "from rclpy.serialization import deserialize_message, serialize_message; from std_msgs.msg import Header; m = deserialize_message(serialize_message(Header(frame_id='map')), Header); assert m.frame_id == 'map'" requirements: run: - - ros-rolling-rclpy + - ros2-rclpy