pw_protobuf_compiler: Decouple proto packaging from directory
- Allow specifying prefix and strip_prefix arguments for proto files.
The proto directory tree is built as specified in the out directory.
- Only invoke protoc from the default toolchain. This prevents duplicate
protoc invocations.
- Prevent duplicate pw_proto_library Python package definitions anywhere
in the build.
- Replace implicit handling of standalone external protos with a
python_package_as_module option.
Change-Id: Id37d8b4d83294f7d3142a389e74ceea96dd4d620
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/34640
Reviewed-by: Alexei Frolov <frolv@google.com>
diff --git a/pw_protobuf_compiler/proto.cmake b/pw_protobuf_compiler/proto.cmake
index 73b06b6..cc07ce0 100644
--- a/pw_protobuf_compiler/proto.cmake
+++ b/pw_protobuf_compiler/proto.cmake
@@ -30,11 +30,16 @@
# NAME - the base name of the libraries to create
# SOURCES - .proto source files
# DEPS - dependencies on other pw_proto_library targets
+# PREFIX - prefix add to the proto files
+# STRIP_PREFIX - prefix to remove from the proto files
+# INPUTS - files to include along with the .proto files (such as Nanopb
+# .options files
#
function(pw_proto_library NAME)
- cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "SOURCES;DEPS")
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "STRIP_PREFIX;PREFIX"
+ "SOURCES;INPUTS;DEPS")
- set(out_dir "${CMAKE_CURRENT_BINARY_DIR}/protos")
+ set(out_dir "${CMAKE_CURRENT_BINARY_DIR}/${NAME}")
# Use INTERFACE libraries to track the proto include paths that are passed to
# protoc.
@@ -46,33 +51,77 @@
target_link_libraries("${NAME}._includes" INTERFACE ${include_deps})
# Generate a file with all include paths needed by protoc.
- set(include_file "${out_dir}/${NAME}.include_paths.txt")
+ set(include_file "${out_dir}/include_paths.txt")
file(GENERATE OUTPUT "${include_file}"
CONTENT
"$<TARGET_PROPERTY:${NAME}._includes,INTERFACE_INCLUDE_DIRECTORIES>")
+ if("${arg_STRIP_PREFIX}" STREQUAL "")
+ set(arg_STRIP_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+
+ foreach(path IN LISTS arg_SOURCES arg_INPUTS)
+ get_filename_component(abspath "${path}" ABSOLUTE)
+ list(APPEND files_to_mirror "${abspath}")
+ endforeach()
+
+ # Mirror the sources to the output directory with the specified prefix.
+ _pw_rebase_paths(
+ sources "${out_dir}/sources/${arg_PREFIX}" "${arg_STRIP_PREFIX}" "${arg_SOURCES}" "")
+ _pw_rebase_paths(
+ inputs "${out_dir}/sources/${arg_PREFIX}" "${arg_STRIP_PREFIX}" "${arg_INPUTS}" "")
+
+ add_custom_command(
+ COMMAND
+ python
+ "$ENV{PW_ROOT}/pw_build/py/pw_build/mirror_tree.py"
+ --source-root "${arg_STRIP_PREFIX}"
+ --directory "${out_dir}/sources/${arg_PREFIX}"
+ ${files_to_mirror}
+ DEPENDS
+ "$ENV{PW_ROOT}/pw_build/py/pw_build/mirror_tree.py"
+ ${files_to_mirror}
+ ${arg_DEPS}
+ OUTPUT
+ ${sources} ${inputs}
+ )
+
# Create a protobuf target for each supported protobuf library.
_pw_pwpb_library(
- "${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
+ "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
_pw_raw_rpc_library(
- "${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
+ "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
_pw_nanopb_library(
- "${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
+ "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
_pw_nanopb_rpc_library(
- "${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
+ "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
endfunction(pw_proto_library)
+function(_pw_rebase_paths VAR OUT_DIR ROOT FILES EXTENSIONS)
+ foreach(file IN LISTS FILES)
+ get_filename_component(file "${file}" ABSOLUTE)
+ file(RELATIVE_PATH file "${ROOT}" "${file}")
+
+ if ("${EXTENSIONS}" STREQUAL "")
+ list(APPEND mirrored_files "${OUT_DIR}/${file}")
+ else()
+ foreach(ext IN LISTS EXTENSIONS)
+ get_filename_component(dir "${file}" DIRECTORY)
+ get_filename_component(name "${file}" NAME_WE)
+ list(APPEND mirrored_files "${OUT_DIR}/${dir}/${name}${ext}")
+ endforeach()
+ endif()
+ endforeach()
+
+ set("${VAR}" "${mirrored_files}" PARENT_SCOPE)
+endfunction(_pw_rebase_paths)
+
# Internal function that invokes protoc through generate_protos.py.
function(_pw_generate_protos
- TARGET LANGUAGE PLUGIN OUTPUT_EXTS INCLUDE_FILE OUT_DIR SOURCES DEPS)
- # Determine the names of the output files.
- foreach(extension IN LISTS OUTPUT_EXTS)
- foreach(source_file IN LISTS SOURCES)
- get_filename_component(dir "${source_file}" DIRECTORY)
- get_filename_component(name "${source_file}" NAME_WE)
- list(APPEND outputs "${OUT_DIR}/${dir}/${name}${extension}")
- endforeach()
- endforeach()
+ TARGET LANGUAGE PLUGIN OUTPUT_EXTS INCLUDE_FILE OUT_DIR SOURCES INPUTS DEPS)
+ # Determine the names of the compiled output files.
+ _pw_rebase_paths(outputs
+ "${OUT_DIR}/${LANGUAGE}" "${OUT_DIR}/sources" "${SOURCES}" "${OUTPUT_EXTS}")
# Export the output files to the caller's scope so it can use them if needed.
set(generated_outputs "${outputs}" PARENT_SCOPE)
@@ -90,14 +139,14 @@
"${script}"
--language "${LANGUAGE}"
--plugin-path "${PLUGIN}"
- --include-path "${CMAKE_CURRENT_SOURCE_DIR}"
--include-file "${INCLUDE_FILE}"
- --out-dir "${OUT_DIR}"
- ${ARGN}
- ${SOURCES}
+ --compile-dir "${OUT_DIR}/sources"
+ --out-dir "${OUT_DIR}/${LANGUAGE}"
+ --sources ${SOURCES}
DEPENDS
- ${SOURCES}
${script}
+ ${SOURCES}
+ ${INPUTS}
${DEPS}
OUTPUT
${outputs}
@@ -106,7 +155,7 @@
endfunction(_pw_generate_protos)
# Internal function that creates a pwpb proto library.
-function(_pw_pwpb_library NAME SOURCES DEPS INCLUDE_FILE OUT_DIR)
+function(_pw_pwpb_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
list(TRANSFORM DEPS APPEND .pwpb)
_pw_generate_protos("${NAME}.generate.pwpb"
@@ -116,18 +165,19 @@
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
+ "${INPUTS}"
"${DEPS}"
)
# Create the library with the generated source files.
add_library("${NAME}.pwpb" INTERFACE)
- target_include_directories("${NAME}.pwpb" INTERFACE "${OUT_DIR}")
+ target_include_directories("${NAME}.pwpb" INTERFACE "${OUT_DIR}/pwpb")
target_link_libraries("${NAME}.pwpb" INTERFACE pw_protobuf ${DEPS})
add_dependencies("${NAME}.pwpb" "${NAME}.generate.pwpb")
endfunction(_pw_pwpb_library)
# Internal function that creates a raw_rpc proto library.
-function(_pw_raw_rpc_library NAME SOURCES DEPS INCLUDE_FILE OUT_DIR)
+function(_pw_raw_rpc_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
list(TRANSFORM DEPS APPEND .raw_rpc)
_pw_generate_protos("${NAME}.generate.raw_rpc"
@@ -137,12 +187,13 @@
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
+ "${INPUTS}"
"${DEPS}"
)
# Create the library with the generated source files.
add_library("${NAME}.raw_rpc" INTERFACE)
- target_include_directories("${NAME}.raw_rpc" INTERFACE "${OUT_DIR}")
+ target_include_directories("${NAME}.raw_rpc" INTERFACE "${OUT_DIR}/raw_rpc")
target_link_libraries("${NAME}.raw_rpc"
INTERFACE
pw_rpc.raw
@@ -153,7 +204,7 @@
endfunction(_pw_raw_rpc_library)
# Internal function that creates a nanopb proto library.
-function(_pw_nanopb_library NAME SOURCES DEPS INCLUDE_FILE OUT_DIR)
+function(_pw_nanopb_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
list(TRANSFORM DEPS APPEND .nanopb)
set(nanopb_dir "$<TARGET_PROPERTY:$<IF:$<TARGET_EXISTS:protobuf-nanopb-static>,protobuf-nanopb-static,pw_build.empty>,SOURCE_DIR>")
@@ -167,18 +218,19 @@
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
+ "${INPUTS}"
"${DEPS}"
)
# Create the library with the generated source files.
add_library("${NAME}.nanopb" EXCLUDE_FROM_ALL ${generated_outputs})
- target_include_directories("${NAME}.nanopb" PUBLIC "${OUT_DIR}")
+ target_include_directories("${NAME}.nanopb" PUBLIC "${OUT_DIR}/nanopb")
target_link_libraries("${NAME}.nanopb" PUBLIC pw_third_party.nanopb ${DEPS})
add_dependencies("${NAME}.nanopb" "${NAME}.generate.nanopb")
endfunction(_pw_nanopb_library)
# Internal function that creates a nanopb_rpc library.
-function(_pw_nanopb_rpc_library NAME SOURCES DEPS INCLUDE_FILE OUT_DIR)
+function(_pw_nanopb_rpc_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
# Determine the names of the output files.
list(TRANSFORM DEPS APPEND .nanopb_rpc)
@@ -189,12 +241,16 @@
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
+ "${INPUTS}"
"${DEPS}"
)
# Create the library with the generated source files.
add_library("${NAME}.nanopb_rpc" INTERFACE)
- target_include_directories("${NAME}.nanopb_rpc" INTERFACE "${OUT_DIR}")
+ target_include_directories("${NAME}.nanopb_rpc"
+ INTERFACE
+ "${OUT_DIR}/nanopb_rpc"
+ )
target_link_libraries("${NAME}.nanopb_rpc"
INTERFACE
"${NAME}.nanopb"