blob: d196538cbe503c1618944cdd6163d90f847df10d [file] [log] [blame]
Julian Halldf86fce2020-11-23 18:09:55 +01001#-------------------------------------------------------------------------------
Imre Kisa465cf42024-04-11 14:30:31 +02002# Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
Julian Halldf86fce2020-11-23 18:09:55 +01003#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#-------------------------------------------------------------------------------
7
8#[===[.rst:
Gyorgy Szing2247d242021-09-03 16:17:25 +02009NanoPB integration for cmake
Julian Halldf86fce2020-11-23 18:09:55 +010010----------------------------
11
12This module will:
Ross Burton39a5bc72023-09-29 16:21:26 +010013 - use LazyFetch to download nanopb and build the static library and the generator.
14 Usual LazyFetch configuration to use prefetched source or prebuilt binaries apply.
15 - run find_module() to import the static library
16 - run find_executable() import the generator to the build (extend PYTHONPATH) and
17 define a cmake function to provide access to the generator to build nanopb files.
Julian Halldf86fce2020-11-23 18:09:55 +010018
Ross Burton39a5bc72023-09-29 16:21:26 +010019Note: see requirements.txt for dependencies which need to be installed in the build
20environment to use this module.
Julian Halldf86fce2020-11-23 18:09:55 +010021
22#]===]
23
24#### Get the dependency
25
Gyorgy Szing96669942021-12-08 04:19:50 +010026set(NANOPB_URL "https://github.com/nanopb/nanopb.git"
27 CACHE STRING "nanopb repository URL")
Ross Burton39a5bc72023-09-29 16:21:26 +010028set(NANOPB_REFSPEC "nanopb-0.4.8"
Gyorgy Szing96669942021-12-08 04:19:50 +010029 CACHE STRING "nanopb git refspec")
30set(NANOPB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/nanopb-src"
31 CACHE PATH "nanopb source-code")
32set(NANOPB_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/nanopb_install"
33 CACHE PATH "nanopb installation directory")
Gyorgy Szing34aaf212022-10-20 07:26:23 +020034set(NANOPB_BUILD_TYPE "Release"
35 CACHE STRING "nanopb build type")
Julian Halldf86fce2020-11-23 18:09:55 +010036
37# Checking git
38find_program(GIT_COMMAND "git")
39if (NOT GIT_COMMAND)
40 message(FATAL_ERROR "Please install git")
41endif()
42
Gyorgy Szing96669942021-12-08 04:19:50 +010043set(GIT_OPTIONS
Julian Halldf86fce2020-11-23 18:09:55 +010044 GIT_REPOSITORY ${NANOPB_URL}
45 GIT_TAG ${NANOPB_REFSPEC}
Julian Halla628af32022-04-01 10:08:18 +010046 GIT_SHALLOW FALSE
Imre Kisa465cf42024-04-11 14:30:31 +020047 #See the .patch file for details on why it is needed.
48 PATCH_COMMAND git stash
49 COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/0001-Fix-race-condition-in-directory-creation.patch
Gyorgy Szing96669942021-12-08 04:19:50 +010050 )
Julian Halldf86fce2020-11-23 18:09:55 +010051
Gyorgy Szinga7e762b2022-03-05 00:33:57 +000052# Only pass libc settings to nanopb if needed. For environments where the standard
53# library is not overridden, this is not needed.
54if(TARGET stdlib::c)
55 include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
56
57 # Save libc settings
58 save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
59 # Translate libc settings to cmake code fragment. Will be inserted into
60 # nanopb-init-cache.cmake.in when LazyFetch configures the file.
61 translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
62 unset_saved_properties(LIBC)
63endif()
Andrew Beggs97a00d42021-06-15 15:45:46 +000064
Ross Burton39a5bc72023-09-29 16:21:26 +010065# Nanopb build depends on python. Discover python here and pass the result to
66# nanopb build through the initial cache file.
67find_package(Python3 REQUIRED COMPONENTS Interpreter)
68
69# Use LazyFetch to manage the external dependency.
Gyorgy Szing96669942021-12-08 04:19:50 +010070include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
71LazyFetch_MakeAvailable(DEP_NAME nanopb
72 FETCH_OPTIONS ${GIT_OPTIONS}
73 INSTALL_DIR ${NANOPB_INSTALL_DIR}
74 PACKAGE_DIR ${NANOPB_INSTALL_DIR}
75 CACHE_FILE "${TS_ROOT}/external/nanopb/nanopb-init-cache.cmake.in"
76 SOURCE_DIR "${NANOPB_SOURCE_DIR}"
77 )
Gyorgy Szinga7e762b2022-03-05 00:33:57 +000078unset(_cmake_fragment)
Julian Halldf86fce2020-11-23 18:09:55 +010079
Gyorgy Szing28bca0b2023-02-15 11:17:07 +010080if(TARGET stdlib::c)
81 target_link_libraries(nanopb::protobuf-nanopb-static INTERFACE stdlib::c)
82endif()
Julian Halldf86fce2020-11-23 18:09:55 +010083
84#### Build access to the protobuf compiler
Ross Burton39a5bc72023-09-29 16:21:26 +010085find_program(NANOPB_GENERATOR_PATH
Julian Halldf86fce2020-11-23 18:09:55 +010086 NAMES nanopb_generator.py
Ross Burton39a5bc72023-09-29 16:21:26 +010087 HINTS ${NANOPB_INSTALL_DIR}/bin ${NANOPB_INSTALL_DIR}/sbin
Julian Halldf86fce2020-11-23 18:09:55 +010088 DOC "nanopb protobuf compiler"
89 NO_DEFAULT_PATH
90 )
91
92if (NOT NANOPB_GENERATOR_PATH)
93 message(FATAL_ERROR "Nanopb generator was not found!")
94endif()
95
96#[===[.rst:
97.. cmake:command:: protobuf_generate
98
99 .. code-block:: cmake
100
101 protobuf_generate(SRC file.proto
102 TGT foo
103 NAMESPACE bar
104 BASE_DIR "proto/definitions")
105
106 Run the ``nanopb_generator`` to compile a protobuf definition file into C source.
107 Generated source file will be added to the source list of ``TGT``. Protobuf
108 compilation will take part before TGT+NAMESPACE is built.
109
110 Protobuf file names added to the same TGT must not collide.
111
112 Inputs:
113
114 ``SRC``
Gyorgy Szing2247d242021-09-03 16:17:25 +0200115 Path to of the protobuf file to process. Either absolute or relative to the
Julian Halldf86fce2020-11-23 18:09:55 +0100116 callers location.
117
118 ``TGT``
119 Name of target to compile generated source files.
120
121 ``NAMESPACE``
122 Namespace to put generated files under. Specifies include path and allows
123 separating colliding protobuf files.
124
125 ``BASE_DIR``
Gyorgy Szing2247d242021-09-03 16:17:25 +0200126 Base directory. Generated files are located relative to this base.
Julian Halldf86fce2020-11-23 18:09:55 +0100127
128#]===]
129function(protobuf_generate)
130 set(_options )
131 set(_oneValueArgs SRC TGT NAMESPACE BASE_DIR)
132 set(_multiValueArgs )
133
134 cmake_parse_arguments(PARAMS "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
135
136 #Verify mandatory parameters
137 if (NOT DEFINED PARAMS_SRC)
138 message(FATAL_ERROR "nanopb_generate(): mandatory parameter SRC missing.")
139 endif()
140 if (NOT DEFINED PARAMS_TGT)
141 message(FATAL_ERROR "nanopb_generate(): mandatory parameter TGT missing.")
142 endif()
143 if (NOT DEFINED PARAMS_NAMESPACE)
144 message(FATAL_ERROR "nanopb_generate(): mandatory parameter NAMESPACE missing.")
145 endif()
146 if (NOT DEFINED PARAMS_BASE_DIR)
147 message(FATAL_ERROR "nanopb_generate(): mandatory parameter BASE_DIR missing.")
148 endif()
149
Gyorgy Szing2247d242021-09-03 16:17:25 +0200150 #If SRC is not absolute make it relative to the callers location.
Julian Halldf86fce2020-11-23 18:09:55 +0100151 if (NOT IS_ABSOLUTE ${PARAMS_SRC})
152 set(PARAMS_SRC "${CMAKE_CURRENT_LIST_DIR}/${PARAMS_SRC}")
153 endif()
154
155 #Calculate the output directory
156 set(_OUT_DIR_BASE ${CMAKE_BINARY_DIR}/src/${PARAMS_NAMESPACE})
157 #Calculate output file names
158 get_filename_component(_BASENAME ${PARAMS_SRC} NAME_WE)
159
160 #Get relative path or SRC to BASE_DIR
161 file(RELATIVE_PATH _SRC_REL ${PARAMS_BASE_DIR} ${PARAMS_SRC})
162 get_filename_component(_OUT_DIR_REL ${_SRC_REL} DIRECTORY )
163
164 #Calculate output file paths
165 set(_OUT_C "${_OUT_DIR_BASE}/${_OUT_DIR_REL}/${_BASENAME}.pb.c")
166 set(_OUT_H "${_OUT_DIR_BASE}/${_OUT_DIR_REL}/${_BASENAME}.pb.h")
167
168 #some helper variables for the purpose of readability
169 set(_nanopb_target "nanopb_generate_${PARAMS_TGT}_${PARAMS_NAMESPACE}")
170 set(_nanopb_fake_file "nanopb_generate_ff_${PARAMS_TGT}")
171
172 if (NOT TARGET "${_nanopb_target}")
Gyorgy Szingcd3241a2021-06-30 22:41:11 +0000173 #Tell cmake the dependency (source) file is fake.
174 set_source_files_properties("${_nanopb_fake_file}" PROPERTIES SYMBOLIC "true")
Julian Halldf86fce2020-11-23 18:09:55 +0100175 #Create a custom target which depends on a "fake" file.
176 add_custom_target("${_nanopb_target}"
177 DEPENDS "${_nanopb_fake_file}")
Gyorgy Szing2247d242021-09-03 16:17:25 +0200178 #Add a custom command to the target to create output directory.
Julian Halldf86fce2020-11-23 18:09:55 +0100179 add_custom_command(OUTPUT "${_nanopb_fake_file}"
Ross Burton39a5bc72023-09-29 16:21:26 +0100180 COMMAND ${CMAKE_COMMAND} -E make_directory ${_OUT_DIR_BASE}/${_OUT_DIR_REL}
Julian Halldf86fce2020-11-23 18:09:55 +0100181 COMMENT "Generating source from protobuf definitions for target ${PARAMS_TGT}")
182 #Ensure protobuf build happens before test target.
183 add_dependencies(${PARAMS_TGT} ${_nanopb_target})
184 #Add include path to protobuf output.
185 target_include_directories(${PARAMS_TGT} PRIVATE ${_OUT_DIR_BASE})
186 endif()
187
188 #Append a protobuf generator command to the nanopb_generate target.
Gyorgy Szingcd3241a2021-06-30 22:41:11 +0000189 add_custom_command(OUTPUT "${_OUT_C}" "${_OUT_H}"
Gyorgy Szing0358e082022-05-10 09:09:37 +0200190 COMMAND
Ross Burton39a5bc72023-09-29 16:21:26 +0100191 ${CMAKE_COMMAND} -E env PYTHONPATH=${NANOPB_INSTALL_DIR}/lib/python
Gyorgy Szing0358e082022-05-10 09:09:37 +0200192 ${Python3_EXECUTABLE} ${NANOPB_GENERATOR_PATH}
Julian Halldf86fce2020-11-23 18:09:55 +0100193 -I ${PARAMS_BASE_DIR}
194 -D ${_OUT_DIR_BASE}
195 ${_SRC_REL}
196 DEPENDS "${PARAMS_SRC}")
197
198 #Add generated file to the target
199 set_property(SOURCE "${_OUT_C}" PROPERTY GENERATED TRUE)
200 target_sources(${PARAMS_TGT} PRIVATE "${_OUT_C}")
201endfunction()
202
203#[===[.rst:
204.. cmake:command:: protobuf_generate_all
205
206 .. code-block:: cmake
207
208 protobuf_generate_all(TGT foo
209 NAMESPACE bar
210 BASE_DIR "proto/definitions")
211
212 Generates C code from all .proto files listed in the target
213 property PROTOBUF_FILES.
214
215 Inputs:
216
217 ``TGT``
218 Name of target to compile generated source files.
219
220 ``NAMESPACE``
221 Namespace to put generated files under. Specifies include path and allows
222 separating colliding protobuf files.
223
224 ``BASE_DIR``
Gyorgy Szing2247d242021-09-03 16:17:25 +0200225 Base directory. Generated files are located relative to this base.
Julian Halldf86fce2020-11-23 18:09:55 +0100226
227#]===]
228function(protobuf_generate_all)
229 set(_options )
230 set(_oneValueArgs TGT NAMESPACE BASE_DIR)
231 set(_multiValueArgs )
232
233 cmake_parse_arguments(PARAMS "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
234
235 #Verify mandatory parameters
236 if (NOT DEFINED PARAMS_TGT)
237 message(FATAL_ERROR "nanopb_generate_all(): mandatory parameter TGT missing.")
238 endif()
239 if (NOT DEFINED PARAMS_NAMESPACE)
240 message(FATAL_ERROR "nanopb_generate_all(): mandatory parameter NAMESPACE missing.")
241 endif()
242 if (NOT DEFINED PARAMS_BASE_DIR)
243 message(FATAL_ERROR "nanopb_generate_all(): mandatory parameter BASE_DIR missing.")
244 endif()
245
246 get_property(_protolist TARGET ${PARAMS_TGT} PROPERTY PROTOBUF_FILES)
247
248 #Build of each .proto file
249 foreach(_file IN LISTS _protolist)
250 protobuf_generate(
251 TGT ${PARAMS_TGT}
252 SRC "${_file}"
253 NAMESPACE ${PARAMS_NAMESPACE}
254 BASE_DIR ${PARAMS_BASE_DIR})
255 endforeach()
Gyorgy Szing96669942021-12-08 04:19:50 +0100256endfunction()