1# Copyright (c) 2021-2024 Huawei Device Co., Ltd. 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13 14cmake_minimum_required(VERSION 3.5.2 FATAL_ERROR) 15 16# Generate files based on templates and YAML data provided. 17# Adds targets for every template. Also adds a target for the whole function invocation 18# with name ${data_name}_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files. 19# 20# Mandatory arguments: 21# * DATA -- a list of data sources, YAML files 22# * API -- a list of Ruby scripts that provide data-querying API for templates 23# (Nth script from API should parse Nth YAML file from DATA) 24# * TEMPLATES -- a list of templates to generate files 25# 26# Optional arguments: 27# * SOURCE -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates 28# * DESTINATION -- a directory for output files, default is ${PANDA_BINARY_ROOT} 29# * REQUIRES -- if defined, will require additional Ruby files for template generation 30# * EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies 31# * EXTRA_ARGV -- a list of positional arguments that could be accessed in '.erb' files via ARGV[] 32 33function(panda_gen) 34 set(singlevalues SOURCE DESTINATION TARGET_NAME) 35 set(multivalues DATA API TEMPLATES REQUIRES EXTRA_DEPENDENCIES EXTRA_ARGV) 36 cmake_parse_arguments( 37 GEN_ARG 38 "" 39 "${singlevalues}" 40 "${multivalues}" 41 ${ARGN} 42 ) 43 44 if (NOT DEFINED GEN_ARG_TEMPLATES) 45 message(FATAL_ERROR "`TEMPLATES` were not passed to `panda_gen` function") 46 endif() 47 48 if (NOT DEFINED GEN_ARG_DATA) 49 message(FATAL_ERROR "`DATA` was not passed to `panda_gen` function") 50 endif() 51 52 if (NOT DEFINED GEN_ARG_API) 53 message(FATAL_ERROR "`API` was not passed to `panda_gen` function") 54 endif() 55 56 if (NOT DEFINED GEN_ARG_SOURCE) 57 set(GEN_ARG_SOURCE "${PROJECT_SOURCE_DIR}/templates") 58 endif() 59 60 if (NOT DEFINED GEN_ARG_DESTINATION) 61 set(GEN_ARG_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") 62 endif() 63 64 if (NOT DEFINED GEN_ARG_TARGET_NAME) 65 get_filename_component(DATA_NAME ${GEN_ARG_DATA} NAME_WE) 66 set(GEN_ARG_TARGET_NAME "${DATA_NAME}_gen_${PROJECT_NAME}") 67 endif() 68 69 add_custom_target(${GEN_ARG_TARGET_NAME}) # Umbrella target for all generated files 70 add_dependencies(panda_gen_files ${GEN_ARG_TARGET_NAME}) 71 72 foreach(t ${GEN_ARG_TEMPLATES}) 73 set(TEMPLATE "${GEN_ARG_SOURCE}/${t}") 74 string(REGEX REPLACE "\.erb$" "" NAME ${t}) 75 string(REPLACE "\." "_" TARGET ${NAME}) 76 string(REPLACE "/" "_" TARGET ${TARGET}) 77 set(TARGET ${PROJECT_NAME}_${TARGET}) 78 set(OUTPUT_FILE "${GEN_ARG_DESTINATION}/${NAME}") 79 80 panda_gen_file(DATA ${GEN_ARG_DATA} 81 API ${GEN_ARG_API} 82 TEMPLATE ${TEMPLATE} 83 OUTPUTFILE ${OUTPUT_FILE} 84 REQUIRES ${GEN_ARG_REQUIRES} 85 EXTRA_DEPENDENCIES ${GEN_ARG_EXTRA_DEPENDENCIES} 86 EXTRA_ARGV ${GEN_ARG_EXTRA_ARGV} 87 ) 88 add_custom_target(${TARGET} DEPENDS ${OUTPUT_FILE}) 89 add_dependencies(${GEN_ARG_TARGET_NAME} ${TARGET}) 90 endforeach() 91endfunction() 92 93# Calls `panda_gen` for ISA YAML. 94# Adds targets for every template. Also adds a target for the whole function invocation 95# with name isa_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files. 96# 97# Mandatory arguments: 98# * TEMPLATES -- a list of templates to generate files 99# 100# Optional arguments: 101# * SOURCE -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates 102# * DESTINATION -- a directory for output files, default is ${PANDA_BINARY_ROOT} 103# * REQUIRES -- if defined, will require additional Ruby files for template generation 104# * EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies 105 106function(panda_isa_gen) 107 set(singlevalues SOURCE DESTINATION TARGET_NAME) 108 set(multivalues TEMPLATES REQUIRES EXTRA_DEPENDENCIES) 109 cmake_parse_arguments( 110 ISA_GEN_ARG 111 "" 112 "${singlevalues}" 113 "${multivalues}" 114 ${ARGN} 115 ) 116 set(ISA_DATA "${CMAKE_BINARY_DIR}/isa/isa.yaml") 117 set(ISAPI "${PANDA_ROOT}/isa/isapi.rb") 118 list(APPEND ISA_GEN_ARG_EXTRA_DEPENDENCIES isa_assert) 119 panda_gen(DATA ${ISA_DATA} 120 API ${ISAPI} 121 TEMPLATES ${ISA_GEN_ARG_TEMPLATES} 122 SOURCE ${ISA_GEN_ARG_SOURCE} 123 TARGET_NAME ${ISA_GEN_ARG_TARGET_NAME} 124 DESTINATION ${ISA_GEN_ARG_DESTINATION} 125 REQUIRES ${ISA_GEN_ARG_REQUIRES} 126 EXTRA_DEPENDENCIES ${ISA_GEN_ARG_EXTRA_DEPENDENCIES} 127 ) 128endfunction() 129 130# Generate file for a template and YAML data provided. 131# 132# Mandatory arguments: 133# * DATA -- a list of data sources, YAML files 134# * API -- a list of Ruby scripts that provide data-querying API for templates 135# (Nth script from API should parse Nth YAML file from DATA) 136# * TEMPLATE -- template full name 137# * OUTPUTFILE -- output file full name 138# 139# Optional arguments: 140# * REQUIRES -- if defined, will require additional Ruby files for template generation 141# * EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies 142# * EXTRA_ARGV -- a list of positional arguments that could be accessed in '.erb' files via ARGV[] 143 144function(panda_gen_file) 145 set(singlevalues TEMPLATE OUTPUTFILE) 146 set(multivalues DATA API REQUIRES EXTRA_DEPENDENCIES EXTRA_ARGV) 147 cmake_parse_arguments( 148 ARG 149 "" 150 "${singlevalues}" 151 "${multivalues}" 152 ${ARGN} 153 ) 154 if (NOT DEFINED ARG_TEMPLATE) 155 message(FATAL_ERROR "`TEMPLATE` was not passed to `panda_gen_file` function") 156 endif() 157 if (NOT DEFINED ARG_DATA) 158 message(FATAL_ERROR "`DATA` was not passed to `panda_gen_file` function") 159 endif() 160 if (NOT DEFINED ARG_API) 161 message(FATAL_ERROR "`API` was not passed to `panda_gen_file` function") 162 endif() 163 set(GENERATOR "${PANDA_ROOT}/isa/gen.rb") 164 string(REPLACE ";" "," DATA_STR "${ARG_DATA}") 165 string(REPLACE ";" "," API_STR "${ARG_API}") 166 if(DEFINED ARG_REQUIRES) 167 string(REPLACE ";" "," REQUIRE_STR "${ARG_REQUIRES}") 168 set(REQUIRE_OPTION --require ${REQUIRE_STR}) 169 endif() 170 set(DEPENDS_LIST ${GENERATOR} ${ARG_TEMPLATE} ${ARG_DATA} ${ARG_API}) 171 172 173 add_custom_command(OUTPUT ${ARG_OUTPUTFILE} 174 COMMENT "Generate file for ${ARG_TEMPLATE}" 175 COMMAND ${GENERATOR} ${ARG_EXTRA_ARGV} --template ${ARG_TEMPLATE} --data ${DATA_STR} --api ${API_STR} --output ${ARG_OUTPUTFILE} ${REQUIRE_OPTION} 176 DEPENDS ${DEPENDS_LIST} ${ARG_EXTRA_DEPENDENCIES} 177 ) 178endfunction() 179 180# Create an options header using a YAML file for the target 181# 182# Mandatory arguments: 183# TARGET -- target 184# YAML_FILE -- YAML file 185# GENERATED_HEADER -- generated header 186# 187# Use "#include 'generated/GENERATED_HEADER"' to include the generated header 188 189function(panda_gen_options) 190 # Parsing function arguments 191 set(singlevalues TARGET YAML_FILE GENERATED_HEADER) 192 cmake_parse_arguments(GEN_OPTIONS "" "${singlevalues}" "" ${ARGN}) 193 194 # Generate a options header 195 get_filename_component(YAML_FILE ${GEN_OPTIONS_YAML_FILE} ABSOLUTE) 196 set(GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/panda_gen_options/generated) 197 file(MAKE_DIRECTORY ${GENERATED_DIR}) 198 set(OPTIONS_H ${GENERATED_DIR}/${GEN_OPTIONS_GENERATED_HEADER}) 199 panda_gen_file( 200 DATA ${YAML_FILE} 201 TEMPLATE ${PANDA_ROOT}/templates/options/options.h.erb 202 OUTPUTFILE ${OPTIONS_H} 203 API ${PANDA_ROOT}/templates/common.rb 204 ) 205 206 # Add dependencies for a target 207 panda_target_include_directories(${GEN_OPTIONS_TARGET} PUBLIC ${GENERATED_DIR}/..) 208 add_custom_target(${GEN_OPTIONS_TARGET}_options DEPENDS ${OPTIONS_H}) 209 add_dependencies(${GEN_OPTIONS_TARGET} ${GEN_OPTIONS_TARGET}_options) 210 add_dependencies(panda_gen_files ${GEN_OPTIONS_TARGET}_options) 211endfunction() 212 213function(panda_gen_messages) 214 set(singlevalues TARGET YAML_FILE GENERATED_HEADER) 215 cmake_parse_arguments(ARG "" "${singlevalues}" "" ${ARGN}) 216 217 if(NOT DEFINED ARG_YAML_FILE) 218 set(ARG_YAML_FILE ${CMAKE_CURRENT_SOURCE_DIR}/messages.yaml) 219 endif() 220 221 if(NOT DEFINED ARG_GENERATED_HEADER) 222 set(ARG_GENERATED_HEADER messages.h) 223 endif() 224 225 get_filename_component(YAML_FILE ${ARG_YAML_FILE} ABSOLUTE) 226 227 if(IS_ABSOLUTE ${ARG_GENERATED_HEADER}) 228 get_filename_component(GENERATED_DIR ${ARG_GENERATED_HEADER} DIRECTORY) 229 set(MESSAGES_H ${ARG_GENERATED_HEADER}) 230 else() 231 set(INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/panda_gen_messages) 232 set(GENERATED_DIR ${INCLUDE_DIR}/generated) 233 set(MESSAGES_H ${GENERATED_DIR}/${ARG_GENERATED_HEADER}) 234 endif() 235 236 file(MAKE_DIRECTORY ${GENERATED_DIR}) 237 panda_gen_file( 238 DATA ${YAML_FILE} 239 TEMPLATE ${PANDA_ROOT}/templates/messages/messages.h.erb 240 OUTPUTFILE ${MESSAGES_H} 241 API ${PANDA_ROOT}/templates/messages.rb 242 ) 243 244 # Add dependencies for a target 245 if (NOT DEFINED ARG_TARGET) 246 set(ARG_TARGET messages_gen_${PROJECT_NAME}) 247 add_custom_target(${ARG_TARGET}) 248 endif() 249 250 if (DEFINED INCLUDE_DIR) 251 panda_target_include_directories(${ARG_TARGET} PUBLIC ${INCLUDE_DIR}) 252 endif() 253 add_custom_target(${ARG_TARGET}_messages DEPENDS ${MESSAGES_H}) 254 add_dependencies(${ARG_TARGET} ${ARG_TARGET}_messages) 255 add_dependencies(panda_gen_files ${ARG_TARGET}_messages) 256endfunction() 257 258add_custom_target(plugin_options_gen) 259set_target_properties(plugin_options_gen PROPERTIES PLUGIN_OPTIONS_YAML_FILES "${PANDA_ROOT}/templates/plugin_options.yaml") 260 261add_custom_target(entrypoints_yaml_gen) 262set_target_properties(entrypoints_yaml_gen PROPERTIES ENTRYPOINT_YAML_FILES "${PANDA_ROOT}/runtime/entrypoints/entrypoints.yaml") 263 264add_custom_target(runtime_options_gen) 265set_target_properties(runtime_options_gen PROPERTIES RUNTIME_OPTIONS_YAML_FILES "${PANDA_ROOT}/runtime/options.yaml") 266 267add_custom_target(compiler_options_gen) 268set_target_properties(compiler_options_gen PROPERTIES COMPILER_OPTIONS_YAML_FILES "${PANDA_ROOT}/compiler/compiler.yaml") 269 270function(add_plugin_options YAML_FILE_PATH) 271 get_target_property(YAML_FILES plugin_options_gen PLUGIN_OPTIONS_YAML_FILES) 272 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 273 set_target_properties(plugin_options_gen PROPERTIES PLUGIN_OPTIONS_YAML_FILES "${YAML_FILES}") 274endfunction() 275 276function(add_entrypoints_yaml YAML_FILE_PATH) 277 get_target_property(YAML_FILES entrypoints_yaml_gen ENTRYPOINT_YAML_FILES) 278 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 279 set_target_properties(entrypoints_yaml_gen PROPERTIES ENTRYPOINT_YAML_FILES "${YAML_FILES}") 280endfunction() 281 282function(add_runtime_options YAML_FILE_PATH) 283 get_target_property(YAML_FILES runtime_options_gen RUNTIME_OPTIONS_YAML_FILES) 284 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 285 set_target_properties(runtime_options_gen PROPERTIES RUNTIME_OPTIONS_YAML_FILES "${YAML_FILES}") 286endfunction() 287 288function(add_compiler_options YAML_FILE_PATH) 289 get_target_property(YAML_FILES compiler_options_gen COMPILER_OPTIONS_YAML_FILES) 290 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 291 set_target_properties(compiler_options_gen PROPERTIES COMPILER_OPTIONS_YAML_FILES "${YAML_FILES}") 292endfunction() 293