Skip to content

Commit b109bb7

Browse files
committed
working, still WIP
Signed-off-by: William Woodall <[email protected]>
1 parent 8da5bcb commit b109bb7

File tree

6 files changed

+474
-13
lines changed

6 files changed

+474
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

grpc_vendor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ ament_vendor(grpc_vendor
3434
-DgRPC_BUILD_NODE_PLUGIN:BOOL=OFF
3535
-DgRPC_BUILD_OBJECTIVEC_PLUGIN:BOOL=OFF
3636
-DgRPC_BUILD_RUBY_PLUGIN:BOOL=OFF
37+
-DgRPC_BUILD_GRPC_PYTHON_PLUGIN=ON
3738
-DgRPC_PROTOBUF_PROVIDER:STRING=module
3839
-DPROTOBUF_ROOT_DIR=${PROTOBUF_ROOT_DIR}
3940
)

intrinsic_sdk_cmake/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ include(cmake/sdk_imw_zenoh.cmake)
3434
# Build the sdk C++ sources into a library.
3535
include(cmake/sdk.cmake)
3636

37+
# Collect and install the sdk Python sources.
38+
include(cmake/sdk_python.cmake)
39+
3740
# Extract tool binaries from bazel build of sdk.
3841
include(cmake/sdk_tools.cmake)
3942

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
set(python_package_directory ${PYTHON_PACKAGE_DIRECTORY})
2+
set(python_package_to_install_package_dir
3+
"${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/${python_package_directory}")
4+
set(python_package_to_install_package_dir_fixed
5+
"${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/fixed_imports/${python_package_directory}")
6+
7+
file(GLOB_RECURSE python_package_sources
8+
RELATIVE "${python_package_to_install_package_dir}"
9+
"${python_package_to_install_package_dir}/**/*.py"
10+
)
11+
12+
set(FIND_LIST
13+
"from google.api"
14+
"from google.longrunning"
15+
"from google.rpc"
16+
"from google.type"
17+
)
18+
set(REPLACE_LIST
19+
"from googleapis.google.api"
20+
"from googleapis.google.longrunning"
21+
"from googleapis.google.rpc"
22+
"from googleapis.google.type"
23+
)
24+
25+
foreach(python_package_source ${python_package_sources})
26+
set(source_file "${python_package_to_install_package_dir}/${python_package_source}")
27+
set(target_file "${python_package_to_install_package_dir_fixed}/${python_package_source}")
28+
29+
file(READ "${source_file}" contents)
30+
31+
list(LENGTH FIND_LIST len1)
32+
math(EXPR len2 "${len1} - 1")
33+
34+
foreach(val RANGE ${len2})
35+
list(GET FIND_LIST ${val} find)
36+
list(GET REPLACE_LIST ${val} replace)
37+
38+
message(STATUS "'${find}' -> '${replace}' in '${source_file}'")
39+
string(REPLACE "${find}" "${replace}" contents "${contents}")
40+
endforeach()
41+
42+
get_filename_component(target_file_dir "${target_file}" DIRECTORY)
43+
file(MAKE_DIRECTORY "${target_file_dir}")
44+
45+
file(WRITE "${target_file}" "${contents}")
46+
endforeach()

intrinsic_sdk_cmake/cmake/sdk_protos.cmake

Lines changed: 168 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protos_gen)
2+
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py)
23

34
file(GLOB_RECURSE intrinsic_proto_SRCS "${intrinsic_sdk_SOURCE_DIR}/**/*.proto")
45
list(FILTER intrinsic_proto_SRCS EXCLUDE REGEX "_test\\.proto$")
56

