blob: 6287cb645fbf9f485f7544e48ac8155b196d0ad8 [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001#----------------------------------------------------------------------------
Richard Burtonf32a86a2022-11-15 11:46:11 +00002# SPDX-FileCopyrightText: Copyright 2021 Arm Limited and/or its affiliates <open-source-office@arm.com>
alexander3c798932021-03-26 21:42:19 +00003# SPDX-License-Identifier: Apache-2.0
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#----------------------------------------------------------------------------
17set(SCRIPTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/scripts)
18
19##############################################################################
20# This function generates C++ files for images located in the directory it is
21# pointed at. NOTE: uses python
22##############################################################################
23function(generate_images_code input_dir src_out hdr_out img_size)
24
25 # Absolute paths for passing into python script
26 get_filename_component(input_dir_abs ${input_dir} ABSOLUTE)
27 get_filename_component(src_out_abs ${src_out} ABSOLUTE)
28 get_filename_component(hdr_out_abs ${hdr_out} ABSOLUTE)
29
30 message(STATUS "Generating image files from ${input_dir_abs}")
31 execute_process(
32 COMMAND ${PYTHON} ${SCRIPTS_DIR}/py/gen_rgb_cpp.py
33 --image_path ${input_dir_abs}
34 --source_folder_path ${src_out_abs}
35 --header_folder_path ${hdr_out_abs}
36 --image_size ${img_size} ${img_size}
37 RESULT_VARIABLE return_code
38 )
39 if (NOT return_code EQUAL "0")
40 message(FATAL_ERROR "Failed to generate image files.")
41 endif ()
42
43endfunction()
44
45##############################################################################
46# This function generates C++ files for audio files located in the directory it is
47# pointed at. NOTE: uses python
48##############################################################################
49function(generate_audio_code input_dir src_out hdr_out s_rate_opt mono_opt off_opt duration_opt res_type_opt min_sample_opt)
50
51 # Absolute paths for passing into python script
52 get_filename_component(input_dir_abs ${input_dir} ABSOLUTE)
53 get_filename_component(src_out_abs ${src_out} ABSOLUTE)
54 get_filename_component(hdr_out_abs ${hdr_out} ABSOLUTE)
55
56 to_py_bool(mono_opt mono_opt_py)
57
58 message(STATUS "Generating audio files from ${input_dir_abs}")
59 execute_process(
60 COMMAND ${PYTHON} ${SCRIPTS_DIR}/py/gen_audio_cpp.py
61 --audio_path ${input_dir_abs}
62 --source_folder_path ${src_out_abs}
63 --header_folder_path ${hdr_out_abs}
64 --sampling_rate ${s_rate_opt}
65 --mono ${mono_opt_py}
66 --offset ${off_opt}
67 --duration ${duration_opt}
68 --res_type ${res_type_opt}
69 --min_samples ${min_sample_opt}
70 RESULT_VARIABLE return_code
71 )
72 if (NOT return_code EQUAL "0")
73 message(FATAL_ERROR "Failed to generate audio files.")
74 endif ()
75
76endfunction()
77
78##############################################################################
79# This function generates default empty input C++ files for applications with no
80# external input. Main use is for the inference runner. NOTE: uses python
81##############################################################################
82function(generate_default_input_code hdr_out)
83
84 # Absolute paths for passing into python script
85 get_filename_component(hdr_out_abs ${hdr_out} ABSOLUTE)
86
87 message(STATUS "Generating default input files")
88 execute_process(
89 COMMAND ${PYTHON} ${SCRIPTS_DIR}/py/gen_default_input_cpp.py
90 --header_folder_path ${hdr_out_abs}
91 RESULT_VARIABLE return_code
92 )
93 if (NOT return_code EQUAL "0")
94 message(FATAL_ERROR "Failed to generate default input .")
95 endif ()
96
97endfunction()
98##############################################################################
99# This function generates C++ files for tflite NN model files.
100# @param[in] MODEL_PATH path to a tflite file
101# @param[in] DESTINATION directory in which the output cc must be
102# placed
103# @param[in] EXPRESSIONS C++ code expressions to add to the generated file
104# @param[in] NAMESPACE model name space
105# NOTE: Uses python
106##############################################################################
107function(generate_tflite_code)
108
109 set(multiValueArgs EXPRESSIONS NAMESPACE)
110 set(oneValueArgs MODEL_PATH DESTINATION)
111 cmake_parse_arguments(PARSED "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
112
113 # Absolute paths for passing into python script
114 get_filename_component(ABS_MODEL_PATH ${PARSED_MODEL_PATH} ABSOLUTE)
115 get_filename_component(ABS_DESTINATION ${PARSED_DESTINATION} ABSOLUTE)
116
117 if (EXISTS ${ABS_MODEL_PATH})
118 message(STATUS "Using ${ABS_MODEL_PATH}")
119 else ()
120 message(FATAL_ERROR "${ABS_MODEL_PATH} not found!")
121 endif ()
122
123
124 foreach(expression ${PARSED_EXPRESSIONS})
125 set(py_arg_exp ${py_arg_exp} --expression=${expression})
126 endforeach()
127
128 foreach(name ${PARSED_NAMESPACE})
129 set(py_arg_exp ${py_arg_exp} --namespaces=${name})
130 endforeach()
131
132 execute_process(
133 COMMAND ${PYTHON} ${SCRIPTS_DIR}/py/gen_model_cpp.py
134 --tflite_path ${ABS_MODEL_PATH}
135 --output_dir ${ABS_DESTINATION} ${py_arg_exp}
136 RESULT_VARIABLE return_code
137 )
138 if (NOT return_code EQUAL "0")
139 message(FATAL_ERROR "Failed to generate model files.")
140 endif ()
141endfunction()
142
143
144##############################################################################
145# This function generates C++ file for a given labels' text file.
146# @param[in] INPUT Path to the label text file
147# @param[in] DESTINATION_SRC directory in which the output cc must be
148# placed
149# @param[in] DESTINATION_HDR directory in which the output h file must be
150# placed
151# @param[in] OUTPUT_FILENAME Path to required output file
152# @param[in] NAMESPACE data name space
153# NOTE: Uses python
154##############################################################################
155function(generate_labels_code)
156
157 set(multiValueArgs NAMESPACE)
158 set(oneValueArgs INPUT DESTINATION_SRC DESTINATION_HDR OUTPUT_FILENAME)
159 cmake_parse_arguments(PARSED "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
160
161 # Absolute paths for passing into python script
162 get_filename_component(input_abs ${PARSED_INPUT} ABSOLUTE)
163 get_filename_component(src_out_abs ${PARSED_DESTINATION_SRC} ABSOLUTE)
164 get_filename_component(hdr_out_abs ${PARSED_DESTINATION_HDR} ABSOLUTE)
165
166 message(STATUS "Generating labels file from ${PARSED_INPUT}")
167 file(REMOVE "${hdr_out_abs}/${PARSED_OUTPUT_FILENAME}.hpp")
168 file(REMOVE "${src_out_abs}/${PARSED_OUTPUT_FILENAME}.cc")
169
170 foreach(name ${PARSED_NAMESPACE})
171 set(py_arg_exp ${py_arg_exp} --namespaces=${name})
172 endforeach()
173
174 message(STATUS "writing to ${hdr_out_abs}/${PARSED_OUTPUT_FILENAME}.hpp and ${src_out_abs}/${PARSED_OUTPUT_FILENAME}.cc")
175 execute_process(
176 COMMAND ${PYTHON} ${SCRIPTS_DIR}/py/gen_labels_cpp.py
177 --labels_file ${input_abs}
178 --source_folder_path ${src_out_abs}
179 --header_folder_path ${hdr_out_abs}
180 --output_file_name ${PARSED_OUTPUT_FILENAME} ${py_arg_exp}
181 RESULT_VARIABLE return_code
182 )
183 if (NOT return_code EQUAL "0")
184 message(FATAL_ERROR "Failed to generate label files.")
185 endif ()
186endfunction()
187
188
189##############################################################################
190# This function generates C++ data files for test located in the directory it is
191# pointed at.
192# @param[in] INPUT_DIR directory in which are the npy files
193# @param[in] DESTINATION_SRC directory in which the output cc must be
194# placed
195# @param[in] DESTINATION_HDR directory in which the output h file must be
196# placed
alexander3c798932021-03-26 21:42:19 +0000197# @param[in] NAMESPACE data name space
198# NOTE: Uses python
199##############################################################################
200function(generate_test_data_code)
201
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100202 set(multiValueArgs NAMESPACE INPUT_DIR)
203 set(oneValueArgs DESTINATION_SRC DESTINATION_HDR)
alexander3c798932021-03-26 21:42:19 +0000204 cmake_parse_arguments(PARSED "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
205
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100206 list(LENGTH PARSED_INPUT_DIR input_dir_length)
alexander3c798932021-03-26 21:42:19 +0000207
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100208 if (${input_dir_length} GREATER 1)
209 set(add_extra_namespace TRUE)
210 else()
211 set(add_extra_namespace FALSE)
212 endif()
213
214 foreach(input_dir ${PARSED_INPUT_DIR})
215 unset(py_arg_exp)
216 file(GLOB_RECURSE input_data_files
217 "${input_dir}/*.npy"
218 )
219 # no input NPY data found => skip code generation.
220 if(NOT input_data_files)
Kshitij Sisodiab59ba682021-11-23 17:19:52 +0000221 message(WARNING "No files were found to generate input data: ${input_dir}")
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100222 break()
223 endif()
224
225 # Absolute paths for passing into python script
226 get_filename_component(input_dir_abs ${input_dir} ABSOLUTE)
227 get_filename_component(input_dir_name ${input_dir} NAME)
228 get_filename_component(src_out_abs ${PARSED_DESTINATION_SRC} ABSOLUTE)
229 get_filename_component(hdr_out_abs ${PARSED_DESTINATION_HDR} ABSOLUTE)
230
231 foreach(name ${PARSED_NAMESPACE})
232 set(py_arg_exp ${py_arg_exp} --namespaces=${name})
233 endforeach()
234
235 if (${add_extra_namespace})
236 set(py_arg_exp ${py_arg_exp} --namespaces=${input_dir_name})
237 endif()
238
239 message(STATUS "Generating test ifm and ofm files from ${input_dir_abs}")
240 execute_process(
241 COMMAND ${PYTHON} ${SCRIPTS_DIR}/py/gen_test_data_cpp.py
242 --data_folder_path ${input_dir_abs}
243 --source_folder_path ${src_out_abs}
244 --header_folder_path ${hdr_out_abs}
245 --usecase ${input_dir_name}
246 ${py_arg_exp}
247 RESULT_VARIABLE return_code
248 )
249 if (NOT return_code EQUAL "0")
250 message(FATAL_ERROR "Failed to generate test data files.")
251 endif ()
alexander3c798932021-03-26 21:42:19 +0000252 endforeach()
alexander3c798932021-03-26 21:42:19 +0000253endfunction()
254
255
256##############################################################################
257# Function to prepare a python virtual environment for running the functions
258# outlined above.
259##############################################################################
260function(setup_source_generator)
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000261
262 # If a virtual env has been created in the resources_downloaded directory,
263 # use it for source generator. Else, fall back to creating a virtual env
264 # in the current build directory.
265 if (EXISTS ${RESOURCES_DIR}/env)
266 set(DEFAULT_VENV_DIR ${RESOURCES_DIR}/env)
267 else()
268 set(DEFAULT_VENV_DIR ${CMAKE_BINARY_DIR}/venv)
269 endif()
270
alexander3c798932021-03-26 21:42:19 +0000271 if (${CMAKE_HOST_WIN32})
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000272 # Windows Python3 is python.exe
alexander3c798932021-03-26 21:42:19 +0000273 set(PY_EXEC python)
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000274 set(PYTHON ${DEFAULT_VENV_DIR}/Scripts/${PY_EXEC})
alexander3c798932021-03-26 21:42:19 +0000275 else()
276 set(PY_EXEC python3)
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000277 set(PYTHON ${DEFAULT_VENV_DIR}/bin/${PY_EXEC})
alexander3c798932021-03-26 21:42:19 +0000278 endif()
279 set(PYTHON ${PYTHON} PARENT_SCOPE)
Kshitij Sisodiab1904b12022-04-21 09:48:10 +0100280 set(PYTHON_VENV ${DEFAULT_VENV_DIR} PARENT_SCOPE)
alexander3c798932021-03-26 21:42:19 +0000281
282 if (EXISTS ${PYTHON})
283 message(STATUS "Using existing python at ${PYTHON}")
284 return()
285 endif ()
Kshitij Sisodia1da52ae2021-06-25 09:55:14 +0100286
Kshitij Sisodia36b5b132023-06-09 11:58:26 +0100287 # If environment is not found, find the required Python version
288 # and create it.
289 find_package(Python3 3.9
290 COMPONENTS Interpreter
291 REQUIRED)
292
293 if (NOT Python3_FOUND)
294 message(FATAL_ERROR "Required version of Python3 not found!")
295 else()
296 message(STATUS "Python3 (v${Python3_VERSION}) found: ${Python3_EXECUTABLE}")
297 endif()
298
alexander3c798932021-03-26 21:42:19 +0000299 message(STATUS "Configuring python environment at ${PYTHON}")
Kshitij Sisodia1da52ae2021-06-25 09:55:14 +0100300
alexander3c798932021-03-26 21:42:19 +0000301 execute_process(
Kshitij Sisodia36b5b132023-06-09 11:58:26 +0100302 COMMAND ${Python3_EXECUTABLE} -m venv ${DEFAULT_VENV_DIR}
alexander3c798932021-03-26 21:42:19 +0000303 RESULT_VARIABLE return_code
304 )
Kshitij Sisodia1da52ae2021-06-25 09:55:14 +0100305 if (NOT return_code STREQUAL "0")
Kshitij Sisodia36b5b132023-06-09 11:58:26 +0100306 message(FATAL_ERROR "Failed to setup Python3 environment. Return code: ${return_code}")
alexander3c798932021-03-26 21:42:19 +0000307 endif ()
308
Kshitij Sisodia1da52ae2021-06-25 09:55:14 +0100309 execute_process(
310 COMMAND ${PYTHON} -m pip install --upgrade pip
311 RESULT_VARIABLE return_code
312 )
313 if (NOT return_code EQUAL "0")
314 message(FATAL_ERROR "Failed to upgrade pip")
315 endif ()
316
317 execute_process(
318 COMMAND ${PYTHON} -m pip install wheel
319 RESULT_VARIABLE return_code
320 )
321 if (NOT return_code EQUAL "0")
322 message(FATAL_ERROR "Failed to install wheel")
323 endif ()
alexander3c798932021-03-26 21:42:19 +0000324
325 execute_process(
326 COMMAND ${PYTHON} -m pip install -r ${SCRIPTS_DIR}/py/requirements.txt
327 RESULT_VARIABLE return_code
328 )
329 if (NOT return_code EQUAL "0")
Kshitij Sisodia1da52ae2021-06-25 09:55:14 +0100330 message(FATAL_ERROR "Failed to install requirements")
alexander3c798932021-03-26 21:42:19 +0000331 endif ()
332endfunction()