From 1505ac07675800c8259ae40df3421177ce0eb17a Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Sun, 11 Feb 2024 09:42:27 -0800 Subject: [PATCH] Prototype code for seeing if FindPython3 is usable for rosidl_python (#140) * Use FindPython3 for rosidl_python * Add in COMPONENTS keyword. * Mark the libraries private. * Use Python3::Interpreter in the custom command. * Switch to target_link_libraries almost everywhere. Signed-off-by: Chris Lalancette --- rosidl_generator_py/CMakeLists.txt | 13 +- .../cmake/custom_command.cmake | 4 +- ...idl_generator_py_generate_interfaces.cmake | 118 +++++++----------- 3 files changed, 47 insertions(+), 88 deletions(-) diff --git a/rosidl_generator_py/CMakeLists.txt b/rosidl_generator_py/CMakeLists.txt index acffa894..07d124a1 100644 --- a/rosidl_generator_py/CMakeLists.txt +++ b/rosidl_generator_py/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.14) project(rosidl_generator_py) @@ -25,11 +25,6 @@ if(BUILD_TESTING) find_package(python_cmake_module REQUIRED) find_package(PythonExtra MODULE REQUIRED) - set(BUILDTYPE_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}") - if(WIN32 AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(BUILDTYPE_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE_DEBUG}") - endif() - include(cmake/register_py.cmake) include(cmake/rosidl_generator_py_get_typesupports.cmake) @@ -72,18 +67,14 @@ if(BUILD_TESTING) string(REPLACE ";" ":" pythonpath "${pythonpath}") endif() ament_add_pytest_test(test_interfaces_py "test/test_interfaces.py" - PYTHON_EXECUTABLE "${BUILDTYPE_PYTHON_EXECUTABLE}" APPEND_ENV "PYTHONPATH=${pythonpath}" APPEND_LIBRARY_DIRS "${_append_library_dirs}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py" ) - ament_add_pytest_test(test_cli_extension test/test_cli_extension.py - PYTHON_EXECUTABLE "${BUILDTYPE_PYTHON_EXECUTABLE}" - ) + ament_add_pytest_test(test_cli_extension test/test_cli_extension.py) ament_add_pytest_test(test_property_py test/test_property.py - PYTHON_EXECUTABLE "${BUILDTYPE_PYTHON_EXECUTABLE}" APPEND_ENV "PYTHONPATH=${pythonpath}" APPEND_LIBRARY_DIRS "${_append_library_dirs}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py" diff --git a/rosidl_generator_py/cmake/custom_command.cmake b/rosidl_generator_py/cmake/custom_command.cmake index 62fd7627..203747a6 100644 --- a/rosidl_generator_py/cmake/custom_command.cmake +++ b/rosidl_generator_py/cmake/custom_command.cmake @@ -20,7 +20,9 @@ # add_subdirectory() call. add_custom_command( OUTPUT ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} - COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_py_BIN} + # This assumes that python_cmake_module was found, which is always the case since this is only + # called from rosidl_generator_py_generate_interfaces.cmake + COMMAND Python3::Interpreter ${rosidl_generator_py_BIN} --generator-arguments-file "${generator_arguments_file}" --typesupport-impls "${_typesupport_impls}" DEPENDS ${target_dependencies} ${rosidl_generate_interfaces_TARGET} 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 0a72e416..ba491901 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -12,15 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +find_package(python_cmake_module REQUIRED) +find_package(PythonExtra REQUIRED) find_package(rmw REQUIRED) find_package(rosidl_runtime_c REQUIRED) find_package(rosidl_typesupport_c REQUIRED) find_package(rosidl_typesupport_interface REQUIRED) -find_package(PythonInterp 3.6 REQUIRED) - -find_package(python_cmake_module REQUIRED) -find_package(PythonExtra MODULE REQUIRED) +find_package(Python3 REQUIRED COMPONENTS Interpreter Development NumPy) # Get a list of typesupport implementations from valid rmw implementations. rosidl_generator_py_get_typesupports(_typesupport_impls) @@ -72,10 +71,10 @@ foreach(_generated_py_file ${_generated_py_files}) endforeach() if(NOT _generated_c_files STREQUAL "") - foreach(_typesupport_impl ${_typesupport_impls}) - list(APPEND _generated_extension_${_typesupport_impl}_files "${_output_path}/_${PROJECT_NAME}_s.ep.${_typesupport_impl}.c") - list(APPEND _generated_extension_files "${_generated_extension_${_typesupport_impl}_files}") - endforeach() + foreach(_typesupport_impl ${_typesupport_impls}) + list(APPEND _generated_extension_${_typesupport_impl}_files "${_output_path}/_${PROJECT_NAME}_s.ep.${_typesupport_impl}.c") + list(APPEND _generated_extension_files "${_generated_extension_${_typesupport_impl}_files}") + endforeach() endif() set(_dependency_files "") set(_dependencies "") @@ -126,11 +125,6 @@ endif() set(_target_suffix "__py") -set(_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) -if(WIN32 AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE_DEBUG}) -endif() - # move custom command into a subdirectory to avoid multiple invocations on Windows set(_subdir "${CMAKE_CURRENT_BINARY_DIR}/${rosidl_generate_interfaces_TARGET}${_target_suffix}") file(MAKE_DIRECTORY "${_subdir}") @@ -142,12 +136,9 @@ set_property( ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} PROPERTY GENERATED 1) -# Export target so downstream interface packages can link to it -set(rosidl_generator_py_suffix "__rosidl_generator_py") - -set(_target_name_lib "${rosidl_generate_interfaces_TARGET}${rosidl_generator_py_suffix}") +set(_target_name_lib "${rosidl_generate_interfaces_TARGET}__rosidl_generator_py") add_library(${_target_name_lib} SHARED ${_generated_c_files}) -target_link_libraries(${_target_name_lib} +target_link_libraries(${_target_name_lib} PRIVATE ${rosidl_generate_interfaces_TARGET}__rosidl_generator_c) add_dependencies( ${_target_name_lib} @@ -156,44 +147,23 @@ add_dependencies( ) target_link_libraries( - ${_target_name_lib} - ${PythonExtra_LIBRARIES} + ${_target_name_lib} PRIVATE + Python3::NumPy + Python3::Python ) target_include_directories(${_target_name_lib} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py - ${PythonExtra_INCLUDE_DIRS} ) -# Check if numpy is in the include path -find_file(_numpy_h numpy/numpyconfig.h - PATHS ${PythonExtra_INCLUDE_DIRS} -) - -if(APPLE OR WIN32 OR NOT _numpy_h) - # add include directory for numpy headers - set(_python_code - "import numpy" - "print(numpy.get_include())" - ) - execute_process( - COMMAND "${PYTHON_EXECUTABLE}" "-c" "${_python_code}" - OUTPUT_VARIABLE _output - RESULT_VARIABLE _result - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(NOT _result EQUAL 0) - message(FATAL_ERROR - "execute_process(${PYTHON_EXECUTABLE} -c '${_python_code}') returned " - "error code ${_result}") - endif() - message(STATUS "Using numpy include directory: ${_output}") - target_include_directories(${_target_name_lib} PUBLIC "${_output}") +set(_extension_compile_flags "") +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(_extension_compile_flags -Wall -Wextra) endif() rosidl_get_typesupport_target(c_typesupport_target "${rosidl_generate_interfaces_TARGET}" "rosidl_typesupport_c") -target_link_libraries(${_target_name_lib} ${c_typesupport_target}) +target_link_libraries(${_target_name_lib} PRIVATE ${c_typesupport_target}) foreach(_typesupport_impl ${_typesupport_impls}) find_package(${_typesupport_impl} REQUIRED) @@ -203,10 +173,9 @@ foreach(_typesupport_impl ${_typesupport_impls}) continue() endif() - set(_pyext_suffix "__pyext") - set(_target_name "${PROJECT_NAME}__${_typesupport_impl}${_pyext_suffix}") + set(_target_name "${PROJECT_NAME}_s__${_typesupport_impl}") - add_library(${_target_name} SHARED + python3_add_library(${_target_name} MODULE ${_generated_extension_${_typesupport_impl}_files} ) add_dependencies( @@ -215,65 +184,62 @@ foreach(_typesupport_impl ${_typesupport_impls}) ${rosidl_generate_interfaces_TARGET}__rosidl_typesupport_c ) - set(_extension_compile_flags "") - if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(_extension_compile_flags -Wall -Wextra) - endif() + set_target_properties(${_target_name} PROPERTIES DEBUG_POSTFIX "${PythonExtra_POSTFIX}") + # target_compile_options(${_target_name} PRIVATE ${_extension_compile_flags}) + # TODO(sloretz) use target_compile_options when python extension passes -Wpedantic + set_target_properties(${_target_name} PROPERTIES COMPILE_OPTIONS "${_extension_compile_flags}") + set_target_properties(${_target_name} PROPERTIES - COMPILE_OPTIONS "${_extension_compile_flags}" - PREFIX "" - OUTPUT_NAME "${PROJECT_NAME}_s__${_typesupport_impl}${PythonExtra_EXTENSION_SUFFIX}" - SUFFIX "${PythonExtra_EXTENSION_EXTENSION}") + LIBRARY_OUTPUT_DIRECTORY ${_output_path} + RUNTIME_OUTPUT_DIRECTORY ${_output_path}) + target_link_libraries( - ${_target_name} + ${_target_name} PRIVATE ${_target_name_lib} - ${PythonExtra_LIBRARIES} ${rosidl_generate_interfaces_TARGET}__${_typesupport_impl} + ${c_typesupport_target} + rosidl_runtime_c::rosidl_runtime_c + rosidl_typesupport_c::rosidl_typesupport_c + rosidl_typesupport_interface::rosidl_typesupport_interface ) target_include_directories(${_target_name} - PUBLIC + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py - ${PythonExtra_INCLUDE_DIRS} ) - target_link_libraries(${_target_name} ${c_typesupport_target}) - - ament_target_dependencies(${_target_name} - "rosidl_runtime_c" - "rosidl_typesupport_c" - "rosidl_typesupport_interface" - ) foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) - ament_target_dependencies(${_target_name} - ${_pkg_name} - ) + target_link_libraries(${_target_name} PRIVATE ${${_pkg_name}__TARGETS}) endforeach() add_dependencies(${_target_name} ${rosidl_generate_interfaces_TARGET}__${_typesupport_impl} ) - ament_target_dependencies(${_target_name} - "rosidl_runtime_c" + + ament_target_dependencies(${_target_name} PUBLIC "rosidl_generator_py" ) if(NOT rosidl_generate_interfaces_SKIP_INSTALL) + # PYTHON_INSTALL_DIR is defined by ament_cmake_python install(TARGETS ${_target_name} DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}") endif() endforeach() -set(PYTHON_EXECUTABLE ${_PYTHON_EXECUTABLE}) # 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} ${${_pkg_name}_TARGETS${rosidl_generator_py_suffix}}) + 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}") + set_target_properties(${_target_name_lib} PROPERTIES - COMPILE_OPTIONS "${_extension_compile_flags}") + LIBRARY_OUTPUT_DIRECTORY ${_output_path} + RUNTIME_OUTPUT_DIRECTORY ${_output_path}) + if(NOT rosidl_generate_interfaces_SKIP_INSTALL) install(TARGETS ${_target_name_lib} EXPORT export_${_target_name_lib}