67
set(exclude_SRCS
7-
intrinsic/icon/proto/service.proto
8+
intrinsic/icon/proto/service.proto
89
third_party/ros2/ros_interfaces/jazzy/diagnostic_msgs/srv/self_test.proto
910
third_party/ros2/ros_interfaces/jazzy/diagnostic_msgs/srv/add_diagnostics.proto
1011
third_party/ros2/ros_interfaces/jazzy/rcl_interfaces/srv/set_parameters.proto
@@ -77,22 +78,28 @@ set(grpc_gateway_SRCS
7778
${grpc_gateway_SOURCE_DIR}/protoc-gen-openapiv2/options/openapiv2.proto
7879
)
7980

80-
# Generate code from protos and build into a library.
81-
add_library(intrinsic_sdk_protos STATIC
81+
set(sdk_protos
8282
${intrinsic_proto_SRCS}
8383
${googleapis_SRCS}
8484
${grpc_gateway_SRCS}
8585
${grpc_SRCS}
8686
)
87+
set(sdk_proto_import_dirs
88+
${intrinsic_sdk_SOURCE_DIR}
89+
${googleapis_SOURCE_DIR}
90+
${grpc_gateway_SOURCE_DIR}
91+
${grpc_SOURCE_DIR}
92+
)
93+
94+
# Generate code from protos and build into a library.
95+
add_library(intrinsic_sdk_protos STATIC
96+
${sdk_protos}
97+
)
8798
set_property(TARGET intrinsic_sdk_protos PROPERTY POSITION_INDEPENDENT_CODE ON)
8899
protobuf_generate(
89100
TARGET intrinsic_sdk_protos
90101
LANGUAGE cpp
91-
IMPORT_DIRS
92-
${intrinsic_sdk_SOURCE_DIR}
93-
${googleapis_SOURCE_DIR}
94-
${grpc_gateway_SOURCE_DIR}
95-
${grpc_SOURCE_DIR}
102+
IMPORT_DIRS ${sdk_proto_import_dirs}
96103
PROTOC_OPTIONS --experimental_editions
97104
PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/protos_gen
98105
)
@@ -114,11 +121,7 @@ protobuf_generate(
114121
TARGET intrinsic_sdk_services
115122
LANGUAGE grpc
116123
PLUGIN protoc-gen-grpc=$<TARGET_FILE:gRPC::grpc_cpp_plugin>
117-
IMPORT_DIRS
118-
${intrinsic_sdk_SOURCE_DIR}
119-
${googleapis_SOURCE_DIR}
120-
${grpc_gateway_SOURCE_DIR}
121-
${grpc_SOURCE_DIR}
124+
IMPORT_DIRS ${sdk_proto_import_dirs}
122125
PROTOC_OPTIONS --experimental_editions
123126
PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/protos_gen
124127
GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
@@ -131,6 +134,158 @@ target_include_directories(intrinsic_sdk_services
131134
target_link_libraries(intrinsic_sdk_services PUBLIC intrinsic_sdk_protos)
132135
set_property(TARGET intrinsic_sdk_services PROPERTY POSITION_INDEPENDENT_CODE ON)
133136

137+
# Generate Python code from the protos.
138+
# add_custom_target(intrinsic_sdk_protos_python ALL DEPENDS ${sdk_protos})
139+
# protobuf_generate(
140+
# TARGET intrinsic_sdk_protos_python
141+
# PLUGIN protoc-gen-grpc=$<TARGET_FILE:gRPC::grpc_python_plugin>
142+
# LANGUAGE python
143+
# PROTOS ${sdk_protos}
144+
# IMPORT_DIRS ${sdk_proto_import_dirs}
145+
# PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py
146+
# OUT_VAR sdk_protos_python_sources_maybe_hyphens
147+
# )
148+
# Use the protoc from the grpcio-tools Python package to generate _pb2.py and _pb2_grpc.py files.
149+
set(venv_dir "${CMAKE_CURRENT_BINARY_DIR}/grpc_venv")
150+
if(NOT EXISTS "${venv_dir}")
151+
execute_process(
152+
COMMAND "${Python3_EXECUTABLE}" -m venv "${venv_dir}"
153+
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
154+
RESULT_VARIABLE VENV_CREATE_RESULT
155+
OUTPUT_VARIABLE VENV_CREATE_OUTPUT
156+
ERROR_VARIABLE VENV_CREATE_ERROR
157+
)
158+
if(NOT VENV_CREATE_RESULT EQUAL 0)
159+
message(FATAL_ERROR "Failed to create virtual environment: ${VENV_CREATE_ERROR}")
160+
endif()
161+
162+
execute_process(
163+
COMMAND "${venv_dir}/bin/pip" install -U grpcio-tools
164+
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
165+
RESULT_VARIABLE PIP_INSTALL_RESULT
166+
OUTPUT_VARIABLE PIP_INSTALL_OUTPUT
167+
ERROR_VARIABLE PIP_INSTALL_ERROR
168+
)
169+
if(NOT PIP_INSTALL_RESULT EQUAL 0)
170+
message(FATAL_ERROR "Failed to install Python dependencies: ${PIP_INSTALL_ERROR}")
171+
endif()
172+
endif()
173+
set(protoc_include_flags)
174+
foreach(sdk_proto_import_dir ${sdk_proto_import_dirs})
175+
list(APPEND protoc_include_flags -I "${sdk_proto_import_dir}")
176+
endforeach()
177+
set(protoc_generated_files)
178+
foreach(sdk_proto ${sdk_protos})
179+
set(_proto ${sdk_proto})
180+
get_filename_component(_abs_file ${_proto} ABSOLUTE)
181+
get_filename_component(_abs_dir ${_abs_file} DIRECTORY)
182+
get_filename_component(_file_full_name ${_proto} NAME)
183+
string(FIND "${_file_full_name}" "." _file_last_ext_pos REVERSE)
184+
string(SUBSTRING "${_file_full_name}" 0 ${_file_last_ext_pos} _basename)
185+
set(_suitable_include_found FALSE)
186+
foreach(DIR ${sdk_proto_import_dirs})
187+
if(NOT DIR STREQUAL "-I")
188+
file(RELATIVE_PATH _rel_dir ${DIR} ${_abs_dir})
189+
if(_rel_dir STREQUAL _abs_dir)
190+
# When there is no relative path from DIR to _abs_dir (e.g. due to
191+
# different drive letters on Windows), _rel_dir is equal to _abs_dir.
192+
# Therefore, DIR is not a suitable include path and must be skipped.
193+
continue()
194+
endif()
195+
string(FIND "${_rel_dir}" "../" _is_in_parent_folder)
196+
if (NOT ${_is_in_parent_folder} EQUAL 0)
197+
set(_suitable_include_found TRUE)
198+
break()
199+
endif()
200+
endif()
201+
endforeach()
202+
if(NOT _suitable_include_found)
203+
message(FATAL_ERROR "Error: could not find any correct proto include directory: ${_proto}")
204+
endif()
205+
set(_proto_generated_files)
206+
list(APPEND _proto_generated_files
207+
"${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/${_rel_dir}/${_basename}_pb2.py")
208+
list(APPEND _proto_generated_files
209+
"${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/${_rel_dir}/${_basename}_pb2_grpc.py")
210+
list(APPEND protoc_generated_files ${_proto_generated_files})
211+
add_custom_command(
212+
OUTPUT ${_proto_generated_files}
213+
DEPENDS "${sdk_proto}"
214+
COMMAND
215+
"${venv_dir}/bin/python3"
216+
-m grpc_tools.protoc
217+
${protoc_include_flags}
218+
--python_out="${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py"
219+
--grpc_python_out="${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py"
220+
"${sdk_proto}"
221+
COMMENT "Using 'grpc_tools.protoc' to generate Python code for '${sdk_proto}'..."
222+
)
223+
endforeach()
224+
add_custom_target(intrinsic_sdk_protos_python ALL DEPENDS ${sdk_protos} ${protoc_generated_files})
225+
set(sdk_protos_python_sources_maybe_hyphens ${protoc_generated_files})
226+
# Create empty __init__.py files for each python package generated by protoc.
227+
set(sdk_protos_python_sources "")
228+
set(python_package_directories "")
229+
foreach(generated_python_file_maybe_hyphen ${sdk_protos_python_sources_maybe_hyphens})
230+
file(RELATIVE_PATH rel_generated_python_file_maybe_hyphen
231+
"${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py"
232+
"${generated_python_file_maybe_hyphen}"
233+
)
234+
string(REPLACE "-" "_" rel_generated_python_file "${rel_generated_python_file_maybe_hyphen}")
235+
set(generated_python_file "${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/${rel_generated_python_file}")
236+
list(APPEND sdk_protos_python_sources "${generated_python_file}")
237+
get_filename_component(generated_python_file_dir "${generated_python_file}" DIRECTORY)
238+
list(APPEND python_package_directories "${generated_python_file_dir}")
239+
endforeach()
240+
list(REMOVE_DUPLICATES python_package_directories)
241+
set(python_init_py_files "")
242+
# add __init__.py to "leaf" directories
243+
foreach(python_package_directory ${python_package_directories})
244+
file(MAKE_DIRECTORY "${python_package_directory}")
245+
set(python_init_py_file "${python_package_directory}/__init__.py")
246+
list(APPEND python_init_py_files "${python_init_py_file}")
247+
file(TOUCH "${python_init_py_file}")
248+
endforeach()
249+
# second pass to add __init__.py to intermediate directories now that the folder structure exists.
250+
file(GLOB_RECURSE leaf_python_init_files_and_dirs
251+
LIST_DIRECTORIES true
252+
RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/"
253+
"${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/*/__init__.py"
254+
)
255+
foreach(leaf_python_init_file_or_dir ${leaf_python_init_files_and_dirs})
256+
if(IS_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/${leaf_python_init_file_or_dir}")
257+
set(python_init_py_file "${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/${leaf_python_init_file_or_dir}/__init__.py")
258+
list(APPEND python_init_py_files "${python_init_py_file}")
259+
file(TOUCH "${python_init_py_file}")
260+
endif()
261+
endforeach()
262+
# final pass because glob doesn't get the root folders correctly.
263+
file(GLOB root_directories
264+
LIST_DIRECTORIES true
265+
"${CMAKE_CURRENT_BINARY_DIR}/protos_gen_py/*"
266+
)
267+
foreach(root_directory ${root_directories})
268+
if(IS_DIRECTORY "${root_directory}")
269+
set(python_init_py_file "${root_directory}/__init__.py")
270+
list(APPEND python_init_py_files "${python_init_py_file}")
271+
file(TOUCH "${python_init_py_file}")
272+
endif()
273+
endforeach()
274+
list(REMOVE_DUPLICATES python_init_py_files)
275+
276+
# add_custom_target(intrinsic_sdk_protos_python_grpc ALL DEPENDS ${sdk_protos})
277+
# foreach(sdk_protos_python_source ${sdk_protos_python_sources})
278+
# string(REPLACE "_pb2.py" "_pb2_grpc.py" grpc_version "${sdk_protos_python_source}")
279+
# add_custom_command(
280+
# TARGET intrinsic_sdk_protos_python_grpc POST_BUILD
281+
# DEPENDS "${sdk_protos_python_source}" intrinsic_sdk_protos_python
282+
# COMMAND ${CMAKE_COMMAND} -E copy "${sdk_protos_python_source}" "${grpc_version}"
283+
# COMMENT "Duplicating '${sdk_protos_python_source}' as '${grpc_version}'..."
284+
# )
285+
# endforeach()
286+
287+
# Generated Python code is installed with the Python sdk files later.
288+
134289
# Generate a descriptor set.
135290
add_custom_command(
136291
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/intrinsic_proto.desc

0 commit comments

Comments
 (0)