1#
2# Arm SCP/MCP Software
3# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
4#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7
8#
9# Directories
10#
11export TOP_DIR := $(shell pwd)
12export ARCH_DIR := $(TOP_DIR)/arch
13export FWK_DIR := $(TOP_DIR)/framework
14export TOOLS_DIR := $(TOP_DIR)/tools
15export PRODUCTS_DIR := $(TOP_DIR)/product
16export MODULES_DIR := $(TOP_DIR)/module
17export DOC_DIR := $(TOP_DIR)/doc
18export MOD_TEST_DIR := $(TOP_DIR)/unit_test
19export MOD_TEST_BUILD_DIR=$(BUILD_DIR)/unit_test
20
21#
22# Tools
23#
24export RM := rm -rf
25export MD := mkdir -p
26export CP := cp -r
27export DOC := doxygen
28export CMAKE := cmake
29export CTEST := ctest
30export CD := cd
31export LCOV := lcov
32export GENHTML  := genhtml
33export PYTHON := python3
34
35#
36# Documentation paths
37#
38export BUILD_STRING := $(shell $(TOOLS_DIR)/build_string.py 2>/dev/null)
39
40export BUILD_DOC_DIR = $(BUILD_DIR)/doc
41export MODULE_INCLUDES := $(shell ls -d $(MODULES_DIR)/*/include/ 2>/dev/null)
42export MODULE_DOCS := $(shell ls -d $(MODULES_DIR)/*/doc/ 2>/dev/null)
43export MODULE_DOCS += $(shell ls -d $(PRODUCTS_DIR)/*/module/*/doc/ 2>/dev/null)
44
45#
46# Default options
47#
48DEFAULT_MODE := release
49DEFAULT_BUILD_PATH := $(TOP_DIR)/build
50DEFAULT_VERBOSE := n
51DEFAULT_DEBUGGER := n
52DEFAULT_TOOLCHAIN := GNU
53DEFAULT_BUILD_SYSTEM := Ninja
54export CMSIS_DIR := $(TOP_DIR)/contrib/cmsis/git/CMSIS/Core
55DEFAULT_LOG_LEVEL_debug := INFO
56DEFAULT_LOG_LEVEL_release := WARN
57
58DEFAULT_CMAKE_TOOL_LOG_LEVEL := NOTICE
59
60#
61# Top-level configuration
62#
63.DEFAULT_GOAL = all
64# MAKECMDGOALS isn't set if there's no explicit goal in the
65# command line, so set the default.
66MAKECMDGOALS ?= $(.DEFAULT_GOAL)
67
68# Mode
69MODE ?= $(DEFAULT_MODE)
70ifneq ($(filter-out debug release, $(MODE)),)
71    $(error "Invalid MODE parameter. Aborting...")
72endif
73
74# Build System
75BUILD_SYSTEM ?= $(DEFAULT_BUILD_SYSTEM)
76ifneq ($(filter-out Make Ninja, $(BUILD_SYSTEM)),)
77    $(error "Invalid BUILD_SYSTEM parameter. Aborting...")
78endif
79
80# Toolchain
81TOOLCHAIN ?= $(DEFAULT_TOOLCHAIN)
82ifneq ($(filter-out GNU ArmClang Clang, $(TOOLCHAIN)),)
83    $(error "Invalid TOOLCHAIN parameter. Aborting...")
84endif
85
86# Log level
87LOG_LEVEL ?= $(DEFAULT_LOG_LEVEL_${MODE})
88CMAKE_SCP_LOG_LEVEL_OPTION=-DSCP_LOG_LEVEL=$(LOG_LEVEL)
89
90# Build directory
91BUILD_PATH ?= $(DEFAULT_BUILD_PATH)
92ifeq ($(BUILD_PATH),)
93    $(error "Invalid BUILD_PATH parameter. Aborting...")
94endif
95export BUILD_DIR = $(abspath $(BUILD_PATH))
96
97# Verbose mode: y/n
98export V ?= $(DEFAULT_VERBOSE)
99ifneq ($(V),n)
100    CMAKE_TOOL_LOG_LEVEL := --log-level=VERBOSE
101    CMAKE_BUILD_VERBOSE_OPTION := -v
102else
103    CMAKE_TOOL_LOG_LEVEL := --log-level=$(DEFAULT_CMAKE_TOOL_LOG_LEVEL)
104    MAKEFLAGS += --silent
105    MAKEFLAGS += --no-print-directory
106endif
107
108# Include debugger library: y/n
109DEBUGGER ?= $(DEFAULT_DEBUGGER)
110ifeq ($(DEBUGGER),y)
111    CMAKE_DEBUGGER_OPTION := -DSCP_ENABLE_DEBUGGER=ON
112endif
113
114#
115# Products
116#
117PRODUCTS := $(shell ls $(PRODUCTS_DIR) 2>/dev/null)
118
119#
120# Deprecated Products/Platforms
121#
122DEPRECATED_PLATFORMS := tc0
123
124PRODUCT_INDEPENDENT_GOALS := clean help test doc fwk_test mod_test
125
126ifneq ($(filter-out $(PRODUCT_INDEPENDENT_GOALS), $(MAKECMDGOALS)),)
127    ifeq ($(PRODUCT),)
128        $(error "You must define PRODUCT. Aborting...")
129    endif
130
131    PRODUCT_DIR := $(PRODUCTS_DIR)/$(PRODUCT)
132
133    ifeq ($(wildcard $(PRODUCT_DIR)/product.mk),)
134        $(error "Missing product.mk in $(PRODUCT_DIR)")
135    endif
136
137    include $(PRODUCT_DIR)/product.mk
138
139    ifeq ($(BS_FIRMWARE_LIST),)
140        $(error "You must define BS_FIRMWARE_LIST in product.mk. Aborting...")
141    endif
142
143    # Terminate the build if the chosen platform is in the list of deprecated
144    # ones.
145    ifeq ($(filter-out $(DEPRECATED_PLATFORMS), $(PRODUCT)),)
146        $(error "$(PRODUCT) has been deprecated! Build terminated")
147    endif
148
149    FIRMWARE_TARGETS := $(addprefix firmware-, $(BS_FIRMWARE_LIST))
150
151ifndef PLATFORM_VARIANT
152    PRODUCT_BUILD_PATH := $(BUILD_PATH)/$(BS_PRODUCT_NAME)/$(TOOLCHAIN)/$(MODE)
153else
154    PRODUCT_BUILD_PATH := $(BUILD_PATH)/$(BS_PRODUCT_NAME)/platform_variant_$(PLATFORM_VARIANT)/$(TOOLCHAIN)/$(MODE)
155endif
156
157define msg_start
158================================================================
159Arm SCP/MCP Software build System
160Platform    : $(BS_PRODUCT_NAME)
161Mode        : $(MODE)
162Firmware(s) : $(BS_FIRMWARE_LIST)
163================================================================
164endef
165
166    $(info $(msg_start))
167endif
168
169ifeq ($(MODE),debug)
170	CMAKE_BUILD_TYPE=-DCMAKE_BUILD_TYPE=Debug
171endif
172
173CMAKE_COMMAND_OPTION := $(CMAKE_BUILD_TYPE)
174CMAKE_COMMAND_OPTION += -DSCP_TOOLCHAIN="$(TOOLCHAIN)"
175CMAKE_COMMAND_OPTION += -DSCP_LLVM_SYSROOT_CC="$(LLVM_SYSROOT_CC)"
176
177ifdef PLATFORM_VARIANT
178    CMAKE_COMMAND_OPTION += -DSCP_PLATFORM_VARIANT="$(PLATFORM_VARIANT)"
179endif
180
181ifdef CMAKE_BUILD_VERBOSE_OPTION
182    CMAKE_COMMAND_OPTION += -DCOMMAND_OUTPUT_VERBOSE=1
183endif
184
185ifeq ($(TEST_ON_TARGET),1)
186    CMAKE_COMMAND_OPTION += -DTEST_ON_TARGET=1
187endif
188
189ifeq ($(BUILD_SYSTEM), Ninja)
190    CMAKE_COMMAND_OPTION += -G $(BUILD_SYSTEM)
191endif
192
193CMAKE_COMMAND_OPTION += $(CMAKE_TOOL_LOG_LEVEL)
194CMAKE_COMMAND_OPTION += $(CMAKE_SCP_LOG_LEVEL_OPTION)
195CMAKE_COMMAND_OPTION += $(CMAKE_DEBUGGER_OPTION)
196
197#
198# Rules
199#
200.PHONY: help
201
202help:
203	@echo "Arm SCP/MCP Software build system"
204	@echo ""
205	@echo "Usage: make -f Makefile.cmake [PRODUCT=<name>] [OPTIONS] [TARGET]"
206	@echo ""
207	@echo "--------------------------------------------------------------------"
208	@echo "| Available Targets                                                |"
209	@echo "--------------------------------------------------------------------"
210	@echo "    all             Build all firmware defined by PRODUCT=<product>"
211	@echo "    clean           Remove all built products"
212	@echo "    help            Show this documentation"
213	@echo "    doc             Generate the documentation of this project with Doxygen"
214	@echo ""
215	@echo "--------------------------------------------------------------------"
216	@echo "| Product Selection                                                |"
217	@echo "--------------------------------------------------------------------"
218	@echo "    PRODUCT"
219	@echo "        Available products: $(PRODUCTS)"
220	@echo "        Select the target product to build. This is a required"
221	@echo "        parameter."
222	@echo ""
223	@echo "--------------------------------------------------------------------"
224	@echo "| Options                                                          |"
225	@echo "--------------------------------------------------------------------"
226	@echo "    BUILD_PATH"
227	@echo "        Value: <Full, user provided path>"
228	@echo "        Default: '$(DEFAULT_BUILD_PATH)'"
229	@echo "        Set the base directory used during the build process."
230	@echo ""
231	@echo "    MODE"
232	@echo "        Value: <debug | release>"
233	@echo "        Default: '$(DEFAULT_MODE)'"
234	@echo "        Choose between release and debug mode."
235	@echo ""
236	@echo "    O"
237	@echo "        Value: <Compiler-specific optimization level>"
238	@echo "        Default: <Compiler and MODE specific>"
239	@echo "        Set the desired level of optimization the compiler will use."
240	@echo ""
241	@echo "    V"
242	@echo "        Value: <y|n>"
243	@echo "        Default: $(DEFAULT_VERBOSE)"
244	@echo "        Enable or disable verbose mode for the build system."
245	@echo ""
246	@echo "    DEBUGGER"
247	@echo "        Value: <y|n>"
248	@echo "        Default: $(DEFAULT_DEBUGGER)"
249	@echo "        Include the debugger library."
250	@echo ""
251	@echo "    LOG_LEVEL"
252	@echo "        Value: <TRACE|INFO|WARN|ERROR|CRIT>"
253	@echo "        Default: $(LOG_LEVEL)"
254	@echo "        Filter log messages less important than this level."
255	@echo ""
256	@echo "    BUILD_SYSTEM"
257	@echo "        Value: <Make|Ninja>"
258	@echo "        Default: $(DEFAULT_BUILD_SYSTEM)"
259	@echo "        Specify CMake to generate GNU Make or Ninja build system."
260	@echo ""
261	@echo "    TOOLCHAIN"
262	@echo "        Value: <GNU|ArmClang|Clang>"
263	@echo "        Default: $(DEFAULT_TOOLCHAIN)"
264	@echo "        Specify Toolchain to build the firmware."
265	@echo ""
266	@echo "    LLVM_SYSROOT_CC"
267	@echo "        Value: <LLVM sysroot compiler path>"
268	@echo "        Specify LLVM sysroot compiler path to build the firmware."
269	@echo ""
270	@echo "    PLATFORM_VARIANT"
271	@echo "        Value: <Platform variant>"
272	@echo "        Specify Platform variant if it is required."
273	@echo ""
274	@echo "    EXTRA_CONFIG_ARGS"
275	@echo "        Value: <cmake configuration parameters>"
276	@echo "        Default: "
277	@echo "        Pass extra arguments directly to cmake configuration stage."
278	@echo "        Multiplle extra args can be added with += or by passing the arguments as a string"
279	@echo ""
280	@echo "    EXTRA_BUILD_ARGS"
281	@echo "        Value: <cmake build parameters>"
282	@echo "        Default: "
283	@echo "        Pass extra arguments directly to cmake build stage."
284	@echo "        Multiplle extra args can be added with += or by passing the arguments as a string"
285	@echo ""
286
287
288.SECONDEXPANSION:
289
290.PHONY: all
291all: $(FIRMWARE_TARGETS)
292
293firmware-%: $(PRODUCT_BUILD_PATH)/$$@/CMakeCache.txt
294	$(CMAKE) --build $(<D)/ $(CMAKE_BUILD_VERBOSE_OPTION) $(EXTRA_BUILD_ARGS)
295
296.PRECIOUS: $(PRODUCT_BUILD_PATH)/firmware-%/CMakeCache.txt
297
298$(PRODUCT_BUILD_PATH)/firmware-%/CMakeCache.txt:  $(PRODUCT_DIR)/%/Firmware.cmake
299	$(RM) $(@D)
300	$(CMAKE) -B $(@D) -DSCP_FIRMWARE_SOURCE_DIR:PATH=$(PRODUCT_DIR)/$* $(CMAKE_COMMAND_OPTION) $(EXTRA_CONFIG_ARGS)
301
302.PHONY: clean
303clean:
304	$(RM) $(BUILD_DIR)
305
306
307.PHONY: doc
308doc:
309	mkdir -p $(BUILD_DOC_DIR)
310	$(DOC) $(DOC_DIR)/Doxyfile
311
312.PHONY: test
313test : fwk_test mod_test
314
315.PHONY: fwk_test
316fwk_test:
317	$(CMAKE) -B ${BUILD_PATH}/framework/test $(FWK_DIR)/test -G Ninja
318	$(CMAKE) --build ${BUILD_PATH}/framework/test
319	# --test-dir option of ctest is not available before ctest 3.20
320	# so use workaround to change the test dir and run the tests from there
321	${CD} ${BUILD_PATH}/framework/test && ${CTEST} -V
322
323.PHONY: mod_test
324mod_test:
325	$(CMAKE) -B $(MOD_TEST_BUILD_DIR) $(MOD_TEST_DIR) -G Ninja
326	$(CMAKE) --build $(MOD_TEST_BUILD_DIR)
327	${CD} $(MOD_TEST_BUILD_DIR) && $(CTEST) -V --output-junit Testing/TestResults.xml
328	${CD} $(MOD_TEST_BUILD_DIR) && $(LCOV) --capture --directory $(MOD_TEST_BUILD_DIR) --output-file scp_v2_unit_test_coverage.info
329	${CD} $(MOD_TEST_BUILD_DIR) && $(PYTHON) ../../unit_test/utils/generate_coverage_report.py
330	${CD} $(MOD_TEST_BUILD_DIR) && $(GENHTML) scp_v2_unit_test_coverage_filtered.info --prefix "$(TOP_DIR)" --output-directory $(BUILD_DIR)/coverage_report
331