third_party.pigweed.src/pw_protobuf_compiler/proto.cmake
Wyatt Hepler d9336a4cad pw_protobuf_compiler: Pass plugin paths
- Rather than relying on Python entry point scripts to get paths to
  protoc plugins, pass the paths to the generate_protos.py script. This
  works in environments where the Python entry points are not available.
- Use unique paths for generated proto code in the GN build. This allows
  multiple GN targets to generate code from the same .proto files. The
  CMake build already worked like this.
- Cleanup and reduce code duplication in the CMake and GN proto
  generation code.
- Support Windows builds: generate .bat wrapper script for plugins, fix
  compilation issue that affects some older compilers.

Change-Id: Iab27a3d193d6008567b324dc1c4e5f540894b8ff
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/24380
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Reviewed-by: Zoltan Szatmary-Ban <szatmz@google.com>
2020-11-12 17:28:22 +00:00

208 lines
7.2 KiB
CMake

# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
include_guard(GLOBAL)
# Declares a protocol buffers library. This function creates a library for each
# supported protocol buffer implementation:
#
# ${NAME}.pwpb - pw_protobuf generated code
# ${NAME}.nanopb - Nanopb generated code (requires Nanopb)
#
# This function also creates libraries for generating pw_rpc code:
#
# ${NAME}.nanopb_rpc - generates Nanopb pw_rpc code
# ${NAME}.raw_rpc - generates raw pw_rpc (no protobuf library) code
# ${NAME}.pwpb_rpc - (Not implemented) generates pw_protobuf pw_rpc code
#
# Args:
#
# NAME - the base name of the libraries to create
# SOURCES - .proto source files
# DEPS - dependencies on other pw_proto_library targets
#
function(pw_proto_library NAME)
cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "SOURCES;DEPS")
set(out_dir "${CMAKE_CURRENT_BINARY_DIR}/protos")
# Use INTERFACE libraries to track the proto include paths that are passed to
# protoc.
set(include_deps "${arg_DEPS}")
list(TRANSFORM include_deps APPEND ._includes)
add_library("${NAME}._includes" INTERFACE)
target_include_directories("${NAME}._includes" INTERFACE ".")
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")
file(GENERATE OUTPUT "${include_file}"
CONTENT
"$<TARGET_PROPERTY:${NAME}._includes,INTERFACE_INCLUDE_DIRECTORIES>")
# Create a protobuf target for each supported protobuf library.
_pw_pwpb_library(
"${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
_pw_raw_rpc_library(
"${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
_pw_nanopb_library(
"${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
_pw_nanopb_rpc_library(
"${NAME}" "${arg_SOURCES}" "${arg_DEPS}" "${include_file}" "${out_dir}")
endfunction(pw_proto_library)
# 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()
# Export the output files to the caller's scope so it can use them if needed.
set(generated_outputs "${outputs}" PARENT_SCOPE)
if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
get_filename_component(dir "${source_file}" DIRECTORY)
get_filename_component(name "${source_file}" NAME_WE)
set(PLUGIN "${dir}/${name}.bat")
endif()
set(script "$ENV{PW_ROOT}/pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py")
add_custom_command(
COMMAND
python
"${script}"
--language "${LANGUAGE}"
--plugin-path "${PLUGIN}"
--module-path "${CMAKE_CURRENT_SOURCE_DIR}"
--include-file "${INCLUDE_FILE}"
--out-dir "${OUT_DIR}"
${ARGN}
${SOURCES}
DEPENDS
${SOURCES}
${script}
${DEPS}
OUTPUT
${outputs}
)
add_custom_target("${TARGET}" DEPENDS ${outputs})
endfunction(_pw_generate_protos)
# Internal function that creates a pwpb proto library.
function(_pw_pwpb_library NAME SOURCES DEPS INCLUDE_FILE OUT_DIR)
list(TRANSFORM DEPS APPEND .pwpb)
_pw_generate_protos("${NAME}.generate.pwpb"
pwpb
"$ENV{PW_ROOT}/pw_protobuf/py/pw_protobuf/plugin.py"
".pwpb.h"
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
"${DEPS}"
)
# Create the library with the generated source files.
add_library("${NAME}.pwpb" INTERFACE)
target_include_directories("${NAME}.pwpb" INTERFACE "${OUT_DIR}")
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)
list(TRANSFORM DEPS APPEND .raw_rpc)
_pw_generate_protos("${NAME}.generate.raw_rpc"
raw_rpc
"$ENV{PW_ROOT}/pw_rpc/py/pw_rpc/plugin_raw.py"
".raw_rpc.pb.h"
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
"${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_link_libraries("${NAME}.raw_rpc"
INTERFACE
pw_rpc.raw
pw_rpc.server
${DEPS}
)
add_dependencies("${NAME}.raw_rpc" "${NAME}.generate.raw_rpc")
endfunction(_pw_raw_rpc_library)
# Internal function that creates a nanopb proto library.
function(_pw_nanopb_library NAME SOURCES 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>")
set(nanopb_plugin
"$<IF:$<TARGET_EXISTS:protobuf-nanopb-static>,${nanopb_dir}/generator/protoc-gen-nanopb,COULD_NOT_FIND_protobuf-nanopb-static_TARGET_PLEASE_SET_UP_NANOPB>")
_pw_generate_protos("${NAME}.generate.nanopb"
nanopb
"${nanopb_plugin}"
".pb.h;.pb.c"
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
"${DEPS}"
--include-paths "${nanopb_dir}/generator/proto"
)
# 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_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)
# Determine the names of the output files.
list(TRANSFORM DEPS APPEND .nanopb_rpc)
_pw_generate_protos("${NAME}.generate.nanopb_rpc"
nanopb_rpc
"$ENV{PW_ROOT}/pw_rpc/py/pw_rpc/plugin_nanopb.py"
".rpc.pb.h"
"${INCLUDE_FILE}"
"${OUT_DIR}"
"${SOURCES}"
"${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_link_libraries("${NAME}.nanopb_rpc"
INTERFACE
"${NAME}.nanopb"
pw_rpc.nanopb.method_union
pw_rpc.server
${DEPS}
)
add_dependencies("${NAME}.nanopb_rpc" "${NAME}.generate.nanopb_rpc")
endfunction(_pw_nanopb_rpc_library)