blob: 62f6eaf171711db4358d3c12453b7c1d0d087274 [file] [log] [blame]
Wyatt Heplerc9e51d22020-10-29 09:12:37 -07001# Copyright 2020 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14include_guard(GLOBAL)
15
16# Declares a protocol buffers library. This function creates a library for each
17# supported protocol buffer implementation:
18#
19# ${NAME}.pwpb - pw_protobuf generated code
20# ${NAME}.nanopb - Nanopb generated code (requires Nanopb)
21#
22# This function also creates libraries for generating pw_rpc code:
23#
24# ${NAME}.nanopb_rpc - generates Nanopb pw_rpc code
25# ${NAME}.raw_rpc - generates raw pw_rpc (no protobuf library) code
26# ${NAME}.pwpb_rpc - (Not implemented) generates pw_protobuf pw_rpc code
27#
28# Args:
29#
30# NAME - the base name of the libraries to create
31# SOURCES - .proto source files
32# DEPS - dependencies on other pw_proto_library targets
Wyatt Hepler752d7d32021-03-02 09:02:23 -080033# PREFIX - prefix add to the proto files
34# STRIP_PREFIX - prefix to remove from the proto files
35# INPUTS - files to include along with the .proto files (such as Nanopb
Wyatt Heplerbcaf8832021-05-25 11:20:04 -070036# .options files)
Wyatt Heplerc9e51d22020-10-29 09:12:37 -070037#
38function(pw_proto_library NAME)
Wyatt Hepler752d7d32021-03-02 09:02:23 -080039 cmake_parse_arguments(PARSE_ARGV 1 arg "" "STRIP_PREFIX;PREFIX"
40 "SOURCES;INPUTS;DEPS")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -070041
Wyatt Hepler1573b822021-03-11 17:32:26 -080042 if("${arg_SOURCES}" STREQUAL "")
43 message(FATAL_ERROR
44 "pw_proto_library requires at least one .proto file in SOURCES. No "
45 "SOURCES were listed for ${NAME}.")
46 endif()
47
Wyatt Hepler752d7d32021-03-02 09:02:23 -080048 set(out_dir "${CMAKE_CURRENT_BINARY_DIR}/${NAME}")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -070049
50 # Use INTERFACE libraries to track the proto include paths that are passed to
51 # protoc.
52 set(include_deps "${arg_DEPS}")
53 list(TRANSFORM include_deps APPEND ._includes)
54
55 add_library("${NAME}._includes" INTERFACE)
Wyatt Hepler1035aa02021-04-12 14:32:36 -070056 target_include_directories("${NAME}._includes" INTERFACE "${out_dir}/sources")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -070057 target_link_libraries("${NAME}._includes" INTERFACE ${include_deps})
58
Wyatt Hepler1035aa02021-04-12 14:32:36 -070059 # Generate a file with all include paths needed by protoc. Use the include
60 # directory paths and replace ; with \n.
Wyatt Hepler752d7d32021-03-02 09:02:23 -080061 set(include_file "${out_dir}/include_paths.txt")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -070062 file(GENERATE OUTPUT "${include_file}"
63 CONTENT
Wyatt Hepler1035aa02021-04-12 14:32:36 -070064 "$<JOIN:$<TARGET_PROPERTY:${NAME}._includes,INTERFACE_INCLUDE_DIRECTORIES>,\n>")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -070065
Wyatt Hepler752d7d32021-03-02 09:02:23 -080066 if("${arg_STRIP_PREFIX}" STREQUAL "")
67 set(arg_STRIP_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}")
68 endif()
69
70 foreach(path IN LISTS arg_SOURCES arg_INPUTS)
71 get_filename_component(abspath "${path}" ABSOLUTE)
72 list(APPEND files_to_mirror "${abspath}")
73 endforeach()
74
75 # Mirror the sources to the output directory with the specified prefix.
76 _pw_rebase_paths(
77 sources "${out_dir}/sources/${arg_PREFIX}" "${arg_STRIP_PREFIX}" "${arg_SOURCES}" "")
78 _pw_rebase_paths(
79 inputs "${out_dir}/sources/${arg_PREFIX}" "${arg_STRIP_PREFIX}" "${arg_INPUTS}" "")
80
81 add_custom_command(
82 COMMAND
Wyatt Hepler8f357f42021-03-17 15:37:09 -070083 python3
Wyatt Hepler752d7d32021-03-02 09:02:23 -080084 "$ENV{PW_ROOT}/pw_build/py/pw_build/mirror_tree.py"
85 --source-root "${arg_STRIP_PREFIX}"
86 --directory "${out_dir}/sources/${arg_PREFIX}"
87 ${files_to_mirror}
88 DEPENDS
89 "$ENV{PW_ROOT}/pw_build/py/pw_build/mirror_tree.py"
90 ${files_to_mirror}
Wyatt Hepler752d7d32021-03-02 09:02:23 -080091 OUTPUT
92 ${sources} ${inputs}
93 )
Wyatt Hepler1035aa02021-04-12 14:32:36 -070094 add_custom_target("${NAME}._sources" DEPENDS ${sources} ${inputs})
95
96 set(sources_deps "${arg_DEPS}")
97 list(TRANSFORM sources_deps APPEND ._sources)
98
99 if(sources_deps)
100 add_dependencies("${NAME}._sources" ${sources_deps})
101 endif()
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800102
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700103 # Create a protobuf target for each supported protobuf library.
104 _pw_pwpb_library(
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800105 "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700106 _pw_raw_rpc_library(
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800107 "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700108 _pw_nanopb_library(
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800109 "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700110 _pw_nanopb_rpc_library(
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800111 "${NAME}" "${sources}" "${inputs}" "${arg_DEPS}" "${include_file}" "${out_dir}")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700112endfunction(pw_proto_library)
113
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800114function(_pw_rebase_paths VAR OUT_DIR ROOT FILES EXTENSIONS)
115 foreach(file IN LISTS FILES)
116 get_filename_component(file "${file}" ABSOLUTE)
117 file(RELATIVE_PATH file "${ROOT}" "${file}")
118
119 if ("${EXTENSIONS}" STREQUAL "")
120 list(APPEND mirrored_files "${OUT_DIR}/${file}")
121 else()
122 foreach(ext IN LISTS EXTENSIONS)
123 get_filename_component(dir "${file}" DIRECTORY)
124 get_filename_component(name "${file}" NAME_WE)
125 list(APPEND mirrored_files "${OUT_DIR}/${dir}/${name}${ext}")
126 endforeach()
127 endif()
128 endforeach()
129
130 set("${VAR}" "${mirrored_files}" PARENT_SCOPE)
131endfunction(_pw_rebase_paths)
132
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700133# Internal function that invokes protoc through generate_protos.py.
134function(_pw_generate_protos
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800135 TARGET LANGUAGE PLUGIN OUTPUT_EXTS INCLUDE_FILE OUT_DIR SOURCES INPUTS DEPS)
136 # Determine the names of the compiled output files.
137 _pw_rebase_paths(outputs
138 "${OUT_DIR}/${LANGUAGE}" "${OUT_DIR}/sources" "${SOURCES}" "${OUTPUT_EXTS}")
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800139
140 # Export the output files to the caller's scope so it can use them if needed.
141 set(generated_outputs "${outputs}" PARENT_SCOPE)
142
143 if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
144 get_filename_component(dir "${source_file}" DIRECTORY)
145 get_filename_component(name "${source_file}" NAME_WE)
146 set(PLUGIN "${dir}/${name}.bat")
147 endif()
148
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700149 set(script "$ENV{PW_ROOT}/pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py")
150 add_custom_command(
151 COMMAND
Wyatt Hepler8f357f42021-03-17 15:37:09 -0700152 python3
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700153 "${script}"
154 --language "${LANGUAGE}"
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800155 --plugin-path "${PLUGIN}"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700156 --include-file "${INCLUDE_FILE}"
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800157 --compile-dir "${OUT_DIR}/sources"
158 --out-dir "${OUT_DIR}/${LANGUAGE}"
159 --sources ${SOURCES}
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700160 DEPENDS
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700161 ${script}
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800162 ${SOURCES}
163 ${INPUTS}
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700164 ${DEPS}
165 OUTPUT
166 ${outputs}
167 )
Wyatt Heplerde26e482021-05-27 15:41:24 -0700168 add_custom_target("${TARGET}._generate.${LANGUAGE}" DEPENDS ${outputs})
169 add_dependencies("${TARGET}._generate.${LANGUAGE}" "${TARGET}._sources")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700170endfunction(_pw_generate_protos)
171
172# Internal function that creates a pwpb proto library.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800173function(_pw_pwpb_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700174 list(TRANSFORM DEPS APPEND .pwpb)
175
Wyatt Heplerde26e482021-05-27 15:41:24 -0700176 _pw_generate_protos("${NAME}"
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800177 pwpb
178 "$ENV{PW_ROOT}/pw_protobuf/py/pw_protobuf/plugin.py"
179 ".pwpb.h"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700180 "${INCLUDE_FILE}"
181 "${OUT_DIR}"
182 "${SOURCES}"
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800183 "${INPUTS}"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700184 "${DEPS}"
185 )
186
187 # Create the library with the generated source files.
188 add_library("${NAME}.pwpb" INTERFACE)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800189 target_include_directories("${NAME}.pwpb" INTERFACE "${OUT_DIR}/pwpb")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700190 target_link_libraries("${NAME}.pwpb" INTERFACE pw_protobuf ${DEPS})
Wyatt Hepler1035aa02021-04-12 14:32:36 -0700191 add_dependencies("${NAME}.pwpb" "${NAME}._generate.pwpb")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700192endfunction(_pw_pwpb_library)
193
194# Internal function that creates a raw_rpc proto library.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800195function(_pw_raw_rpc_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700196 list(TRANSFORM DEPS APPEND .raw_rpc)
197
Wyatt Heplerde26e482021-05-27 15:41:24 -0700198 _pw_generate_protos("${NAME}"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700199 raw_rpc
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800200 "$ENV{PW_ROOT}/pw_rpc/py/pw_rpc/plugin_raw.py"
201 ".raw_rpc.pb.h"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700202 "${INCLUDE_FILE}"
203 "${OUT_DIR}"
204 "${SOURCES}"
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800205 "${INPUTS}"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700206 "${DEPS}"
207 )
208
209 # Create the library with the generated source files.
210 add_library("${NAME}.raw_rpc" INTERFACE)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800211 target_include_directories("${NAME}.raw_rpc" INTERFACE "${OUT_DIR}/raw_rpc")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700212 target_link_libraries("${NAME}.raw_rpc"
213 INTERFACE
214 pw_rpc.raw
215 pw_rpc.server
216 ${DEPS}
217 )
Wyatt Hepler1035aa02021-04-12 14:32:36 -0700218 add_dependencies("${NAME}.raw_rpc" "${NAME}._generate.raw_rpc")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700219endfunction(_pw_raw_rpc_library)
220
221# Internal function that creates a nanopb proto library.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800222function(_pw_nanopb_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700223 list(TRANSFORM DEPS APPEND .nanopb)
224
Wyatt Hepler8f357f42021-03-17 15:37:09 -0700225 if("${dir_pw_third_party_nanopb}" STREQUAL "")
Wyatt Hepler1035aa02021-04-12 14:32:36 -0700226 add_custom_target("${NAME}._generate.nanopb"
Wyatt Heplerb59d2c92021-05-11 11:20:43 -0700227 "${CMAKE_COMMAND}" -E echo
Wyatt Hepler8f357f42021-03-17 15:37:09 -0700228 ERROR: Attempting to use pw_proto_library, but
229 dir_pw_third_party_nanopb is not set. Set dir_pw_third_party_nanopb
230 to the path to the Nanopb repository.
231 COMMAND
Wyatt Heplerb59d2c92021-05-11 11:20:43 -0700232 "${CMAKE_COMMAND}" -E false
Wyatt Hepler8f357f42021-03-17 15:37:09 -0700233 DEPENDS
234 ${DEPS}
235 SOURCES
236 ${SOURCES}
237 )
238 set(generated_outputs $<TARGET_PROPERTY:pw_build.empty,SOURCES>)
239 else()
Wyatt Heplerbcaf8832021-05-25 11:20:04 -0700240 # When compiling with the Nanopb plugin, the nanopb.proto file is already
241 # compiled internally, so skip recompiling it with protoc.
242 if("${SOURCES}" MATCHES "nanopb\\.proto")
243 add_custom_target("${NAME}._generate.nanopb") # Nothing to do
244 add_library("${NAME}.nanopb" INTERFACE)
Wyatt Heplerde26e482021-05-27 15:41:24 -0700245 target_link_libraries("${NAME}.nanopb"
246 INTERFACE
247 pw_third_party.nanopb
248 ${DEPS}
249 )
Wyatt Heplerbcaf8832021-05-25 11:20:04 -0700250 else()
Wyatt Heplerde26e482021-05-27 15:41:24 -0700251 _pw_generate_protos("${NAME}"
Wyatt Heplerbcaf8832021-05-25 11:20:04 -0700252 nanopb
253 "${dir_pw_third_party_nanopb}/generator/protoc-gen-nanopb"
254 ".pb.h;.pb.c"
255 "${INCLUDE_FILE}"
256 "${OUT_DIR}"
257 "${SOURCES}"
258 "${INPUTS}"
259 "${DEPS}"
260 )
261
262 # Create the library with the generated source files.
263 add_library("${NAME}.nanopb" EXCLUDE_FROM_ALL ${generated_outputs})
264 target_include_directories("${NAME}.nanopb" PUBLIC "${OUT_DIR}/nanopb")
265 target_link_libraries("${NAME}.nanopb" PUBLIC pw_third_party.nanopb ${DEPS})
266 endif()
267
268 add_dependencies("${NAME}.nanopb" "${NAME}._generate.nanopb")
Wyatt Heplera3ca62a2021-05-04 16:21:43 -0700269
270 # Ensure that nanopb_pb2.py is generated to avoid race conditions.
271 add_dependencies("${NAME}._generate.nanopb"
272 pw_third_party.nanopb.generate_proto
273 )
Wyatt Hepler8f357f42021-03-17 15:37:09 -0700274 endif()
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700275endfunction(_pw_nanopb_library)
276
277# Internal function that creates a nanopb_rpc library.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800278function(_pw_nanopb_rpc_library NAME SOURCES INPUTS DEPS INCLUDE_FILE OUT_DIR)
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700279 # Determine the names of the output files.
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700280 list(TRANSFORM DEPS APPEND .nanopb_rpc)
281
Wyatt Heplerde26e482021-05-27 15:41:24 -0700282 _pw_generate_protos("${NAME}"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700283 nanopb_rpc
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800284 "$ENV{PW_ROOT}/pw_rpc/py/pw_rpc/plugin_nanopb.py"
285 ".rpc.pb.h"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700286 "${INCLUDE_FILE}"
287 "${OUT_DIR}"
288 "${SOURCES}"
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800289 "${INPUTS}"
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700290 "${DEPS}"
291 )
292
293 # Create the library with the generated source files.
294 add_library("${NAME}.nanopb_rpc" INTERFACE)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800295 target_include_directories("${NAME}.nanopb_rpc"
296 INTERFACE
297 "${OUT_DIR}/nanopb_rpc"
298 )
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700299 target_link_libraries("${NAME}.nanopb_rpc"
300 INTERFACE
301 "${NAME}.nanopb"
Alexei Frolovbebba902021-06-09 17:03:52 -0700302 pw_rpc.nanopb.client
Wyatt Heplerdcfa92b2020-11-10 09:47:30 -0800303 pw_rpc.nanopb.method_union
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700304 pw_rpc.server
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700305 ${DEPS}
306 )
Wyatt Hepler1035aa02021-04-12 14:32:36 -0700307 add_dependencies("${NAME}.nanopb_rpc" "${NAME}._generate.nanopb_rpc")
Wyatt Heplerc9e51d22020-10-29 09:12:37 -0700308endfunction(_pw_nanopb_rpc_library)