1# Copyright (C) 2021-2022 Intel Corporation.
2# SPDX-License-Identifier: BSD-3-Clause
3
4# usage: check_coexistence <symbol 1> <symbol 2>
5#
6# This macro checks if the given symbols are both defined or both not. This is used to check the coexistence of BOARD &
7# SCENARIO or BOARD_FILE & SCENARIO_FILE.
8define check_coexistence =
9ifdef $(1)
10  ifndef $(2)
11    $$(warning $(1) is defined while $(2) is empty)
12    $$(error $(1) & $(2) must be given in pair)
13  endif
14else
15  ifdef $(2)
16    $$(warning $(2) is defined while $(1) is empty)
17    $$(error $(1) & $(2) must be given in pair)
18  endif
19endif
20endef
21
22# usage: determine_config <symbol>
23#
24# BOARD and SCENARIO can be specified in the following places.
25#
26#   1. Configuration data in config.mk (named CONFIG_BOARD or CONFIG_SCENARIO) which are extracted from the existing XML
27#      file.
28#
29#   2. Variables defined on the command line when invoking 'make'.
30#
31# In place #2 it can be either a board/scenario name or path to an XML file. Depending on where these variables are
32# defined and their values, this script behaves as follows.
33#
34#   * If a variable is defined in both #1 and #2 with the same value, that value is effective for the build.
35#
36#   * If a variable is defined in both #1 and #2 with different values, the build terminates with an error message.
37#
38#   * If a variable is defined in either #1 or #2 (but not both), that value is effective for the build.
39#
40#   * If a variable is defined in neither #1 nor #2, the build terminates with an error message.
41#
42# If #2 gives a path to an XML file, the board/scenario defined in that file is used for the comparison above.
43#
44# This macro implements the policy. The following variables will be rewritten after the rules are evaluated without any
45# error.
46#
47#   * The <symbol> (i.e. either BOARD or SCENARIO) will always hold the name of the effective board/scenario.
48#
49#   * The <symbol>_FILE (i.e. either BOARD_FILE or SCENARIO_FILE) will hold the path to an existing XML file that
50#     defines the effective board/scenario. If only a BOARD/SCENARIO name is given from the command line, a predefined
51#     configuration under misc/config_tools/data/$BOARD will be used. If neither <symbol>_FILE nor <symbol> is given,
52#     this variable has an empty string as its value.
53#
54define determine_config =
55ifneq ($($(1)),)
56  ifneq ($(realpath $($(1))),)
57    override $(1)_FILE := $($(1))
58    ifneq (SCENARIO, $(1))
59      override $(1) := $$(shell xmllint --xpath 'string(/acrn-config/@$(shell echo $(1) | tr A-Z a-z))' $$($(1)_FILE))
60    else
61      scenario_name := $(subst .xml,,$(notdir $($(1))))
62      override $(1) := $$(if $$(subst scenario,,$$(scenario_name)),$$(scenario_name),$(notdir $(abspath $(dir $($(1))))))
63    endif
64  else
65    override $(1)_FILE := $(HV_PREDEFINED_DATA_DIR)/$$(BOARD)/$$($(1)).xml
66    ifeq ($$(realpath $$($(1)_FILE)),)
67      $$(error $(1) = '$($(1))' is neither path to a file nor name of a predefined board)
68    endif
69  endif
70  ifdef CONFIG_$(1)
71    ifneq ($$($(1)), $(CONFIG_$(1)))
72      $$(warning The command line sets $(1) to be '$$($(1))', but an existing build is configured with '$(CONFIG_$(1))')
73      $$(warning Try cleaning up the existing build with 'make clean' or setting HV_OBJDIR to a newly-created directory)
74      $$(error Configuration conflict identified)
75    endif
76  endif
77else
78  ifdef CONFIG_$(1)
79    override $(1) := $(CONFIG_$(1))
80    override $(1)_FILE :=
81  else
82    $$(error There is no $(1) parameter specified on the command-line and none from a previous build. Please provide a valid $(1) parameter)
83  endif
84endif
85endef
86
87# usage: determine_build_type <default>
88#
89# Similar to BOARD or SCENARIO, the RELEASE variable has three sources where it can be defined. But unlike those
90# variables that cannot be modified once configured, users shall be able to tweak RELEASE from the command line even a
91# build directory has already been configured.
92#
93# This macro implements the same check as determine_config, but attempts to update the configuration file if RELEASE is
94# changed.
95define determine_build_type =
96ifdef RELEASE
97  ifdef CONFIG_RELEASE
98    ifneq ($(RELEASE),$(CONFIG_RELEASE))
99      $$(warning The command line sets RELEASE to be '$(RELEASE)', but an existing build is configured with '$(CONFIG_RELEASE)')
100      $$(warning The configuration will be modified for RELEASE=$(RELEASE))
101      ifeq ($(RELEASE),y)
102        $$(shell sed -i "s@\(<BUILD_TYPE.*>\).*\(</BUILD_TYPE>\)@\1release\2@g" $(HV_SCENARIO_XML))
103      else
104        $$(shell sed -i "s@\(<BUILD_TYPE.*>\).*\(</BUILD_TYPE>\)@\1debug\2@g" $(HV_SCENARIO_XML))
105      endif
106    endif
107  endif
108else
109  ifdef CONFIG_RELEASE
110    override RELEASE := $(CONFIG_RELEASE)
111  else
112    override RELEASE := $(1)
113  endif
114endif
115endef
116
117# Paths to the inputs
118HV_BOARD_XML := $(HV_OBJDIR)/.board.xml
119HV_SCENARIO_XML := $(HV_OBJDIR)/.scenario.xml
120HV_UNIFIED_XML_IN := $(BASEDIR)/scripts/makefile/unified.xml.in
121HV_PREDEFINED_DATA_DIR := $(realpath $(BASEDIR)/../misc/config_tools/data)
122HV_CONFIG_TOOL_DIR := $(realpath $(BASEDIR)/../misc/config_tools)
123HV_CONFIG_XFORM_DIR := $(HV_CONFIG_TOOL_DIR)/xforms
124
125# Paths to the outputs:
126HV_CONFIG_DIR := $(HV_OBJDIR)/configs
127HV_ALLOCATION_XML := $(HV_CONFIG_DIR)/allocation.xml
128HV_UNIFIED_XML := $(HV_CONFIG_DIR)/unified.xml
129HV_CONFIG_H := $(HV_OBJDIR)/include/config.h
130HV_CONFIG_MK := $(HV_CONFIG_DIR)/config.mk
131HV_VALIDATION_TIMESTAMP := $(HV_CONFIG_DIR)/.validation.timestamp
132HV_CONFIG_TIMESTAMP := $(HV_CONFIG_DIR)/.configfiles.timestamp
133HV_DIFFCONFIG_LIST := $(HV_CONFIG_DIR)/.diffconfig
134
135# Directory containing generated configuration sources for diffconfig
136HV_CONFIG_A_DIR := $(HV_OBJDIR)/a
137# Directory containing edited configuration sources for diffconfig
138HV_CONFIG_B_DIR := $(HV_OBJDIR)/b
139# Patch encoding differences between generated and edited config. sources
140HV_CONFIG_DIFF := $(HV_OBJDIR)/config.patch
141
142# Backward-compatibility for RELEASE=(0|1)
143ifdef RELEASE
144  ifeq ($(RELEASE),1)
145    override RELEASE := y
146  else
147    ifeq ($(RELEASE),0)
148      override RELEASE := n
149    endif
150  endif
151endif
152
153# BOARD/SCENARIO/BOARD_FILE/SCENARIO_FILE parameters sanity check.
154#
155# 1. Raise an error if BOARD/SCENARIO (or BOARD_FILE/SCENARIO_FILE) are partially given.
156# 2. Raise an error if BOARD_FILE/SCENARIO_FILE are given but do not point to valid XMLs.
157
158$(eval $(call check_coexistence,BOARD,SCENARIO))
159$(eval $(call check_coexistence,BOARD_FILE,SCENARIO_FILE))
160
161# BOARD_FILE/SCENARIO_FILE are to be obsoleted. Users can now use BOARD/SCENARIO to give either pre-defined
162# board/scenario or their own XML files.
163#
164# The following block converts BOARD_FILE/SCENARIO_FILE to BOARD/SCENARIO. Removing support of BOARD_FILE/SCENARIO_FILE
165# can be done by simply deleting it.
166ifneq ($(BOARD_FILE)$(SCENARIO_FILE),)
167  $(warning BOARD_FILE/SCENARIO_FILE are obsoleted. Use BOARD/SCENARIO to specify either predefined board/scenario or your own board/scenario XMLs)
168
169  ifneq ($(BOARD)$(SCENARIO),)
170    $(warning BOARD/SCENARIO and BOARD_FILE/SCENARIO_FILE are both given. BOARD/SCENARIO will take precedence)
171  else
172    ifneq ($(BOARD_FILE), $(wildcard $(BOARD_FILE)))
173      $(error BOARD_FILE: $(BOARD_FILE) does not exist)
174    endif
175    ifneq ($(SCENARIO_FILE), $(wildcard $(SCENARIO_FILE)))
176      $(error SCENARIO_FILE: $(SCENARIO_FILE) does not exist)
177    endif
178    BOARD := $(BOARD_FILE)
179    SCENARIO := $(SCENARIO_FILE)
180  endif
181endif
182
183# Internally we still use BOARD to represent the name of the target board and BOARD_FILE to be the path to the board XML
184# file. SCENARIO/SCENARIO_FILE are used in the same way. The following block translates the user-visible BOARD/SCENARIO
185# (which is multiplexed) to the internal representation.
186
187ifeq ($(findstring $(MAKECMDGOALS),distclean),)
188-include $(HV_CONFIG_MK)
189$(eval $(call determine_config,BOARD))
190$(eval $(call determine_config,SCENARIO))
191$(eval $(call determine_build_type,n))
192endif
193
194$(HV_BOARD_XML): $(BOARD_FILE)
195	@echo "Board XML is fetched from $(realpath $(BOARD_FILE))"
196	@mkdir -p $(dir $(HV_BOARD_XML))
197	@cp $(BOARD_FILE) $(HV_BOARD_XML)
198
199$(HV_SCENARIO_XML): $(SCENARIO_FILE)
200	@echo "Scenario XML is fetched from $(abspath $(SCENARIO_FILE))"
201	@mkdir -p $(dir $(HV_SCENARIO_XML))
202	@python3 $(HV_CONFIG_TOOL_DIR)/scenario_config/default_populator.py $(SCENARIO_FILE) $(HV_SCENARIO_XML)
203	@sed "s#<acrn-config.*#<acrn-config scenario=\"$(SCENARIO)\" >#g" -i $(HV_SCENARIO_XML)
204
205# A unified XML is generated to include board and scenario XML files so that XSLT scripts have access to both for
206# generating source files.
207$(HV_ALLOCATION_XML): $(HV_BOARD_XML) $(HV_SCENARIO_XML) $(HV_VALIDATION_TIMESTAMP) | $(HV_CONFIG_DIR)
208	@python3 $(HV_CONFIG_TOOL_DIR)/static_allocators/main.py --board $(HV_BOARD_XML) --scenario $(HV_SCENARIO_XML) --output $(HV_ALLOCATION_XML)
209	@echo "$@ generated"
210
211$(HV_UNIFIED_XML): $(HV_BOARD_XML) $(HV_SCENARIO_XML) $(HV_ALLOCATION_XML) | $(HV_CONFIG_DIR)
212	@sed "s/{BOARD_FILE}/$(subst /,\\/,$(realpath $(HV_BOARD_XML)))/g" $(HV_UNIFIED_XML_IN) | \
213	 sed "s/{SCENARIO_FILE}/$(subst /,\\/,$(HV_SCENARIO_XML))/g" | \
214	 sed "s/{ALLOCATION_FILE}/$(subst /,\\/,$(HV_ALLOCATION_XML))/g" > $@
215	@echo "$@ generated"
216
217$(HV_CONFIG_MK): $(HV_UNIFIED_XML) | $(HV_CONFIG_DIR)
218	@xsltproc -o $@ --xinclude --xincludestyle $(HV_CONFIG_XFORM_DIR)/config.mk.xsl $<
219	@echo "$@ generated"
220
221$(HV_CONFIG_H): $(HV_UNIFIED_XML)
222	@mkdir -p $(dir $(HV_CONFIG_H))
223	@xsltproc -o $@ --xinclude --xincludestyle $(HV_CONFIG_XFORM_DIR)/config.h.xsl $<
224	@echo "$@ generated"
225
226$(HV_VALIDATION_TIMESTAMP): $(HV_BOARD_XML) $(HV_SCENARIO_XML) | $(HV_CONFIG_DIR)
227	@echo "Validating scenario configurations..."
228	@python3 $(HV_CONFIG_TOOL_DIR)/scenario_config/validator.py $(HV_BOARD_XML) $(HV_SCENARIO_XML)
229	@touch $@
230
231$(HV_CONFIG_TIMESTAMP): $(HV_VALIDATION_TIMESTAMP) $(HV_UNIFIED_XML) ${HV_DIFFCONFIG_LIST} | $(HV_CONFIG_DIR)
232	@sh $(BASEDIR)/scripts/genconf.sh $(BASEDIR) $(HV_BOARD_XML) $(HV_SCENARIO_XML) $(HV_CONFIG_DIR) $(HV_UNIFIED_XML)
233	@touch $@
234
235.PHONY: defconfig
236defconfig: $(HV_CONFIG_TIMESTAMP)
237
238showconfig:
239	@echo "Build directory: $(HV_OBJDIR)"
240	@echo "This build directory is configured with the settings below."
241	@echo "- BOARD = $(BOARD)"
242	@echo "- SCENARIO = $(SCENARIO)"
243	@echo "- RELEASE = $(RELEASE)"
244
245diffconfig:
246	@rm -rf $(HV_CONFIG_A_DIR) $(HV_CONFIG_B_DIR)
247	@sh $(BASEDIR)/scripts/genconf.sh $(BASEDIR) $(HV_BOARD_XML) $(HV_SCENARIO_XML) $(HV_CONFIG_A_DIR) $(HV_UNIFIED_XML)
248	@find $(HV_CONFIG_A_DIR) -name '*.aml' -delete
249	@cd $(HV_CONFIG_DIR) && find . -name '*.c' -or -name '*.h' -or -name '*.config' -or -name '*.asl' | while read f; do \
250	  nf=$(HV_CONFIG_B_DIR)/$${f}; mkdir -p `dirname $${nf}` && cp $${f} $${nf}; \
251	done
252	@cd $(HV_OBJDIR) && git diff --no-index --no-prefix a/ b/ > $(HV_CONFIG_DIFF) || true
253	@echo "Diff on generated configuration files is available at $(HV_CONFIG_DIFF)."
254	@echo "To make a patch effective, use 'applydiffconfig PATCH=/path/to/patch' to register it to a build."
255
256applydiffconfig:
257ifdef PATCH
258  ifneq ($(realpath $(PATCH)),)
259    ifeq ($(shell grep '^$(realpath ${PATCH})$$' ${HV_DIFFCONFIG_LIST}),)
260	@echo $(realpath $(PATCH)) >> ${HV_DIFFCONFIG_LIST}
261	@echo "${PATCH} is registered for build directory ${HV_OBJDIR}."
262	@echo "Registered patches will be applied the next time 'make' is invoked."
263	@echo "To unregister a patch, remove it from ${HV_DIFFCONFIG_LIST}."
264    else
265	@echo "${PATCH} is already registered for build directory ${HV_OBJDIR}."
266	@echo "To unregister a patch, remove it from ${HV_DIFFCONFIG_LIST}."
267    endif
268  else
269	@echo "${PATCH}: No such file or directory"
270  endif
271else
272	@echo "No patch file or directory is specified"
273	@echo "Try 'make applydiffconfig PATCH=/path/to/patch' to register patches for generated configuration files."
274  ifneq ($(realpath $(HV_DIFFCONFIG_LIST)),)
275	@echo "Registers patches:"
276	@cat $(HV_DIFFCONFIG_LIST)
277  endif
278endif
279
280$(HV_DIFFCONFIG_LIST): | $(HV_CONFIG_DIR)
281	@touch $@
282
283menuconfig:
284	@echo "To tweak the configurations, run $(HV_CONFIG_TOOL_DIR)/config_app/app.py using python3 and load $(HV_SCENARIO_XML) in the web browser."
285
286$(HV_CONFIG_DIR):
287	@mkdir -p $@
288
289# Legacy variables and targets
290ifdef TARGET_DIR
291  $(warning TARGET_DIR is obsoleted because generated configuration files are now stored in the build directory)
292endif
293
294oldconfig:
295	@echo "Generated configuration files are now automatically updated with the scenario XML file."
296	@echo "There is no need to invoke oldconfig manually anymore."
297
298update_config:
299	@echo "Generated configuration files are now automatically updated with the scenario XML file."
300	@echo "There is no need to invoke update_config manually anymore."
301
302CFLAGS += -include $(HV_CONFIG_H)
303