1# Copyright (c) 2021-2022 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 -- data source, YAML file 22# * TEMPLATES -- a list of templates to generate files 23# * REQUIRES -- a list of Ruby scripts that provide data-querying API for templates 24# 25# Optional arguments: 26# * SOURCE -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates 27# * DESTINATION -- a directory for output files, default is ${PANDA_BINARY_ROOT} 28# * EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies 29# * EXTRA_ARGV -- a list of positional arguments that could be accessed in '.erb' files via ARGV[] 30 31function(panda_gen) 32 set(singlevalues DATA SOURCE DESTINATION TARGET_NAME) 33 set(multivalues TEMPLATES REQUIRES EXTRA_DEPENDENCIES EXTRA_ARGV) 34 cmake_parse_arguments( 35 GEN_ARG 36 "" 37 "${singlevalues}" 38 "${multivalues}" 39 ${ARGN} 40 ) 41 42 if (NOT DEFINED GEN_ARG_TEMPLATES) 43 message(FATAL_ERROR "`TEMPLATES` were not passed to `panda_gen` function") 44 endif() 45 46 if (NOT DEFINED GEN_ARG_DATA) 47 message(FATAL_ERROR "`DATA` was not passed to `panda_gen` function") 48 endif() 49 50 if (NOT DEFINED GEN_ARG_SOURCE) 51 set(GEN_ARG_SOURCE "${PROJECT_SOURCE_DIR}/templates") 52 endif() 53 54 if (NOT DEFINED GEN_ARG_DESTINATION) 55 set(GEN_ARG_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") 56 endif() 57 58 if (NOT DEFINED GEN_ARG_TARGET_NAME) 59 get_filename_component(DATA_NAME ${GEN_ARG_DATA} NAME_WE) 60 set(GEN_ARG_TARGET_NAME "${DATA_NAME}_gen_${PROJECT_NAME}") 61 endif() 62 63 add_custom_target(${GEN_ARG_TARGET_NAME}) # Umbrella target for all generated files 64 add_dependencies(panda_gen_files ${GEN_ARG_TARGET_NAME}) 65 66 foreach(t ${GEN_ARG_TEMPLATES}) 67 set(TEMPLATE "${GEN_ARG_SOURCE}/${t}") 68 string(REGEX REPLACE "\.erb$" "" NAME ${t}) 69 string(REPLACE "\." "_" TARGET ${NAME}) 70 string(REPLACE "/" "_" TARGET ${TARGET}) 71 set(TARGET ${PROJECT_NAME}_${TARGET}) 72 set(OUTPUT_FILE "${GEN_ARG_DESTINATION}/${NAME}") 73 74 panda_gen_file(DATAFILE ${GEN_ARG_DATA} 75 TEMPLATE ${TEMPLATE} 76 OUTPUTFILE ${OUTPUT_FILE} 77 REQUIRES ${GEN_ARG_REQUIRES} 78 EXTRA_DEPENDENCIES ${GEN_ARG_EXTRA_DEPENDENCIES} 79 EXTRA_ARGV ${GEN_ARG_EXTRA_ARGV} 80 ) 81 add_custom_target(${TARGET} DEPENDS ${OUTPUT_FILE}) 82 add_dependencies(${GEN_ARG_TARGET_NAME} ${TARGET}) 83 endforeach() 84endfunction() 85 86# Calls `panda_gen` for ISA YAML. 87# Adds targets for every template. Also adds a target for the whole function invocation 88# with name isa_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files. 89# 90# Mandatory arguments: 91# * TEMPLATES -- a list of templates to generate files 92# 93# Optional arguments: 94# * SOURCE -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates 95# * DESTINATION -- a directory for output files, default is ${PANDA_BINARY_ROOT} 96# * REQUIRES -- if defined, will require additional Ruby files for template generation 97# * EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies 98 99function(panda_isa_gen) 100 set(singlevalues SOURCE DESTINATION TARGET_NAME) 101 set(multivalues TEMPLATES REQUIRES EXTRA_DEPENDENCIES) 102 cmake_parse_arguments( 103 ISA_GEN_ARG 104 "" 105 "${singlevalues}" 106 "${multivalues}" 107 ${ARGN} 108 ) 109 set(ISA_DATA "${CMAKE_BINARY_DIR}/isa/isa.yaml") 110 set(ISAPI "${PANDA_ROOT}/isa/isapi.rb") 111 list(INSERT ISA_GEN_ARG_REQUIRES 0 ${ISAPI}) 112 list(APPEND ISA_GEN_ARG_EXTRA_DEPENDENCIES isa_assert) 113 panda_gen(DATA ${ISA_DATA} 114 TEMPLATES ${ISA_GEN_ARG_TEMPLATES} 115 SOURCE ${ISA_GEN_ARG_SOURCE} 116 TARGET_NAME ${ISA_GEN_ARG_TARGET_NAME} 117 DESTINATION ${ISA_GEN_ARG_DESTINATION} 118 REQUIRES ${ISA_GEN_ARG_REQUIRES} 119 EXTRA_DEPENDENCIES ${ISA_GEN_ARG_EXTRA_DEPENDENCIES} 120 ) 121endfunction() 122 123# Generate file for a template and YAML data provided. 124# 125# Mandatory arguments: 126# DATAFILE -- YAML data full name 127# TEMPLATE -- template full name 128# OUTPUTFILE -- output file full name 129# REQUIRES -- a list of scripts that provide data-querying API for templates 130# EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies 131# EXTRA_ARGV -- a list of positional arguments that could be accessed in '.erb' files via ARGV[] 132 133function(panda_gen_file) 134 set(singlevalues DATAFILE TEMPLATE OUTPUTFILE) 135 set(multivalues REQUIRES EXTRA_DEPENDENCIES EXTRA_ARGV) 136 cmake_parse_arguments( 137 ARG 138 "" 139 "${singlevalues}" 140 "${multivalues}" 141 ${ARGN} 142 ) 143 set(GENERATOR "${PANDA_ROOT}/isa/gen.rb") 144 string(REPLACE ";" "," REQUIRE_STR "${ARG_REQUIRES}") 145 set(DEPENDS_LIST ${GENERATOR} ${ARG_TEMPLATE} ${ARG_DATAFILE}) 146 147 add_custom_command(OUTPUT ${ARG_OUTPUTFILE} 148 COMMENT "Generate file for ${ARG_TEMPLATE}" 149 COMMAND ${GENERATOR} ${ARG_EXTRA_ARGV} --template ${ARG_TEMPLATE} --data ${ARG_DATAFILE} --output ${ARG_OUTPUTFILE} --require ${REQUIRE_STR} 150 DEPENDS ${DEPENDS_LIST} ${ARG_EXTRA_DEPENDENCIES} ${ARG_REQUIRES} 151 ) 152endfunction() 153 154# Create an options header using a YAML file for the target 155# 156# Mandatory arguments: 157# TARGET -- target 158# YAML_FILE -- YAML file 159# GENERATED_HEADER -- generated header 160# 161# Use "#include 'generated/GENERATED_HEADER"' to include the generated header 162 163function(panda_gen_options) 164 # Parsing function arguments 165 set(singlevalues TARGET YAML_FILE GENERATED_HEADER) 166 cmake_parse_arguments(GEN_OPTIONS "" "${singlevalues}" "" ${ARGN}) 167 168 # Generate a options header 169 get_filename_component(YAML_FILE ${GEN_OPTIONS_YAML_FILE} ABSOLUTE) 170 set(GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/panda_gen_options/generated) 171 file(MAKE_DIRECTORY ${GENERATED_DIR}) 172 set(OPTIONS_H ${GENERATED_DIR}/${GEN_OPTIONS_GENERATED_HEADER}) 173 panda_gen_file( 174 DATAFILE ${YAML_FILE} 175 TEMPLATE ${PANDA_ROOT}/templates/options/options.h.erb 176 OUTPUTFILE ${OPTIONS_H} 177 REQUIRES ${PANDA_ROOT}/templates/common.rb 178 ) 179 180 # Add dependencies for a target 181 panda_target_include_directories(${GEN_OPTIONS_TARGET} PUBLIC ${GENERATED_DIR}/..) 182 add_custom_target(${GEN_OPTIONS_TARGET}_options DEPENDS ${OPTIONS_H}) 183 add_dependencies(${GEN_OPTIONS_TARGET} ${GEN_OPTIONS_TARGET}_options) 184 add_dependencies(panda_gen_files ${GEN_OPTIONS_TARGET}_options) 185endfunction() 186 187function(panda_gen_messages) 188 set(singlevalues TARGET YAML_FILE GENERATED_HEADER) 189 cmake_parse_arguments(ARG "" "${singlevalues}" "" ${ARGN}) 190 191 if(NOT DEFINED ARG_YAML_FILE) 192 set(ARG_YAML_FILE ${CMAKE_CURRENT_SOURCE_DIR}/messages.yaml) 193 endif() 194 195 if(NOT DEFINED ARG_GENERATED_HEADER) 196 set(ARG_GENERATED_HEADER messages.h) 197 endif() 198 199 get_filename_component(YAML_FILE ${ARG_YAML_FILE} ABSOLUTE) 200 201 if(IS_ABSOLUTE ${ARG_GENERATED_HEADER}) 202 get_filename_component(GENERATED_DIR ${ARG_GENERATED_HEADER} DIRECTORY) 203 set(MESSAGES_H ${ARG_GENERATED_HEADER}) 204 else() 205 set(INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/panda_gen_messages) 206 set(GENERATED_DIR ${INCLUDE_DIR}/generated) 207 set(MESSAGES_H ${GENERATED_DIR}/${ARG_GENERATED_HEADER}) 208 endif() 209 210 file(MAKE_DIRECTORY ${GENERATED_DIR}) 211 panda_gen_file( 212 DATAFILE ${YAML_FILE} 213 TEMPLATE ${PANDA_ROOT}/templates/messages/messages.h.erb 214 OUTPUTFILE ${MESSAGES_H} 215 REQUIRES ${PANDA_ROOT}/templates/messages.rb 216 ) 217 218 # Add dependencies for a target 219 if (NOT DEFINED ARG_TARGET) 220 set(ARG_TARGET messages_gen_${PROJECT_NAME}) 221 add_custom_target(${ARG_TARGET}) 222 endif() 223 224 if (DEFINED INCLUDE_DIR) 225 panda_target_include_directories(${ARG_TARGET} PUBLIC ${INCLUDE_DIR}) 226 endif() 227 add_custom_target(${ARG_TARGET}_messages DEPENDS ${MESSAGES_H}) 228 add_dependencies(${ARG_TARGET} ${ARG_TARGET}_messages) 229 add_dependencies(panda_gen_files ${ARG_TARGET}_messages) 230endfunction() 231 232add_custom_target(plugin_options_gen) 233set_target_properties(plugin_options_gen PROPERTIES PLUGIN_OPTIONS_YAML_FILES "${PANDA_ROOT}/templates/plugin_options.yaml") 234 235add_custom_target(entrypoints_yaml_gen) 236set_target_properties(entrypoints_yaml_gen PROPERTIES ENTRYPOINT_YAML_FILES "${PANDA_ROOT}/runtime/entrypoints/entrypoints.yaml") 237 238add_custom_target(runtime_options_gen) 239set_target_properties(runtime_options_gen PROPERTIES RUNTIME_OPTIONS_YAML_FILES "${PANDA_ROOT}/runtime/options.yaml") 240 241add_custom_target(compiler_options_gen) 242set_target_properties(compiler_options_gen PROPERTIES COMPILER_OPTIONS_YAML_FILES "${PANDA_ROOT}/compiler/compiler.yaml") 243 244function(add_plugin_options YAML_FILE_PATH) 245 get_target_property(YAML_FILES plugin_options_gen PLUGIN_OPTIONS_YAML_FILES) 246 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 247 set_target_properties(plugin_options_gen PROPERTIES PLUGIN_OPTIONS_YAML_FILES "${YAML_FILES}") 248endfunction() 249 250function(add_entrypoints_yaml YAML_FILE_PATH) 251 get_target_property(YAML_FILES entrypoints_yaml_gen ENTRYPOINT_YAML_FILES) 252 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 253 set_target_properties(entrypoints_yaml_gen PROPERTIES ENTRYPOINT_YAML_FILES "${YAML_FILES}") 254endfunction() 255 256function(add_runtime_options YAML_FILE_PATH) 257 get_target_property(YAML_FILES runtime_options_gen RUNTIME_OPTIONS_YAML_FILES) 258 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 259 set_target_properties(runtime_options_gen PROPERTIES RUNTIME_OPTIONS_YAML_FILES "${YAML_FILES}") 260endfunction() 261 262function(add_compiler_options YAML_FILE_PATH) 263 get_target_property(YAML_FILES compiler_options_gen COMPILER_OPTIONS_YAML_FILES) 264 list(APPEND YAML_FILES ${YAML_FILE_PATH}) 265 set_target_properties(compiler_options_gen PROPERTIES COMPILER_OPTIONS_YAML_FILES "${YAML_FILES}") 266endfunction() 267