diff --git a/rosidl_typesupport_c/CMakeLists.txt b/rosidl_typesupport_c/CMakeLists.txt index 25524fd6..13989d50 100644 --- a/rosidl_typesupport_c/CMakeLists.txt +++ b/rosidl_typesupport_c/CMakeLists.txt @@ -2,6 +2,20 @@ cmake_minimum_required(VERSION 3.5) project(rosidl_typesupport_c) +if(BUILD_SHARED_LIBS) + set(${PROJECT_NAME}_LIBRARY_TYPE "SHARED") +else() + set(${PROJECT_NAME}_LIBRARY_TYPE "STATIC") +endif() + +if(rosidl_typesupport_c_LIBRARY_TYPE STREQUAL "STATIC" + AND NOT BUILD_TESTING +) + set(ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT ON) +else() + set(ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT OFF) +endif() + # Default to C11 if(NOT CMAKE_C_STANDARD) set(CMAKE_C_STANDARD 11) @@ -16,13 +30,17 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() find_package(ament_cmake_ros REQUIRED) -find_package(rcpputils REQUIRED) find_package(rcutils REQUIRED) find_package(rosidl_runtime_c REQUIRED) +if(NOT ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT) + find_package(rcpputils REQUIRED) +endif() -ament_export_dependencies(rcpputils) ament_export_dependencies(rosidl_runtime_c) ament_export_dependencies(rosidl_typesupport_interface) +if(NOT ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT) + ament_export_dependencies(rcpputils) +endif() ament_export_include_directories(include) @@ -36,15 +54,23 @@ if(WIN32) target_compile_definitions(${PROJECT_NAME} PRIVATE "ROSIDL_TYPESUPPORT_C_BUILDING_DLL") endif() +target_compile_definitions(${PROJECT_NAME} + PRIVATE + $<$:ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT> +) target_include_directories(${PROJECT_NAME} PUBLIC "$" "$") ament_target_dependencies(${PROJECT_NAME} - "rcpputils" "rcutils" "rosidl_runtime_c" ) +if(NOT ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT) + ament_target_dependencies(${PROJECT_NAME} + "rcpputils" + ) +endif() ament_export_libraries(${PROJECT_NAME}) ament_export_targets(${PROJECT_NAME}) @@ -130,12 +156,6 @@ if(BUILD_TESTING) ament_add_pytest_test(test_cli_extension test/test_cli_extension.py) endif() -if(BUILD_SHARED_LIBS) - set(${PROJECT_NAME}_LIBRARY_TYPE "SHARED") -else() - set(${PROJECT_NAME}_LIBRARY_TYPE "STATIC") -endif() - ament_package( CONFIG_EXTRAS "rosidl_typesupport_c-extras.cmake.in" ) diff --git a/rosidl_typesupport_c/cmake/rosidl_typesupport_c_generate_interfaces.cmake b/rosidl_typesupport_c/cmake/rosidl_typesupport_c_generate_interfaces.cmake index 7a3649c7..f624bc9e 100644 --- a/rosidl_typesupport_c/cmake/rosidl_typesupport_c_generate_interfaces.cmake +++ b/rosidl_typesupport_c/cmake/rosidl_typesupport_c_generate_interfaces.cmake @@ -118,15 +118,19 @@ target_include_directories(${rosidl_generate_interfaces_TARGET}${_target_suffix} # if only a single typesupport is used this package will directly reference it # therefore it needs to link against the selected typesupport if(NOT typesupports MATCHES ";") + set(SINGLE_TYPE_SUPPORT ON) target_include_directories(${rosidl_generate_interfaces_TARGET}${_target_suffix} PUBLIC "$") target_link_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix} ${rosidl_generate_interfaces_TARGET}__${typesupports}) else() + set(SINGLE_TYPE_SUPPORT OFF) if("${rosidl_typesupport_c_LIBRARY_TYPE}" STREQUAL "STATIC") - message(FATAL_ERROR "Multiple typesupports [${typesupports}] but static " - "linking was requested") + target_compile_definitions(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PRIVATE + ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT + ) endif() endif() @@ -150,15 +154,33 @@ add_dependencies( ${rosidl_generate_interfaces_TARGET} ${rosidl_generate_interfaces_TARGET}${_target_suffix} ) +add_dependencies( + ${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${rosidl_generate_interfaces_TARGET}__rosidl_generator_c + ${rosidl_generate_interfaces_TARGET}__rosidl_typesupport_c +) if(NOT rosidl_generate_interfaces_SKIP_INSTALL) - install( - TARGETS ${rosidl_generate_interfaces_TARGET}${_target_suffix} - EXPORT ${rosidl_generate_interfaces_TARGET} - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin - ) + if(SINGLE_TYPE_SUPPORT) + install( + TARGETS + ${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${rosidl_generate_interfaces_TARGET}__${typesupports} + EXPORT ${rosidl_generate_interfaces_TARGET} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + else() + install( + TARGETS ${rosidl_generate_interfaces_TARGET}${_target_suffix} + EXPORT ${rosidl_generate_interfaces_TARGET} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + endif() + ament_export_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix}) endif() diff --git a/rosidl_typesupport_c/resource/msg__type_support.cpp.em b/rosidl_typesupport_c/resource/msg__type_support.cpp.em index d09c4c6d..30b57da3 100644 --- a/rosidl_typesupport_c/resource/msg__type_support.cpp.em +++ b/rosidl_typesupport_c/resource/msg__type_support.cpp.em @@ -76,6 +76,26 @@ typedef struct _@(message.structure.namespaced_type.name)_type_support_data_t void * data[@(len(type_supports))]; } _@(message.structure.namespaced_type.name)_type_support_data_t; +#ifdef ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT +#ifdef __cplusplus +extern "C" +{ +#endif +@[for type_support in sorted(type_supports)]@ +rosidl_message_type_support_t * ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(@(type_support), @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(message.structure.namespaced_type.name))(); +@[end for]@ +#ifdef __cplusplus +} +#endif + +static _@(message.structure.namespaced_type.name)_type_support_data_t _@(message.structure.namespaced_type.name)_message_typesupport_data = { + { +@[for type_support in sorted(type_supports)]@ + (void*) ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(@(type_support), @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(message.structure.namespaced_type.name)), +@[end for]@ + } +}; +#else static _@(message.structure.namespaced_type.name)_type_support_data_t _@(message.structure.namespaced_type.name)_message_typesupport_data = { { @[for type_support in sorted(type_supports)]@ @@ -83,6 +103,7 @@ static _@(message.structure.namespaced_type.name)_type_support_data_t _@(message @[end for]@ } }; +#endif // ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT static const type_support_map_t _@(message.structure.namespaced_type.name)_message_typesupport_map = { @(len(type_supports)), diff --git a/rosidl_typesupport_c/resource/srv__type_support.cpp.em b/rosidl_typesupport_c/resource/srv__type_support.cpp.em index b815f611..3629ac8d 100644 --- a/rosidl_typesupport_c/resource/srv__type_support.cpp.em +++ b/rosidl_typesupport_c/resource/srv__type_support.cpp.em @@ -84,6 +84,26 @@ typedef struct _@(service.namespaced_type.name)_type_support_data_t void * data[@(len(type_supports))]; } _@(service.namespaced_type.name)_type_support_data_t; +#ifdef ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT +#ifdef __cplusplus +extern "C" +{ +#endif +@[for type_support in sorted(type_supports)]@ +rosidl_service_type_support_t * ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(@(type_support), @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name))(); +@[end for]@ +#ifdef __cplusplus +} +#endif + +static _@(service.namespaced_type.name)_type_support_data_t _@(service.namespaced_type.name)_service_typesupport_data = { + { +@[for type_support in sorted(type_supports)]@ + (void*) ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(@(type_support), @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name)), +@[end for]@ + } +}; +#else static _@(service.namespaced_type.name)_type_support_data_t _@(service.namespaced_type.name)_service_typesupport_data = { { @[for type_support in sorted(type_supports)]@ @@ -91,6 +111,7 @@ static _@(service.namespaced_type.name)_type_support_data_t _@(service.namespace @[end for]@ } }; +#endif // ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT static const type_support_map_t _@(service.namespaced_type.name)_service_typesupport_map = { @(len(type_supports)), diff --git a/rosidl_typesupport_c/src/dynamic_support_dispatch.hpp b/rosidl_typesupport_c/src/dynamic_support_dispatch.hpp new file mode 100644 index 00000000..d6f1e2cc --- /dev/null +++ b/rosidl_typesupport_c/src/dynamic_support_dispatch.hpp @@ -0,0 +1,102 @@ +// Copyright 2021 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DYNAMIC_SUPPORT_DISPATCH_HPP_ +#define DYNAMIC_SUPPORT_DISPATCH_HPP_ + +#include +#include +#include + +#include +#include +#include +#include + +#include "rcpputils/shared_library.hpp" +#include "rcutils/error_handling.h" +#include "rcutils/snprintf.h" +#include "rosidl_typesupport_c/type_support_map.h" + +namespace rosidl_typesupport_c +{ + +static void * +handle_shared_library_from_name( + const type_support_map_t * map, + size_t map_item, + const char * identifier +) +{ + rcpputils::SharedLibrary * lib = nullptr; + + if (!map->data[map_item]) { + char library_basename[1024]; + int ret = rcutils_snprintf( + library_basename, 1023, "%s__%s", + map->package_name, identifier); + if (ret < 0) { + RCUTILS_SET_ERROR_MSG("Failed to format library name"); + return nullptr; + } + + std::string library_name; + try { + library_name = rcpputils::get_platform_library_name(library_basename); + } catch (const std::exception & e) { + RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( + "Failed to compute library name for '%s' due to %s", + library_basename, e.what()); + return nullptr; + } + + try { + lib = new rcpputils::SharedLibrary(library_name); + } catch (const std::runtime_error & e) { + RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( + "Could not load library %s: %s", library_name.c_str(), e.what()); + return nullptr; + } catch (const std::bad_alloc & e) { + RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( + "Could not load library %s: %s", library_name.c_str(), e.what()); + return nullptr; + } + map->data[map_item] = lib; + } + + auto clib = static_cast(map->data[map_item]); + lib = const_cast(clib); + + void * sym = nullptr; + + try { + if (!lib->has_symbol(map->symbol_name[map_item])) { + RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( + "Failed to find symbol '%s' in library", map->symbol_name[map_item]); + return nullptr; + } + sym = lib->get_symbol(map->symbol_name[map_item]); + } catch (const std::exception & e) { + RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( + "Failed to get symbol '%s' in library: %s", + map->symbol_name[map_item], e.what()); + return nullptr; + } + + return sym; +} + +} // namespace rosidl_typesupport_c + +#endif // DYNAMIC_SUPPORT_DISPATCH_HPP_ diff --git a/rosidl_typesupport_c/src/type_support_dispatch.hpp b/rosidl_typesupport_c/src/type_support_dispatch.hpp index 4c7ae3e6..a00d0efc 100644 --- a/rosidl_typesupport_c/src/type_support_dispatch.hpp +++ b/rosidl_typesupport_c/src/type_support_dispatch.hpp @@ -15,15 +15,10 @@ #ifndef TYPE_SUPPORT_DISPATCH_HPP_ #define TYPE_SUPPORT_DISPATCH_HPP_ -#include -#include -#include +#ifndef ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT +#include "./dynamic_support_dispatch.hpp" +#endif // ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT -#include -#include -#include - -#include "rcpputils/shared_library.hpp" #include "rcutils/error_handling.h" #include "rcutils/snprintf.h" #include "rosidl_typesupport_c/identifier.h" @@ -50,62 +45,16 @@ get_typesupport_handle_function( if (strcmp(map->typesupport_identifier[i], identifier) != 0) { continue; } - rcpputils::SharedLibrary * lib = nullptr; - - if (!map->data[i]) { - char library_basename[1024]; - int ret = rcutils_snprintf( - library_basename, 1023, "%s__%s", - map->package_name, identifier); - if (ret < 0) { - RCUTILS_SET_ERROR_MSG("Failed to format library name"); - return nullptr; - } - - std::string library_name; - try { - library_name = rcpputils::get_platform_library_name(library_basename); - } catch (const std::exception & e) { - RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( - "Failed to compute library name for '%s' due to %s", - library_basename, e.what()); - return nullptr; - } - - try { - lib = new rcpputils::SharedLibrary(library_name); - } catch (const std::runtime_error & e) { - RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( - "Could not load library %s: %s", library_name.c_str(), e.what()); - return nullptr; - } catch (const std::bad_alloc & e) { - RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( - "Could not load library %s: %s", library_name.c_str(), e.what()); - return nullptr; - } - map->data[i] = lib; - } - auto clib = static_cast(map->data[i]); - lib = const_cast(clib); - - void * sym = nullptr; - - try { - if (!lib->has_symbol(map->symbol_name[i])) { - RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( - "Failed to find symbol '%s' in library", map->symbol_name[i]); - return nullptr; - } - sym = lib->get_symbol(map->symbol_name[i]); - } catch (const std::exception & e) { - RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( - "Failed to get symbol '%s' in library: %s", - map->symbol_name[i], e.what()); - return nullptr; - } - typedef const TypeSupport * (* funcSignature)(void); +#ifndef ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT + void * sym = handle_shared_library_from_name(map, i, identifier); + if (nullptr == sym) { + continue; + } funcSignature func = reinterpret_cast(sym); +#else + funcSignature func = reinterpret_cast(map->data[i]); +#endif // ROSIDL_TYPESUPPORT_STATIC_TYPESUPPORT const TypeSupport * ts = func(); return ts; }