From b9302c375d63829ff2630a284990472da71dcbf0 Mon Sep 17 00:00:00 2001 From: Silvio Traversaro Date: Mon, 2 Oct 2023 12:21:10 +0200 Subject: [PATCH] Fix cross-compilation support for gz-msg10 Signed-off-by: Silvio Traversaro --- CMakeLists.txt | 55 +++++++++++++++++++++++------------- cmake/gz_msgs_factory.cmake | 10 +++++-- cmake/gz_msgs_generate.cmake | 41 +++++++++++++++++++++++++-- cmake/gz_msgs_protoc.cmake | 19 +++++++++++-- core/CMakeLists.txt | 13 ++++++++- gz-msgs-extras.cmake.in | 15 +++++++++- 6 files changed, 124 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3133776..e1af90f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,34 +25,49 @@ gz_configure_project(VERSION_SUFFIX #============================================================================ # Cross-compilation related options -# In a cross-compilation scenario, it is possible that the gz_msgs_gen +# In a cross-compilation scenario, it is possible that the +# ${PROJECT_NAME}_protoc_plugin # generator compiled for the target machine cannot be used to generate -# the C++ code corresponding to the .proto definition. For this scenario, -# the following two options can be used as follows. +# the C++ code corresponding to the .proto definition. +# Similarly, it is possible that Python3::Interpreter and protobuf::protoc +# found via find_package are not executable that can be run during the build. +# To avoid, that the following options can be used as follows. # First of all, gz-msgs is compiled targeting the host machine, and in the -# build targeting the host, the INSTALL_GZ_MSGS_GEN_EXECUTABLE option is -# enabled: -# > cmake -DINSTALL_GZ_MSGS_GEN_EXECUTABLE:BOOL=ON .. -# ensuring that the gz_msgs_gen is installed in -# /bin/gz_msgs_gen . Then, the same version of gz-msgs +# build targeting the host, ensuring that the ${PROJECT_NAME}_protoc_plugin +# is installed in /bin/${PROJECT_NAME}_protoc_plugin . +# Then, the same version of gz-msgs # can be cross-compiled, and in the cross-compilation build the location of the -# host gz_msgs_gen is specified via the GZ_MSGS_GEN_EXECUTABLE -# CMake cache variable: -# > cmake -GZ_MSGS_GEN_EXECUTABLE=/bin/gz_msgs_gen .. +# host gz_msgs_gen is specified via the GZ_MSGS_GEN_EXECUTABLE CMake option. +# Similarly to gz-msgs, also a copy of protoc and of the Python interpreter need +# to be installed in the host at /bin, and they can be passed +# to the build appropriate CMake options: +# > cmake -Dgz-msgs_PROTO_GENERATOR_PLUGIN=gz-msgs_protoc_plugin +# > -Dgz-msgs_PROTOC_EXECUTABLE=/bin/protoc +# > -Dgz-msgs_PYTHON_INTERPRETER=/bin/python +# > .. +# In case the gz-msgs CMake functions are used also in downstream projects, +# the same variables can be passed when configuring the downsream projects. -option( - INSTALL_GZ_MSGS_GEN_EXECUTABLE - "Install the gz_msgs_gen executable." - OFF) +set( + ${PROJECT_NAME}_PROTO_GENERATOR_PLUGIN + "${PROJECT_NAME}_protoc_plugin" + CACHE STRING + "gz_msgs_gen executable used in the gz-msgs CMake functions.") +mark_as_advanced(${PROJECT_NAME}_PROTO_GENERATOR_PLUGIN) -mark_as_advanced(INSTALL_GZ_MSGS_GEN_EXECUTABLE) +set( + ${PROJECT_NAME}_PROTOC_EXECUTABLE + protobuf::protoc + CACHE STRING + "protoc target or executable used in the gz-msgs CMake functions.") +mark_as_advanced(${PROJECT_NAME}_PROTOC_EXECUTABLE) set( - GZ_MSGS_GEN_EXECUTABLE - "$" + ${PROJECT_NAME}_PYTHON_INTERPRETER + Python3::Interpreter CACHE STRING - "gz_msgs_gen executable used in the gz_msgs_protoc CMake function.") -mark_as_advanced(GZ_MSGS_GEN_EXECUTABLE) + "python target or executable used in the gz-msgs CMake functions.") +mark_as_advanced(${PROJECT_NAME}_PYTHON_INTERPRETER) # Python interfaces vars option(USE_SYSTEM_PATHS_FOR_PYTHON_INSTALLATION diff --git a/cmake/gz_msgs_factory.cmake b/cmake/gz_msgs_factory.cmake index b86b1b4f..2af59ffa 100644 --- a/cmake/gz_msgs_factory.cmake +++ b/cmake/gz_msgs_factory.cmake @@ -6,7 +6,7 @@ # One value arguments: # FACTORY_GEN_SCRIPT - Location of the factory generator script # PROTO_PACKAGE - Protobuf package the file belongs to (e.g. "gz.msgs") -# PROTOC_EXEC - Path to protoc +# PYTHON_INTERPRETER - Target or path to the Python interpreter to use to execute the generator script # OUTPUT_CPP_DIR - Path where C++ files are saved # OUTPUT_CPP_HH_VAR - A CMake variable name containing a list that the C++ headers should be appended to # OUTPUT_CPP_CC_VAR - A Cmake variable name containing a list that the C++ sources should be appended to @@ -18,6 +18,7 @@ function(gz_msgs_factory) set(oneValueArgs FACTORY_GEN_SCRIPT PROTO_PACKAGE + PYTHON_INTERPRETER OUTPUT_CPP_DIR OUTPUT_CPP_HH_VAR OUTPUT_CPP_CC_VAR) @@ -25,6 +26,11 @@ function(gz_msgs_factory) cmake_parse_arguments(gz_msgs_factory "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + # Default values for optional parameters + if (NOT DEFINED gz_msgs_factory_PYTHON_INTERPRETER) + set(gz_msgs_factory_PYTHON_INTERPRETER Python3::Interpreter) + endif() + _gz_msgs_proto_pkg_to_path(${gz_msgs_factory_PROTO_PACKAGE} proto_package_dir) set(output_header "${gz_msgs_factory_OUTPUT_CPP_DIR}/${proto_package_dir}/MessageTypes.hh") @@ -57,7 +63,7 @@ function(gz_msgs_factory) add_custom_command( OUTPUT ${output_files} - COMMAND Python3::Interpreter + COMMAND ${gz_msgs_factory_PYTHON_INTERPRETER} ARGS ${gz_msgs_factory_FACTORY_GEN_SCRIPT} ${GENERATE_ARGS} DEPENDS ${depends_index} diff --git a/cmake/gz_msgs_generate.cmake b/cmake/gz_msgs_generate.cmake index 679b9cae..5fc0cf3d 100644 --- a/cmake/gz_msgs_generate.cmake +++ b/cmake/gz_msgs_generate.cmake @@ -2,6 +2,7 @@ # The implementation of gz_msgs_generate_messages # Options: # One value arguments: +# PYTHON_INTERPRETER - Target or path to the python interpreter used # PROTO_PACKAGE - Protobuf package the file belongs to (e.g. "gz.msgs") # MSGS_GEN_SCRIPT - Location of the messge generator script # GZ_PROTOC_PLUGIN - Location of the gazebo generator plugin @@ -20,6 +21,8 @@ function(gz_msgs_generate_messages_impl) set(options "") set(oneValueArgs # Inputs + PYTHON_INTERPRETER + PROTOC_EXEC PROTO_PACKAGE MSGS_GEN_SCRIPT GZ_PROTOC_PLUGIN FACTORY_GEN_SCRIPT PROTO_PATH DEPENDENCY_DESCRIPTIONS DLLEXPORT_DECL @@ -33,6 +36,15 @@ function(gz_msgs_generate_messages_impl) set(multiValueArgs INPUT_PROTOS) cmake_parse_arguments(generate_messages "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Default values for optional parameters + if (NOT DEFINED generate_messages_PYTHON_INTERPRETER) + set(generate_messages_PYTHON_INTERPRETER Python3::Interpreter) + endif() + if (NOT DEFINED generate_messages_PROTOC_EXEC) + set(generate_messages_PROTOC_EXEC protobuf::protoc) + endif() + _gz_msgs_proto_pkg_to_string(${generate_messages_PROTO_PACKAGE} gen_dir) _gz_msgs_proto_pkg_to_path(${generate_messages_PROTO_PACKAGE} proto_package_dir) set(output_directory ${generate_messages_OUTPUT_DIRECTORY}) @@ -42,6 +54,8 @@ function(gz_msgs_generate_messages_impl) foreach(proto_file ${generate_messages_INPUT_PROTOS}) gz_msgs_protoc( + PYTHON_INTERPRETER + ${generate_messages_PYTHON_INTERPRETER} MSGS_GEN_SCRIPT ${generate_messages_MSGS_GEN_SCRIPT} PROTO_PACKAGE @@ -49,7 +63,7 @@ function(gz_msgs_generate_messages_impl) INPUT_PROTO ${proto_file} PROTOC_EXEC - protobuf::protoc + ${generate_messages_PROTOC_EXEC} GZ_PROTOC_PLUGIN ${generate_messages_GZ_PROTOC_PLUGIN} PROTO_PATH @@ -81,6 +95,8 @@ function(gz_msgs_generate_messages_impl) endforeach() gz_msgs_factory( + PYTHON_INTERPRETER + ${generate_messages_PYTHON_INTERPRETER} FACTORY_GEN_SCRIPT ${generate_messages_FACTORY_GEN_SCRIPT} PROTO_PACKAGE @@ -130,6 +146,7 @@ endfunction() ################################################## # Options: # One value arguments: +# PROTOC_EXEC - protoc target or executable to use # PROTO_PATH - Base directory of the proto files # DEPENDENCY_DESCRIPTIONS - Variable containing all depedency description files # OUTPUT_DIRECTORY - Directory of output gz_desc file @@ -140,6 +157,7 @@ function(gz_msgs_generate_desc_impl) set(options "") set(oneValueArgs # Inputs + PROTOC_EXEC PROTO_PATH DEPENDENCY_DESCRIPTIONS OUTPUT_DIRECTORY @@ -148,6 +166,10 @@ function(gz_msgs_generate_desc_impl) cmake_parse_arguments(generate_messages "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (NOT DEFINED generate_messages_PROTOC_EXEC) + set(generate_messages_PROTOC_EXEC protobuf::protoc) + endif() + set(ARGS) list(APPEND ARGS -I${generate_messages_PROTO_PATH}) list(APPEND ARGS --descriptor_set_out=${generate_messages_OUTPUT_FILENAME}) @@ -161,7 +183,7 @@ function(gz_msgs_generate_desc_impl) add_custom_command( OUTPUT ${generate_messages_OUTPUT_FILENAME} - COMMAND protobuf::protoc + COMMAND ${generate_messages_PROTOC_EXEC} ARGS ${ARGS} DEPENDS ${generate_messages_INPUT_PROTOS} COMMENT "Generating descriptor set" @@ -175,6 +197,8 @@ endfunction() # TARGET - Target (static library) to create # PROTO_PACKAGE - Protobuf package the file belongs to (e.g. "gz.msgs") # MSGS_GEN_SCRIPT - Location of the messge generator script +# PYTHON_INTERPRETER - Target or path to the python interpreter used +# PROTOC_EXEC - Protoc target or executable to use # GZ_PROTOC_PLUGIN - Location of the gazebo generator plugin # FACTORY_GEN_SCRIPT - Location of the factory generator script # MSGS_LIB - gz-msgs library to link to @@ -186,7 +210,7 @@ endfunction() # that depend on gz-msgs function(gz_msgs_generate_messages_lib) set(options "") - set(oneValueArgs TARGET PROTO_PACKAGE MSGS_GEN_SCRIPT GZ_PROTOC_PLUGIN FACTORY_GEN_SCRIPT MSGS_LIB PROTO_PATH) + set(oneValueArgs TARGET PROTO_PACKAGE MSGS_GEN_SCRIPT PYTHON_INTERPRETER PROTOC_EXEC GZ_PROTOC_PLUGIN FACTORY_GEN_SCRIPT MSGS_LIB PROTO_PATH) set(multiValueArgs INPUT_PROTOS DEPENDENCIES) cmake_parse_arguments(generate_messages "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -205,9 +229,19 @@ function(gz_msgs_generate_messages_lib) list(APPEND depends_msgs_desc ${msgs_desc_file}) endforeach() + # Default values for optional parameters + if (NOT DEFINED generate_messages_PYTHON_INTERPRETER) + set(generate_messages_PYTHON_INTERPRETER Python3::Interpreter) + endif() + if (NOT DEFINED generate_messages_PROTOC_EXEC) + set(generate_messages_PROTOC_EXEC protobuf::protoc) + endif() + gz_msgs_generate_messages_impl( PROTO_PACKAGE ${generate_messages_PROTO_PACKAGE} MSGS_GEN_SCRIPT ${generate_messages_MSGS_GEN_SCRIPT} + PYTHON_INTERPRETER ${generate_messages_PYTHON_INTERPRETER} + PROTOC_EXEC ${generate_messages_PROTOC_EXEC} GZ_PROTOC_PLUGIN ${generate_messages_GZ_PROTOC_PLUGIN} FACTORY_GEN_SCRIPT ${generate_messages_FACTORY_GEN_SCRIPT} PROTO_PATH ${generate_messages_PROTO_PATH} @@ -221,6 +255,7 @@ function(gz_msgs_generate_messages_lib) ) gz_msgs_generate_desc_impl( + PROTOC_EXEC ${generate_messages_PROTOC_EXEC} INPUT_PROTOS ${generate_messages_INPUT_PROTOS} PROTO_PATH ${generate_messages_PROTO_PATH} DEPENDENCY_DESCRIPTIONS ${depends_msgs_desc} diff --git a/cmake/gz_msgs_protoc.cmake b/cmake/gz_msgs_protoc.cmake index 077e266c..863d6b64 100644 --- a/cmake/gz_msgs_protoc.cmake +++ b/cmake/gz_msgs_protoc.cmake @@ -4,6 +4,7 @@ # GENERATE_CPP - generates c++ code for the message if specified # GENERATE_PYTHON - generates python code for the message if specified # One value arguments: +# PYTHON_INTERPRETER - Target or path to the Python interpreter to use to run generation scripts # MSGS_GEN_SCRIPT - Path to the message generation python script # PROTO_PACKAGE - Protobuf package the file belongs to (e.g. "gz.msgs") # PROTOC_EXEC - Path to protoc @@ -22,6 +23,7 @@ function(gz_msgs_protoc) set(options GENERATE_CPP GENERATE_PYTHON) set(oneValueArgs + PYTHON_INTERPRETER MSGS_GEN_SCRIPT PROTO_PACKAGE PROTOC_EXEC @@ -38,6 +40,13 @@ function(gz_msgs_protoc) cmake_parse_arguments(gz_msgs_protoc "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (NOT DEFINED gz_msgs_protoc_PYTHON_INTERPRETER) + set(gz_msgs_protoc_PYTHON_INTERPRETER Python3::Interpreter) + endif() + if (NOT DEFINED gz_msgs_protoc_PROTOC_EXEC) + set(gz_msgs_protoc_PROTOC_EXEC protobuf::protoc) + endif() + get_filename_component(ABS_FIL ${gz_msgs_protoc_INPUT_PROTO} ABSOLUTE) get_filename_component(FIL_WE ${gz_msgs_protoc_INPUT_PROTO} NAME_WE) @@ -85,8 +94,14 @@ function(gz_msgs_protoc) set(${gz_msgs_protoc_OUTPUT_PYTHON_VAR} ${${gz_msgs_protoc_OUTPUT_PYTHON_VAR}} PARENT_SCOPE) endif() + if(TARGET ${gz_msgs_protoc_PROTOC_EXEC}) + set(gz_msgs_protoc_PROTOC_EXEC_FILE_ABS_PATH "$") + else() + set(gz_msgs_protoc_PROTOC_EXEC_FILE_ABS_PATH ${gz_msgs_protoc_PROTOC_EXEC}) + endif() + set(GENERATE_ARGS - --protoc-exec "$" + --protoc-exec "${gz_msgs_protoc_PROTOC_EXEC_FILE_ABS_PATH}" --gz-generator-bin "${gz_msgs_protoc_GZ_PROTOC_PLUGIN}" --proto-path "${gz_msgs_protoc_PROTO_PATH}" --input-path "${ABS_FIL}" @@ -118,7 +133,7 @@ function(gz_msgs_protoc) add_custom_command( OUTPUT ${output_files} - COMMAND Python3::Interpreter + COMMAND ${gz_msgs_protoc_PYTHON_INTERPRETER} ARGS ${gz_msgs_protoc_MSGS_GEN_SCRIPT} ${GENERATE_ARGS} DEPENDS ${ABS_FIL} diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 2bbe9114..3cc7fad8 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -26,13 +26,23 @@ include(${PROJECT_SOURCE_DIR}/cmake/gz_msgs_generate.cmake) include(${PROJECT_SOURCE_DIR}/cmake/gz_msgs_protoc.cmake) include(${PROJECT_SOURCE_DIR}/cmake/gz_msgs_string_utils.cmake) +if(TARGET ${${PROJECT_NAME}_PROTO_GENERATOR_PLUGIN}) + set(${PROJECT_NAME}_PROTO_GENERATOR_PLUGIN_FILE $) +else() + set(${PROJECT_NAME}_PROTO_GENERATOR_PLUGIN_FILE ${${PROJECT_NAME}_PROTO_GENERATOR_PLUGIN}) +endif() + gz_msgs_generate_messages_impl( MSGS_GEN_SCRIPT ${PROJECT_SOURCE_DIR}/tools/gz_msgs_generate.py FACTORY_GEN_SCRIPT ${PROJECT_SOURCE_DIR}/tools/gz_msgs_generate_factory.py + PYTHON_INTERPRETER + ${${PROJECT_NAME}_PYTHON_INTERPRETER} + PROTOC_EXEC + ${${PROJECT_NAME}_PROTOC_EXECUTABLE} GZ_PROTOC_PLUGIN - $ + ${${PROJECT_NAME}_PROTO_GENERATOR_PLUGIN_FILE} INPUT_PROTOS ${proto_files} DLLEXPORT_DECL @@ -54,6 +64,7 @@ gz_msgs_generate_messages_impl( ) gz_msgs_generate_desc_impl( + PROTOC_EXEC ${${PROJECT_NAME}_PROTOC_EXECUTABLE} INPUT_PROTOS ${proto_files} PROTO_PATH ${PROJECT_SOURCE_DIR}/proto DEPENDENCY_DESCRIPTIONS ${depends_msgs_desc} diff --git a/gz-msgs-extras.cmake.in b/gz-msgs-extras.cmake.in index 914f779a..40d6c913 100644 --- a/gz-msgs-extras.cmake.in +++ b/gz-msgs-extras.cmake.in @@ -28,7 +28,16 @@ set(PROTO_SCRIPT_NAME "@PROJECT_NAME@_generate.py") set(FACTORY_SCRIPT_NAME "@PROJECT_NAME@_generate_factory.py") set(@PROJECT_NAME@_PROTO_PATH ${@PROJECT_NAME@_INSTALL_PATH}/share/protos) -set(@PROJECT_NAME@_PROTO_GENERATOR_PLUGIN ${@PROJECT_NAME@_INSTALL_PATH}/bin/${PROTOC_NAME}) +# Provide support to override generator executable used during cross-compilation +if(NOT DEFINED @PROJECT_NAME@_PROTO_GENERATOR_PLUGIN) + set(@PROJECT_NAME@_PROTO_GENERATOR_PLUGIN ${@PROJECT_NAME@_INSTALL_PATH}/bin/${PROTOC_NAME}) +endif() +if(NOT DEFINED @PROJECT_NAME@_PROTOC_EXECUTABLE) + set(@PROJECT_NAME@_PROTOC_EXECUTABLE protobuf::protoc) +endif() +if(NOT DEFINED @PROJECT_NAME@_PYTHON_INTERPRETER) + set(@PROJECT_NAME@_PYTHON_INTERPRETER Python3::Interpreter) +endif() set(@PROJECT_NAME@_PROTO_GENERATOR_SCRIPT ${@PROJECT_NAME@_INSTALL_PATH}/bin/${PROTO_SCRIPT_NAME}) set(@PROJECT_NAME@_FACTORY_GENERATOR_SCRIPT ${@PROJECT_NAME@_INSTALL_PATH}/bin/${FACTORY_SCRIPT_NAME}) @@ -64,6 +73,10 @@ function(gz_msgs_generate_messages) cmake_parse_arguments(generate_messages "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) gz_msgs_generate_messages_lib( + PYTHON_INTERPRETER + ${@PROJECT_NAME@_PYTHON_INTERPRETER} + PROTOC_EXEC + ${@PROJECT_NAME@_PROTOC_EXECUTABLE} MSGS_GEN_SCRIPT ${@PROJECT_NAME@_PROTO_GENERATOR_SCRIPT} FACTORY_GEN_SCRIPT