From 3226c31d1f4b2944e87d4ec3e821fdac501c9d26 Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Tue, 30 Apr 2024 14:19:17 +0100 Subject: [PATCH 1/6] Update cmake dependencies to fix broken upstream repo pybind11_protobuf Signed-off-by: Rhys Mainwaring --- CMakeLists.txt | 57 +++++++++++++++---------------- cmake/dependencies/CMakeLists.txt | 39 +++++++++++++++++++-- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d479f8..3f70724 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ project(gz-python) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -15,50 +16,48 @@ option(BUILD_TESTS "Build tests." OFF) #============================================================================ # Find Python -# -# macOS: $ brew install python -# macOS: $ brew install pybind11 -# -find_package(Python 3.10 EXACT COMPONENTS Interpreter Development) -#============================================================================ -# Find Gazebo dependencies - -# Default versions to Gazebo Garden -set(GZ_MSGS_VER 9) -set(GZ_TRANSPORT_VER 12) - -if("$ENV{GZ_VERSION}" STREQUAL "garden") - # Garden - message(STATUS "Compiling against Gazebo Garden") -else() - # Default to Garden - message(STATUS "Compiling against Gazebo Garden") -endif() - -find_package(gz-msgs${GZ_MSGS_VER} REQUIRED) -find_package(gz-transport${GZ_TRANSPORT_VER} REQUIRED) +find_package(Python COMPONENTS Interpreter Development) #============================================================================ # Build dependencies -set(_protobuf_repository "https://github.com/protocolbuffers/protobuf.git") -set(_protobuf_version 21.5) -set(_protobuf_tag v21.5) +set(_absl_repository "https://github.com/abseil/abseil-cpp.git") +set(_absl_version 20230802) +set(_absl_tag 20230802.1) +find_package(absl ${_absl_version} QUIET) -set(_pybind11_protobuf_repository "https://github.com/pybind/pybind11_protobuf.git") +set(_protobuf_repository "https://github.com/protocolbuffers/protobuf.git") +set(_protobuf_version 3.25.0) +set(_protobuf_tag v25.0) +# do not use system protobuf as it will not include proto_api.h +# see also: https://github.com/pybind/pybind11_protobuf/issues/127 +# find_package(Protobuf ${_protobuf_version} QUIET) + +set(_pybind11_repository "https://github.com/pybind/pybind11.git") +set(_pybind11_version 2.11.1) +set(_pybind11_tag v2.11.1) +find_package(pybind11 ${_pybind11_version} QUIET) + +set(_pybind11_protobuf_repository "https://github.com/srmainwaring/pybind11_protobuf.git") set(_pybind11_protobuf_version 0.0.0) -set(_pybind11_protobuf_tag main) +set(_pybind11_protobuf_tag prs/pr-proto-api-fix) +find_package(pybind11_protobuf ${_pybind11_version} QUIET) add_subdirectory(cmake/dependencies dependencies) list(APPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_BINARY_DIR}/dependencies/install) message("pybind11_protobuf_FOUND: ${pybind11_protobuf_FOUND}") message("pybind11_protobuf_SOURCE_DIR: ${pybind11_protobuf_SOURCE_DIR}") -message("pybind11_protobuf_INCLUDE_DIRS: ${pybind11_protobuf_INCLUDE_DIRS}") +message("pybind11_protobuf_SOURCE_DIR: ${pybind11_protobuf_SOURCE_DIR}") +message("protobuf_SOURCE_DIR: ${protobuf_SOURCE_DIR}") # TODO fix upstream... -set(pybind11_protobuf_INCLUDE_DIRS ${pybind11_protobuf_SOURCE_DIR}) +set(pybind11_protobuf_INCLUDE_DIRS + ${pybind11_protobuf_SOURCE_DIR} + ${protobuf_SOURCE_DIR} +) + #============================================================================ # gz_msgs_extras_lib C++ library diff --git a/cmake/dependencies/CMakeLists.txt b/cmake/dependencies/CMakeLists.txt index 9b7ae72..4dc954a 100644 --- a/cmake/dependencies/CMakeLists.txt +++ b/cmake/dependencies/CMakeLists.txt @@ -3,9 +3,19 @@ include(FetchContent) #============================================================================ # Declare all dependencies first -find_package(Protobuf ${_protobuf_version} EXACT QUIET) +if(NOT absl_FOUND) + set(ABSL_PROPAGATE_CXX_STD ON) + set(ABSL_ENABLE_INSTALL ON) + FetchContent_Declare( + absl + GIT_REPOSITORY ${_absl_repository} + GIT_TAG ${_absl_tag}) +endif() + if(NOT Protobuf_FOUND) - set(protobuf_BUILD_TESTS OFF CACHE INTERNAL "") + set(protobuf_BUILD_TESTS + OFF + CACHE INTERNAL "") FetchContent_Declare( Protobuf GIT_REPOSITORY ${_protobuf_repository} @@ -14,7 +24,14 @@ if(NOT Protobuf_FOUND) ) endif() -find_package(pybind11_protobuf ${_pybind11_protobuf_version} EXACT QUIET) +if(NOT pybind11_FOUND) + set(PYBIND11_TEST OFF) + FetchContent_Declare( + pybind11 + GIT_REPOSITORY ${_pybind11_repository} + GIT_TAG ${_pybind11_tag}) +endif() + if(NOT pybind11_protobuf_FOUND) FetchContent_Declare( pybind11_protobuf @@ -26,6 +43,14 @@ endif() #============================================================================ # Make dependencies avaialble +if(NOT absl_FOUND) + message(CHECK_START "Fetching Abseil-cpp") + list(APPEND CMAKE_MESSAGE_INDENT " ") + FetchContent_MakeAvailable(absl) + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "fetched") +endif() + if(NOT Protobuf_FOUND) message(CHECK_START "Fetching Protobuf") list(APPEND CMAKE_MESSAGE_INDENT " ") @@ -34,6 +59,14 @@ if(NOT Protobuf_FOUND) message(CHECK_PASS "fetched") endif() +if(NOT pybind11_FOUND) + message(CHECK_START "Fetching pybind11") + list(APPEND CMAKE_MESSAGE_INDENT " ") + FetchContent_MakeAvailable(pybind11) + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "fetched") +endif() + if(NOT pybind11_protobuf_FOUND) message(CHECK_START "Fetching pybind11_protobuf") list(APPEND CMAKE_MESSAGE_INDENT " ") From 056fb2eb57cd514cbccee24527eefe77207ec974 Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Tue, 30 Apr 2024 14:24:34 +0100 Subject: [PATCH 2/6] Update CMakeLists.txt to avoid conflicts with upstream libs - Support Garden and Harmonic (default). - Move extension modules into namespace gz.python to avoid conflicts. - Rename module extras to msgs_extras. - Remove Python binding generation - instead use bindings in gz-msgs. Signed-off-by: Rhys Mainwaring --- CMakeLists.txt | 188 +++--------------- .../gz/msgs/_gz_msgs_extras_pybind11.cc | 2 +- 2 files changed, 29 insertions(+), 161 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f70724..674cc43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,23 @@ set(pybind11_protobuf_INCLUDE_DIRS ${protobuf_SOURCE_DIR} ) +#============================================================================ +# Find Gazebo dependencies + +if("$ENV{GZ_VERSION}" STREQUAL "garden") + # Garden + set(GZ_MSGS_VER 9) + set(GZ_TRANSPORT_VER 12) + message(STATUS "Compiling against Gazebo Garden") +elseif("$ENV{GZ_VERSION}" STREQUAL "harmonic" OR NOT DEFINED "ENV{GZ_VERSION}") + # Harmonic (default) + message(STATUS "Compiling against Gazebo Harmonic") + set(GZ_MSGS_VER 10) + set(GZ_TRANSPORT_VER 13) +endif() + +find_package(gz-msgs${GZ_MSGS_VER} REQUIRED) +find_package(gz-transport${GZ_TRANSPORT_VER} REQUIRED) #============================================================================ # gz_msgs_extras_lib C++ library @@ -78,11 +95,11 @@ target_include_directories(gz_msgs_extras_lib #============================================================================ # msgs extras Python extension module -pybind11_add_module(extras MODULE +pybind11_add_module(msgs_extras MODULE src/pybind11/gz/msgs/_gz_msgs_extras_pybind11.cc ) -target_link_libraries(extras +target_link_libraries(msgs_extras PRIVATE gz_msgs_extras_lib gz-msgs${GZ_MSGS_VER}::gz-msgs${GZ_MSGS_VER} @@ -90,21 +107,21 @@ target_link_libraries(extras pybind11_native_proto_caster ) -target_include_directories(extras +target_include_directories(msgs_extras PRIVATE ${PROJECT_SOURCE_DIR}/include ${pybind11_protobuf_INCLUDE_DIRS} ) -add_dependencies(extras +add_dependencies(msgs_extras gz_msgs_extras_lib ) -set_target_properties(extras +set_target_properties(msgs_extras PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/msgs" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/msgs" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/msgs" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/python" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/python" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/python" ) #============================================================================ @@ -130,9 +147,9 @@ target_include_directories(transport set_target_properties(transport PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/python" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/python" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/gz/python" ) #============================================================================ @@ -213,152 +230,3 @@ target_link_libraries(gz_topic_echo gz-transport${GZ_TRANSPORT_VER}::gz-transport${GZ_TRANSPORT_VER} ) -#============================================================================ -# generate protobuf Python bindings - -# Get the proto files from the installed location of gz-msgs -set(PROTO_PATH ${gz-msgs${GZ_MSGS_VER}_INCLUDE_DIRS}) -file(GLOB PROTO_FILES ${PROTO_PATH}/gz/msgs/*.proto) - -#============================================================================ -# Modified from gz-msgs/src/CMakeLists.txt for Python -#============================================================================ -# A function that calls protoc on a protobuf file -# Options: -# GENERATE_RUBY - generates ruby code for the message if specified -# GENERATE_CPP - generates c++ code for the message if specified -# GENERATE_PY - generates Python code for the message if specified -# One value arguments: -# PROTO_PACKAGE - Protobuf package the file belongs to (e.g. ".gz.msgs") -# PROTOC_EXEC - Path to protoc -# INPUT_PROTO - Path to the input .proto file -# OUTPUT_CPP_DIR - Path where C++ files are saved -# OUTPUT_RUBY_DIR - Path where Ruby files are saved -# OUTPUT_PY_DIR - Path where Python files are saved -# OUTPUT_CPP_HH_VAR - A CMake variable name containing a list that the C++ header path should be appended to -# OUTPUT_CPP_CC_VAR - A CMake variable name containing a list that the C++ source path should be appended to -# OUTPUT_RUBY_VAR - A CMake variable name containing a list that the ruby file should be appended to -# OUTPUT_PY_VAR - A CMake variable name containing a list that the Python file should be appended to -# Multi value arguments -# PROTO_PATH - Passed to protoc --proto_path -function(gz_msgs_protoc) - set(options GENERATE_RUBY GENERATE_CPP GENERATE_PY) - set(oneValueArgs PROTO_PACKAGE PROTOC_EXEC INPUT_PROTO OUTPUT_CPP_DIR OUTPUT_RUBY_DIR OUTPUT_PY_DIR OUTPUT_CPP_HH_VAR OUTPUT_CPP_CC_VAR OUTPUT_RUBY_VAR OUTPUT_PY_VAR) - set(multiValueArgs PROTO_PATH) - - cmake_parse_arguments(gz_msgs_protoc "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - get_filename_component(ABS_FIL ${gz_msgs_protoc_INPUT_PROTO} ABSOLUTE) - get_filename_component(FIL_WE ${gz_msgs_protoc_INPUT_PROTO} NAME_WE) - - set(protoc_args) - set(output_files) - - foreach(proto_path ${gz_msgs_protoc_PROTO_PATH}) - list(APPEND protoc_args "--proto_path=${proto_path}") - endforeach() - - set(proto_package_dir ".") - if(gz_msgs_protoc_PROTO_PACKAGE) - string(REPLACE "." "/" proto_package_dir ${gz_msgs_protoc_PROTO_PACKAGE}) - endif() - - if(gz_msgs_protoc_GENERATE_CPP) - set(output_header "${gz_msgs_protoc_OUTPUT_CPP_DIR}${proto_package_dir}/${FIL_WE}.pb.h") - set(output_source "${gz_msgs_protoc_OUTPUT_CPP_DIR}${proto_package_dir}/${FIL_WE}.pb.cc") - list(APPEND ${gz_msgs_protoc_OUTPUT_CPP_HH_VAR} ${output_header}) - list(APPEND ${gz_msgs_protoc_OUTPUT_CPP_CC_VAR} ${output_source}) - list(APPEND output_files ${output_header}) - list(APPEND output_files ${output_source}) - list(APPEND protoc_args "--plugin=protoc-gen-gzmsgs=${GZ_MSGS_GEN_EXECUTABLE}") - list(APPEND protoc_args "--cpp_out=dllexport_decl=GZ__MSGS_VISIBLE:${gz_msgs_protoc_OUTPUT_CPP_DIR}") - list(APPEND protoc_args "--gzmsgs_out" "${gz_msgs_protoc_OUTPUT_CPP_DIR}") - set(${gz_msgs_protoc_OUTPUT_CPP_HH_VAR} ${${gz_msgs_protoc_OUTPUT_CPP_HH_VAR}} PARENT_SCOPE) - set(${gz_msgs_protoc_OUTPUT_CPP_CC_VAR} ${${gz_msgs_protoc_OUTPUT_CPP_CC_VAR}} PARENT_SCOPE) - endif() - - if(gz_msgs_protoc_GENERATE_RUBY) - file(MAKE_DIRECTORY ${gz_msgs_protoc_OUTPUT_RUBY_DIR}) - set(output_ruby "${gz_msgs_protoc_OUTPUT_RUBY_DIR}${proto_package_dir}/${FIL_WE}_pb.rb") - list(APPEND ${gz_msgs_protoc_OUTPUT_RUBY_VAR} ${output_ruby}) - list(APPEND output_files ${output_ruby}) - list(APPEND protoc_args "--ruby_out=${gz_msgs_protoc_OUTPUT_RUBY_DIR}") - set(${gz_msgs_protoc_OUTPUT_RUBY_VAR} ${${gz_msgs_protoc_OUTPUT_RUBY_VAR}} PARENT_SCOPE) - endif() - - if(gz_msgs_protoc_GENERATE_PY) - file(MAKE_DIRECTORY ${gz_msgs_protoc_OUTPUT_PY_DIR}) - set(output_py "${gz_msgs_protoc_OUTPUT_PY_DIR}${proto_package_dir}/${FIL_WE}_pb2.py") - list(APPEND ${gz_msgs_protoc_OUTPUT_PY_VAR} ${output_py}) - list(APPEND output_files ${output_py}) - list(APPEND protoc_args "--python_out=${gz_msgs_protoc_OUTPUT_PY_DIR}") - set(${gz_msgs_protoc_OUTPUT_PY_VAR} ${${gz_msgs_protoc_OUTPUT_PY_VAR}} PARENT_SCOPE) - endif() - - #get_cmake_property(_variableNames VARIABLES) - #foreach (_variableName ${_variableNames}) - # message(STATUS "${_variableName}=${${_variableName}}") - #endforeach() - - add_custom_command( - OUTPUT - ${output_files} - COMMAND - ${gz_msgs_protoc_PROTOC_EXEC} - ARGS - ${protoc_args} - ${ABS_FIL} - DEPENDS - ${ABS_FIL} - # gz_msgs_gen - COMMENT "Running protoc on ${gz_msgs_protoc_INPUT_PROTO}" - VERBATIM) -endfunction() - -#============================================================================ -# run the code generation -foreach(proto_file ${PROTO_FILES}) - gz_msgs_protoc( - PROTO_PACKAGE - .gz.msgs - # GENERATE_CPP - # GENERATE_RUBY - GENERATE_PY - INPUT_PROTO - ${proto_file} - PROTOC_EXEC - protobuf::protoc - OUTPUT_CPP_DIR - "${PROJECT_BINARY_DIR}/include" - OUTPUT_RUBY_DIR - "${PROJECT_BINARY_DIR}/ruby" - OUTPUT_PY_DIR - "${PROJECT_BINARY_DIR}/python" - OUTPUT_CPP_HH_VAR - gen_headers - OUTPUT_CPP_CC_VAR - gen_sources - OUTPUT_RUBY_VAR - gen_ruby_scripts - OUTPUT_PY_VAR - gen_py_scripts - PROTO_PATH - "${PROTO_PATH}") - -endforeach() - -#============================================================================ -# add custom target to force .proto compilation - -set_source_files_properties( - ${gen_headers} - ${gen_sources} - ${gen_ruby_scripts} - ${gen_py_scripts} - PROPERTIES GENERATED TRUE -) - -foreach(gen_py_script ${gen_py_scripts}) - get_filename_component(FIL_WE ${gen_py_script} NAME_WE) - add_custom_target(${FIL_WE} ALL DEPENDS ${gen_py_script}) -endforeach() diff --git a/src/pybind11/gz/msgs/_gz_msgs_extras_pybind11.cc b/src/pybind11/gz/msgs/_gz_msgs_extras_pybind11.cc index 5d5e751..4d1bf84 100644 --- a/src/pybind11/gz/msgs/_gz_msgs_extras_pybind11.cc +++ b/src/pybind11/gz/msgs/_gz_msgs_extras_pybind11.cc @@ -23,7 +23,7 @@ namespace py = pybind11; -PYBIND11_MODULE(extras, m) +PYBIND11_MODULE(msgs_extras, m) { using namespace gz; using namespace msgs; From 499674f9eff643cd4ece6a9fa9eea2f7d02adf41 Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Tue, 30 Apr 2024 14:27:53 +0100 Subject: [PATCH 3/6] Update copyright notice Signed-off-by: Rhys Mainwaring --- python/gz_service_info.py | 2 +- python/gz_service_list.py | 2 +- python/gz_topic_echo.py | 2 +- python/gz_topic_info.py | 2 +- python/gz_topic_list.py | 2 +- python/import_check.py | 2 +- python/msgs_example.py | 2 +- python/pub_all_msg_types.py | 2 +- python/publisher.py | 2 +- python/rover_publisher.py | 2 +- python/rover_subscriber.py | 2 +- python/subscriber.py | 2 +- python/transport_example.py | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/python/gz_service_info.py b/python/gz_service_info.py index 96c9ed1..43a771c 100755 --- a/python/gz_service_info.py +++ b/python/gz_service_info.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/gz_service_list.py b/python/gz_service_list.py index 7c994dc..b93d1ca 100755 --- a/python/gz_service_list.py +++ b/python/gz_service_list.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/gz_topic_echo.py b/python/gz_topic_echo.py index 463b3e1..0a55527 100755 --- a/python/gz_topic_echo.py +++ b/python/gz_topic_echo.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/gz_topic_info.py b/python/gz_topic_info.py index 535c847..f3d1c59 100755 --- a/python/gz_topic_info.py +++ b/python/gz_topic_info.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/gz_topic_list.py b/python/gz_topic_list.py index 41e64c0..6e7ed43 100755 --- a/python/gz_topic_list.py +++ b/python/gz_topic_list.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/import_check.py b/python/import_check.py index 9b6ee89..a16aa8d 100755 --- a/python/import_check.py +++ b/python/import_check.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/msgs_example.py b/python/msgs_example.py index ce04756..e22ae61 100755 --- a/python/msgs_example.py +++ b/python/msgs_example.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/pub_all_msg_types.py b/python/pub_all_msg_types.py index 9f0a87c..ff40ab3 100755 --- a/python/pub_all_msg_types.py +++ b/python/pub_all_msg_types.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/publisher.py b/python/publisher.py index a16c421..74e8733 100755 --- a/python/publisher.py +++ b/python/publisher.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/rover_publisher.py b/python/rover_publisher.py index 1269b67..526fcd7 100755 --- a/python/rover_publisher.py +++ b/python/rover_publisher.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/rover_subscriber.py b/python/rover_subscriber.py index 8561580..9f2287b 100755 --- a/python/rover_subscriber.py +++ b/python/rover_subscriber.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/subscriber.py b/python/subscriber.py index 1c54b51..eb864bc 100755 --- a/python/subscriber.py +++ b/python/subscriber.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. diff --git a/python/transport_example.py b/python/transport_example.py index fd72ae3..3e74454 100755 --- a/python/transport_example.py +++ b/python/transport_example.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2022 Rhys Mainwaring +# Copyright (C) 2022-2024 Rhys Mainwaring # # Licensed under the Apache License, Version 2.0 (the "License") # you may not use this file except in compliance with the License. From f564b6881ca14c541789b73cf5e9cb91ac5bf6cb Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Tue, 30 Apr 2024 14:38:04 +0100 Subject: [PATCH 4/6] Update module names in Python examples Signed-off-by: Rhys Mainwaring --- python/gz_service_info.py | 2 +- python/gz_service_list.py | 2 +- python/gz_topic_echo.py | 14 ++++++++++++-- python/gz_topic_info.py | 3 ++- python/gz_topic_list.py | 2 +- python/import_check.py | 25 +++++++++++++++++-------- python/msgs_example.py | 10 ++++++++++ python/pub_all_msg_types.py | 14 ++++++++++++-- python/publisher.py | 13 +++++++++++-- python/rover_publisher.py | 13 +++++++++++-- python/rover_subscriber.py | 13 +++++++++++-- python/subscriber.py | 13 +++++++++++-- python/transport_example.py | 16 +++++++++++++--- 13 files changed, 113 insertions(+), 27 deletions(-) diff --git a/python/gz_service_info.py b/python/gz_service_info.py index 43a771c..a48ff3d 100755 --- a/python/gz_service_info.py +++ b/python/gz_service_info.py @@ -22,7 +22,7 @@ import argparse -from gz.transport import Node +from gz.python.transport import Node def main(): # process command line diff --git a/python/gz_service_list.py b/python/gz_service_list.py index b93d1ca..ba79303 100755 --- a/python/gz_service_list.py +++ b/python/gz_service_list.py @@ -20,7 +20,7 @@ $ gz service -l ''' -from gz.transport import Node +from gz.python.transport import Node def main(): # create a transport node diff --git a/python/gz_topic_echo.py b/python/gz_topic_echo.py index 0a55527..29baa0a 100755 --- a/python/gz_topic_echo.py +++ b/python/gz_topic_echo.py @@ -21,10 +21,20 @@ ''' import argparse +import os import time -from gz.transport import SubscribeOptions -from gz.transport import Node +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + +from gz.python.transport import SubscribeOptions +from gz.python.transport import Node + # callback - prints the raw message def cb(msg): diff --git a/python/gz_topic_info.py b/python/gz_topic_info.py index f3d1c59..480c1a2 100755 --- a/python/gz_topic_info.py +++ b/python/gz_topic_info.py @@ -22,7 +22,8 @@ import argparse -from gz.transport import Node +from gz.python.transport import Node + def main(): # process command line diff --git a/python/gz_topic_list.py b/python/gz_topic_list.py index 6e7ed43..e9d4979 100755 --- a/python/gz_topic_list.py +++ b/python/gz_topic_list.py @@ -19,8 +19,8 @@ $ gz topic -l ''' +from gz.python.transport import Node -from gz.transport import Node def main(): # create a transport node diff --git a/python/import_check.py b/python/import_check.py index a16aa8d..059e95e 100755 --- a/python/import_check.py +++ b/python/import_check.py @@ -14,21 +14,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys -import time +import os + +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") from gz.msgs.any_pb2 import Any from gz.msgs.header_pb2 import Header from gz.msgs.stringmsg_pb2 import StringMsg from gz.msgs.time_pb2 import Time -from gz.msgs.extras import make_time -from gz.msgs.extras import take_time -from gz.msgs.extras import take_topic_info -from gz.msgs.extras import take_wrench +from gz.python.msgs_extras import make_time +from gz.python.msgs_extras import take_time +from gz.python.msgs_extras import take_topic_info +from gz.python.msgs_extras import take_wrench -from gz.transport import AdvertiseMessageOptions -from gz.transport import Node +from gz.python.transport import AdvertiseMessageOptions +from gz.python.transport import Node def main(): @@ -39,9 +46,11 @@ def main(): msg = Any() msg = Header() msg = StringMsg() + msg = Time() # msgs functions msg = make_time() + take_time(msg) # transport types opts = AdvertiseMessageOptions() diff --git a/python/msgs_example.py b/python/msgs_example.py index e22ae61..289e7a4 100755 --- a/python/msgs_example.py +++ b/python/msgs_example.py @@ -14,6 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os + +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + from gz.msgs.header_pb2 import Header from gz.msgs.double_pb2 import Double from gz.msgs.double_v_pb2 import Double_V diff --git a/python/pub_all_msg_types.py b/python/pub_all_msg_types.py index ff40ab3..b53d6e7 100755 --- a/python/pub_all_msg_types.py +++ b/python/pub_all_msg_types.py @@ -14,8 +14,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import time +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + from gz.msgs.cmd_vel2d_pb2 import CmdVel2D from gz.msgs.double_pb2 import Double from gz.msgs.double_v_pb2 import Double_V @@ -35,8 +44,9 @@ from gz.msgs.vector3d_pb2 import Vector3d from gz.msgs.wrench_pb2 import Wrench -from gz.transport import AdvertiseMessageOptions -from gz.transport import Node +from gz.python.transport import AdvertiseMessageOptions +from gz.python.transport import Node + def main(): # Create a transport node and advertise options diff --git a/python/publisher.py b/python/publisher.py index 74e8733..db11a4f 100755 --- a/python/publisher.py +++ b/python/publisher.py @@ -14,12 +14,21 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import time +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + from gz.msgs.stringmsg_pb2 import StringMsg -from gz.transport import AdvertiseMessageOptions -from gz.transport import Node +from gz.python.transport import AdvertiseMessageOptions +from gz.python.transport import Node def main(): # Create a transport node and advertise a topic diff --git a/python/rover_publisher.py b/python/rover_publisher.py index 526fcd7..3196992 100755 --- a/python/rover_publisher.py +++ b/python/rover_publisher.py @@ -16,8 +16,17 @@ from scipy.spatial.transform import Rotation as Rotation import math +import os import time +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + from gz.msgs.header_pb2 import Header from gz.msgs.pose_pb2 import Pose from gz.msgs.quaternion_pb2 import Quaternion @@ -25,8 +34,8 @@ from gz.msgs.twist_pb2 import Twist from gz.msgs.vector3d_pb2 import Vector3d -from gz.transport import AdvertiseMessageOptions -from gz.transport import Node +from gz.python.transport import AdvertiseMessageOptions +from gz.python.transport import Node def main(): # Create a transport node and advertise a topic diff --git a/python/rover_subscriber.py b/python/rover_subscriber.py index 9f2287b..737542d 100755 --- a/python/rover_subscriber.py +++ b/python/rover_subscriber.py @@ -15,15 +15,24 @@ # limitations under the License. import time +import os import typing +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + from gz.msgs.pose_pb2 import Pose from gz.msgs.quaternion_pb2 import Quaternion from gz.msgs.twist_pb2 import Twist from gz.msgs.vector3d_pb2 import Vector3d -from gz.transport import Node -from gz.transport import SubscribeOptions +from gz.python.transport import Node +from gz.python.transport import SubscribeOptions def pose_cb(msg: Pose) -> None: diff --git a/python/subscriber.py b/python/subscriber.py index eb864bc..b0d7cad 100755 --- a/python/subscriber.py +++ b/python/subscriber.py @@ -15,12 +15,21 @@ # limitations under the License. import time +import os import typing +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + from gz.msgs.stringmsg_pb2 import StringMsg -from gz.transport import SubscribeOptions -from gz.transport import Node +from gz.python.transport import SubscribeOptions +from gz.python.transport import Node def cb(msg: StringMsg) -> None: print("Msg: [{}] from Python".format(msg.data)) diff --git a/python/transport_example.py b/python/transport_example.py index 3e74454..df20104 100755 --- a/python/transport_example.py +++ b/python/transport_example.py @@ -14,6 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os + +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") + from gz.msgs.header_pb2 import Header from gz.msgs.time_pb2 import Time from gz.msgs.quaternion_pb2 import Quaternion @@ -22,9 +32,9 @@ from gz.msgs.vector3d_pb2 import Vector3d from gz.msgs.wrench_pb2 import Wrench -from gz.transport import AdvertiseMessageOptions -from gz.transport import SubscribeOptions -from gz.transport import Node +from gz.python.transport import AdvertiseMessageOptions +from gz.python.transport import SubscribeOptions +from gz.python.transport import Node from google.protobuf.internal import api_implementation From e6465f5590f5ae8a1fa8e70af44f8d397a808590 Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Tue, 30 Apr 2024 15:37:25 +0100 Subject: [PATCH 5/6] Update docs to reflect changed module namespace. Signed-off-by: Rhys Mainwaring --- README.md | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b1c82b6..b28f443 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This project provides Python bindings for [`gz-msgs`](https://github.com/gazebos ### Install Gazebo -Follow the installation instructions for [Gazebo Garden](https://gazebosim.org/docs/garden). +Follow the installation instructions for [Gazebo Harmonic](https://gazebosim.org/docs/harmonic). This project depends directly on [`gz-msgs`](https://github.com/gazebosim/gz-msgs) and [`gz-transport`](https://github.com/gazebosim/gz-transport). These may be either available as system installs or in a source install in a local workspace folder which we assume is `~/gz_ws`. ### Install `gz-python` @@ -29,10 +29,10 @@ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python ``` Set the environment variable determing the Gazebo version. -The default is `garden`: +The default is `harmonic`, although `garden` is also supported: ```bash -export GAZEBO_VERSION=garden +export GAZEBO_VERSION=harmonic ``` Then create a build directory, configure and make: @@ -46,23 +46,42 @@ make ### Update the Python environment -Update the PYTHONPATH to include the location of the extension modules and the -generated Python protobuf bindings. +Update the `PYTHONPATH` to include the location of the extension modules: ```bash cd ~/gz_ws/src/gz-python export PYTHONPATH=${PYTHONPATH}:$(pwd)/build/python ``` +As `gz-msgs` now generates Python bindings for its `*.proto` definitions +this project no longer generates them, so ensure that the `PYTHONPATH` also includes the path to the Gazebo Python bindings. + + ## Usage ### `gz-msg` bindings The Python bindings for `gz-msgs` are the standard generated protobuf code -for Python. For example `gz-msgs/proto/gz/msgs/time.proto` may be used as follows: +for Python. + +Gazebo uses versioned module names, to use unversioned module names add the following before importing messages: + +```python +import os + +# alias gz.msgs{GZ_MSGS_VER} to gz.msgs +if os.environ["GZ_VERSION"] == "garden": + from gz import msgs9 as msgs +elif os.environ["GZ_VERSION"] == "harmonic": + from gz import msgs10 as msgs +else: + raise Exception(f"Invalid GZ_VERSION: {os.environ['GZ_VERSION']}") +``` + +In the remaining examples the unversioned imports for messages are assumed. +For example `gz-msgs/proto/gz/msgs/time.proto` may be used as follows: ```python -# example.py from gz.msgs.time_pb2 import Time msg = Time() @@ -73,7 +92,7 @@ print(msg) ### `gz-transport` bindings -The Python bindings for `gz-transport` are contained in a module called `transport`. +The Python bindings for `gz-transport` are contained in a module called `gz.python.transport`. The object naming and usage for the most part follows the C++ interface, so the C++ Gazebo Tutorials are a good guide on how to use the library. @@ -82,8 +101,8 @@ Publish: ```python from gz.msgs.stringmsg_pb2 import StringMsg -from gz.transport import AdvertiseMessageOptions -from gz.transport import Node +from gz.python.transport import AdvertiseMessageOptions +from gz.python.transport import Node # Create a transport node node = Node() @@ -108,8 +127,8 @@ import typing from gz.msgs.stringmsg_pb2 import StringMsg -from gz.transport import SubscribeOptions -from gz.transport import Node +from gz.python.transport import SubscribeOptions +from gz.python.transport import Node def cb(msg: StringMsg) -> None: print("Msg: [{}] from Python".format(msg.data)) @@ -386,7 +405,7 @@ On macOS Bazel can be installed with `brew`: brew install bazel ``` -The [Google protocol buffers compiler](https://github.com/protocolbuffers/protobuf) version `3.19` is also required and can be installed with: +The [Google protocol buffers compiler](https://github.com/protocolbuffers/protobuf) version `25.0` is also required and can be installed with: ```bash @@ -502,11 +521,11 @@ py_binary( ### Protobuf compiler version -The project depends on `protoc` version `3.19.1`. You must ensure that the version of `protoc` installed by `brew` matches (otherwise the examples will segfault). +The project depends on `protoc` version `25.0`. You must ensure that the version of `protoc` installed by `brew` matches (otherwise the examples will segfault). ```bash $ protoc --version -libprotoc 3.19.1 +libprotoc 25.0 ``` ### Protobuf generated Python libraries From 391d7c1ff6d7f8c2f827c49a85b08435f50ab473 Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Tue, 30 Apr 2024 15:51:54 +0100 Subject: [PATCH 6/6] Update CI to use Harmonic Signed-off-by: Rhys Mainwaring --- .github/workflows/ubuntu-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml index f222be6..8b3d247 100644 --- a/.github/workflows/ubuntu-build.yml +++ b/.github/workflows/ubuntu-build.yml @@ -51,12 +51,12 @@ jobs: python3-vcstool \ python3-colcon-common-extensions - - name: Install Gazebo Garden + - name: Install Gazebo Harmonic run: | sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null sudo apt update && sudo apt install --no-install-recommends -y \ - gz-garden + gz-harmonic - name: Build run: |