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