blob: bd8584e4b6a0d8e48239eeb8be36b36739573ebc [file] [log] [blame]
# 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)