# Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. # SPDX-License-Identifier: MIT ################################################################ # Root Makefile of the whole project ################################################################ ################################################################ # Basic Definitions ################################################################ BOOT := KERNEL ?= freertos ifeq ($(DOCS_ARCH),) ifeq ($(ARCH),) DOCS_ARCH = arm64 else DOCS_ARCH = $(ARCH) endif endif ################################################################ # Directories and Files ################################################################ SHELL := /bin/bash PWD := $(shell pwd) PRJDIR := $(PWD) app_DIR := $(PRJDIR)/apps bootloader_DIR := $(PRJDIR)/$(BOOT) build_DIR := $(PRJDIR)/build_system docs_DIR := $(PRJDIR)/arch/$(DOCS_ARCH)/docs kernel_DIR := $(PRJDIR)/kernel/$(KERNEL) fw_DIR := $(PRJDIR)/firmware product_DIR := $(PRJDIR)/products sign_tool_DIR := $(PRJDIR)/tools/sign_tool adnl_DIR := $(PRJDIR)/tools/adnl board_DIR := $(PRJDIR)/boards/$(ARCH)/$(BOARD) OUTPUT_DIR := $(PRJDIR)/output BUILD_DIR := $(OUTPUT_DIR)/$(ARCH)-$(BOARD)-$(PRODUCT) docs_BUILD_DIR := $(OUTPUT_DIR)/docs/$(DOCS_ARCH) bootloader_BUILD_DIR := $(BUILD_DIR)/$(BOOT) kernel_BUILD_DIR := $(BUILD_DIR)/$(KERNEL) sign_tool_BUILD_DIR := $(sign_tool_DIR) adnl_BUILD_DIR := $(adnl_DIR) bootloader_BIN := $(bootloader_BUILD_DIR)/$(BOOT)/ext/mcuboot/mcuboot.bin kernel_BIN := $(kernel_BUILD_DIR)/$(KERNEL).bin fw_BIN := $(fw_DIR)/wcn-modem.bin adnl_BIN := $(adnl_BUILD_DIR)/adnl DIST_DIR := $(BUILD_DIR)/images bootloader_dist_BIN := $(DIST_DIR)/mcuboot-signed.bin kernel_dist_BIN := $(DIST_DIR)/$(KERNEL)-signed.bin fw_dist_BIN := $(DIST_DIR)/wcn-modem.bin adnl_dist_BIN := $(DIST_DIR)/adnl bootloader_KEYPATH = $(build_DIR)/key/rsa/3072 kernel_KEYPATH = $(build_DIR)/key/rsa/2048 SIGNTOOL = $(sign_tool_DIR)/imgtool.py firmware_TOOL = $(PRJDIR)/scripts/gen_firmware.py wcn_firmware_DIR = $(PRJDIR)/wcn/firmware SDK_BASE := $(PRJDIR) TOOLCHAIN_PATH := TOOLCHAIN_DIR := $(OUTPUT_DIR)/toolchains/$(COMPILER)-$(TOOLCHAIN_KEYWORD) PATH := $(TOOLCHAIN_DIR)/bin:$(PATH) #This code segment is used to set the path of the compiler for the find_compiler.cmake to search. ifeq ($(ARCH),xtensa) XTENSA_LOWPOWER_PATTERN=_lowpower ifeq ($(SOC),$(filter $(SOC),a5 t3x s6 a9 a10)) XTENSA_CORE = Amlogic_v9 XTENSA_TOOLCHAIN_VER = RI-2020.5-linux else ifeq ($(SOC),a1) ifeq ($(findstring $(XTENSA_LOWPOWER_PATTERN),$(BOARD)),$(XTENSA_LOWPOWER_PATTERN)) XTENSA_CORE = Amlogic_v2 else XTENSA_CORE = Amlogic_v0 endif XTENSA_TOOLCHAIN_VER = RG-2018.9-linux else XTENSA_CORE = Amlogic_v0 XTENSA_TOOLCHAIN_VER = RG-2018.9-linux endif TOOLCHAIN_PATH=/opt/xtensa/XtDevTools/install/tools/$(XTENSA_TOOLCHAIN_VER)/XtensaTools XTENSA_SYSTEM=/opt/xtensa/XtDevTools/install/builds/$(XTENSA_TOOLCHAIN_VER)/$(XTENSA_CORE)/config endif export PATH ARCH SOC BOARD KERNEL SDK_BASE OUTPUT_DIR kernel_BUILD_DIR TOOLCHAIN_PATH XTENSA_CORE XTENSA_SYSTEM ################################################################ # Macros ################################################################ # MESSAGE Macro -- display a message in bold type MESSAGE = echo "$(TERM_BOLD)>>> $(1)$(TERM_RESET)" TERM_BOLD := $(shell tput smso 2>/dev/null) TERM_RESET := ${shell tput rmso 2>/dev/null} # Macro of Generating Buildsystem # $(1): Target define GENERATE_BUILDSYSTEM $($(1)_BUILD_DIR): project toolchain @ mkdir -p $($(1)_BUILD_DIR) # Auto-generate root CMakeLists.txt and Kconfig @ if [[ -d "$(wcn_firmware_DIR)" ]] && [[ -f "$(firmware_TOOL)" ]]; then \ python3 $(firmware_TOOL) -I $(wcn_firmware_DIR) -o $(BUILD_DIR)/$(KERNEL)/firmware.h; \ fi @ ./scripts/setup.sh @ if [ ! -f $($(1)_BUILD_DIR)/build.ninja ]; then \ cmake -G Ninja -DBOARD=$(BOARD) -DCMAKE_TOOLCHAIN_FILE=$(build_DIR)/cmake/toolchains/$(ARCH)_compiler.cmake -S $(product_DIR)/$(PRODUCT) -B $($(1)_BUILD_DIR); \ fi endef # Macro of Building CMake Targets # $(1): Target define GENERATE_CMAKE_TARGET .PHONY: $(1) $(1): $($(1)_BUILD_DIR) @ $(call MESSAGE,"Building $(1)") @ (if [ $(1) == kernel ]; then \ cmake --build $($(1)_BUILD_DIR); \ else \ if [ $(1) == bootloader ]; then \ if [ ! -d $(kernel_KEYPATH) ]; then \ mkdir -p $(kernel_KEYPATH); \ fi; \ if [ ! -f $(kernel_KEYPATH)/*private.pem -o ! -f $(kernel_KEYPATH)/*public.pem ]; then \ $(call MESSAGE,"Generating kernel key pair ..."); \ python3 $(SIGNTOOL) keygen -k $(kernel_KEYPATH) -t rsa-2048; \ fi; \ $(call MESSAGE,"Attach kernel public key"); \ python3 $(SIGNTOOL) getpub -k $(kernel_KEYPATH)/rsa2048-private.pem > $($(1)_DIR)/bl2/ext/mcuboot/rsa_pub_key.h; \ if [ ! -d $($(1)_KEYPATH) ]; then \ $(call MESSAGE,"Generating $(1) key pair ..."); \ mkdir -p $($(1)_KEYPATH); \ fi; \ if [ ! -f $($(1)_KEYPATH)/*private.pem -o ! -f $($(1)_KEYPATH)/*public.pem ]; then \ python3 $(SIGNTOOL) keygen -k $($(1)_KEYPATH) -t rsa-3072; \ fi; \ fi; \ cmake $($(1)_DIR)/ -G"Unix Makefiles" -DBOARD=$(BOARD) -DPRODUCT=$(PRODUCT) -DCOMPILER=$(ARCH)-gcc; \ cmake --build ./ -- install; \ fi \ ) endef # Macro of Building Targets # $(1): Target define GENERATE_MAKE_TARGET .PHONY: $(1) $(1): toolchain @ $(call MESSAGE,"Building $(1)") @ (cd $($(1)_DIR) && $(MAKE)) endef # Macro of Menuconfig Targets # $(1): Target # $(2): Target suffix define GENERATE_MENUCONFIG_TARGET .PHONY: $(if $(2),$(1)-$(2),$(1)) $(if $(2),$(1)-$(2),$(1)): $($(1)_BUILD_DIR) @ cmake --build $($(1)_BUILD_DIR) --target $(2) endef # Macro of Building Dist Targets # $(1): Target # $(2): Target suffix define GENERATE_DIST_TARGET .PHONY: $(if $(2),$(1)-$(2),$(1)) $(if $(2),$(1)-$(2),$(1)): $(1) $(DIST_DIR) @ if [ -f $($(1)_BIN) ]; then install -p $($(1)_BIN) $($(1)_$(2)_BIN); fi @ if [[ $(PRODUCT) == "communication" ]]; then \ if [[ "1" == "$(SIMULATION)" ]] && \ [[ -x ./communication/scripts/comm_package_entry.sh ]]; then \ ./communication/scripts/comm_package_entry.sh simulation; \ elif [[ -x ./communication/scripts/comm_package_entry.sh ]]; then \ ./communication/scripts/comm_package_entry.sh; \ else \ echo "Create communication flash file failed!"; \ fi; \ fi; endef # Macro of Cleaning Targets # $(1): Target # $(2): Target suffix define GENERATE_CLEAN_TARGET .PHONY: $(if $(2),$(1)-$(2),$(1)) $(if $(2),$(1)-$(2),$(1)): @ $(call MESSAGE,"Cleaning $(1)") @ if [ -d $($(1)_BUILD_DIR) ]; then cmake --build $($(1)_BUILD_DIR) --target $(2); fi endef # Macro of Signing Image # $(1): target binary # $(2): header length define SIGN_IMAGE if [ $(1) == bootloader ]; then \ python3 $(SIGNTOOL) sign_bl2 -P $($(1)_KEYPATH) -H $(2) $($(1)_BIN) $($(1)_dist_BIN); \ else \ python3 $(SIGNTOOL) sign -k $($(1)_KEYPATH)/rsa2048-private.pem -H $(2) $($(1)_BIN) $($(1)_dist_BIN); \ fi endef # Macro of Segment Image # $(1): segment makefile define SEGMENT_IMAGE @ if [ -f $(1) ]; then \ make -f $(1) scatter; \ fi endef ################################################################ # Targets ################################################################ BUILDSYSTEM_TARGETS := kernel CMAKE_TARGETS := kernel MAKE_TARGETS := MENUCONFIG_TARGETS := kernel INSTALL_TARGETS := $(CMAKE_TARGETS) ALL_TARGETS := $(CMAKE_TARGETS) $(MAKE_TARGETS) DIST_TARGETS := $(addsuffix -dist,$(INSTALL_TARGETS)) CLEAN_TARGETS := $(addsuffix -clean,$(ALL_TARGETS)) ############################################################################################################################### # $(OUTPUT_DIR)/scatter_load.mk is not present by default. when segmentation functionality is required, # the CMakeLists within the module needing segmentation will invoke gen_scatter_lib.sh to generate $(OUTPUT_DIR)/scatter_load.mk, # which includes segmentation rules, thereby triggering this functionality. ############################################################################################################################### .PHONY: dist dist: all $(DIST_TARGETS) $(call SEGMENT_IMAGE,$(OUTPUT_DIR)/scatter_load.mk) # $(call SIGN_IMAGE,bootloader,512) # $(call SIGN_IMAGE,kernel,1024) $(DIST_DIR): @ install -d $(DIST_DIR) .PHONY: all all: $(ALL_TARGETS) .PHONY: clean clean: $(CLEAN_TARGETS) @ if [[ $(PRODUCT) == "communication" ]]; then \ if [[ "1" == "$(SIMULATION)" ]] && \ [[ -x ./communication/scripts/comm_package_entry.sh ]]; then \ ./communication/scripts/comm_package_entry.sh simulation clean; \ elif [[ -x ./communication/scripts/comm_package_entry.sh ]]; then \ ./communication/scripts/comm_package_entry.sh clean; \ else \ echo "Create communication flash file failed!"; \ fi; \ fi; ifndef_any_of = $(filter undefined,$(foreach v,$(1),$(origin $(v)))) .PHONY: distclean distclean: ifeq ($(call ifndef_any_of,ARCH SOC BOARD PRODUCT),) @ if [ -d $(BUILD_DIR) ]; then rm -rf $(BUILD_DIR); fi else @ if [ -d $(OUTPUT_DIR) ]; then rm -rf $(OUTPUT_DIR); fi endif .PHONY: project project: ifeq ($(call ifndef_any_of,ARCH SOC BOARD PRODUCT),) @ $(call MESSAGE,"Building $(ARCH) $(SOC) $(BOARD) $(PRODUCT)") else $(error Please execute source scripts/env.sh) endif ################################################################ ## Target command:make [docs|docs-clean] DOCS_ARCH=[arm|arm64|riscv|xtensa] ################################################################ .PHONY: docs docs: @ if [ ! -d $($@_BUILD_DIR) ]; then mkdir -p $($@_BUILD_DIR); fi @ if [ ! -d $($@_DIR) ]; then \ echo "$($@_DIR) is not exist,please set project first with: source scripts/env.sh"; \ else \ echo "Generated docs in $($@_BUILD_DIR) from $($@_DIR)."; \ (rm -rf $($@_BUILD_DIR)/CMakeCache.txt \ && cd $($@_BUILD_DIR) \ && cmake $($@_DIR) -DARCH_NAME=$(DOCS_ARCH) \ -DCMAKE_TOOLCHAIN_FILE=$(build_DIR)/cmake/toolchains/$(DOCS_ARCH)_compiler.cmake \ && make); \ fi .PHONY: docs-clean docs-clean: ifeq ($(call ifndef_any_of,ARCH SOC BOARD PRODUCT),) @ if [ -d $(docs_BUILD_DIR) ]; then rm -rf $(docs_BUILD_DIR); fi else @ if [ -d $(OUTPUT_DIR)/docs ]; then rm -rf $(OUTPUT_DIR)/docs; fi endif ################################################################ # Respective Targets ################################################################ # Buildsystem Targets $(foreach target,$(BUILDSYSTEM_TARGETS),$(eval $(call GENERATE_BUILDSYSTEM,$(target)))) # CMake Build Targets $(foreach target,$(CMAKE_TARGETS),$(eval $(call GENERATE_CMAKE_TARGET,$(target)))) # Build Targets $(foreach target,$(MAKE_TARGETS),$(eval $(call GENERATE_MAKE_TARGET,$(target)))) # Menuconfig Targets #$(foreach target,$(MENUCONFIG_TARGETS),$(eval $(call GENERATE_MENUCONFIG_TARGET,$(target),menuconfig))) # Dist Targets $(foreach target,$(ALL_TARGETS) fw,$(eval $(call GENERATE_DIST_TARGET,$(target),dist))) # Clean Targets $(foreach target,$(ALL_TARGETS),$(eval $(call GENERATE_CLEAN_TARGET,$(target),clean))) .PHONY: toolchain toolchain: project @ ./scripts/prepare_toolchain.sh .PHONY: menuconfig menuconfig: toolchain $(kernel_BUILD_DIR) @ cmake --build $(kernel_BUILD_DIR) --target $@ .PHONY: list-configs list-configs: @ ls $(board_DIR)/*defconfig 2>/dev/null | \ xargs -n1 basename | sort %defconfig:config-clean toolchain @ make $(kernel_BUILD_DIR) BOARD_SPEC_CONFIG=$@ @ echo "configuration $@ written to $(kernel_BUILD_DIR)/.config" .PHONY: config config: config-clean toolchain @ make $(kernel_BUILD_DIR) BOARD_SPEC_CONFIG=defconfig @ echo "configuration defconfig written to $(kernel_BUILD_DIR)/.config" .PHONY: config-clean config-clean: @ if [ -f $(kernel_BUILD_DIR)/build.ninja ]; then \ rm -f $(kernel_BUILD_DIR)/build.ninja; \ fi .PHONY: package package: @ if [ -f ./scripts/package/$(SOC)_gen_package.sh ]; then \ ./scripts/package/$(SOC)_gen_package.sh $(type); \ fi .PHONY: backtrace backtrace: @ make && \ make -f $(build_DIR)/symtable.mk backtrace && \ make && \ make -f $(build_DIR)/symtable.mk clean .PHONY: release release: @ ./scripts/gen_release.sh %: @ if [ -f $(board_DIR)/$*_defconfig ]; then \ $(MAKE) $*_defconfig; \ $(MAKE); \ else \ echo "Invalid target:$*"; \ fi