# 调试,打印当前 MAKE 运行环境和配置信息
ifeq ($(SHOW_MAKE_EVENT), TRUE)
$(info MAKEFILES:$(MAKEFILES))
$(info MAKEFILES_LIST:$(MAKEFILES_LIST))
$(info SHELL:$(SHELL))
$(info MAKESHELL:$(MAKESHELL))
$(info MAKE:$(MAKE))
$(info MAKELEVEL:$(MAKELEVEL))
$(info MAKECMDGOALS:$(MAKECMDGOALS))
$(info SUFFIXES:$(SUFFIXES))
$(info LIBPATTERNS:$(.LIBPATTERNS))
$(info Make $(TARGET_OBJ): $(CURDIR))
endif

# 定义 Make 解析命令的 bash
SHELL	:= /bin/bash

# 构建信息开关,是否显示 gcc、ld 等命令执行的命令行消息,默认关闭
ENABLE_MAKE_LOG ?= FALSE

# 调试信息分离开关,默认开启
TARGET_STRIP ?= TRUE

ifeq ($(TARGET_TYPE), KO)
ARM64_CROSS_LD 			:=	aarch64-linux-gnu-ld
LINUX_CROSS_LD			:=  ld
else
ARM64_CROSS_LD 			:=	$(ARM64_CROSS_CC)
LINUX_CROSS_LD 			:=	$(CC)
endif

# 检查必要的环境变量是否设置
ifeq ($(PLAT_ARM64), TRUE)

# ARM64 SDK 环境变量
ifeq ($(SDKTARGETSYSROOT), )
$(error Unknown SDKTARGETSYSROOT environment Of [$(SDKTARGETSYSROOT)], It's must be set to current environment used <export SDKTARGETSYSROOT=...>)
else
ifneq ($(SDKTARGETSYSROOT), $(wildcard $(SDKTARGETSYSROOT)))
$(error Directory $(SDKTARGETSYSROOT) not exists, Please check it first.)
endif
endif

endif

ifeq ($(TARGET_OBJ), DRV)

# 华晨 ARM64 平台已经编译成功的内核路径,供编译驱动使用
ifeq ($(HUACHENG_ARM64_KERNEL), )
$(error Unknown HUACHENG_ARM64_KERNEL environment Of [$(HUACHENG_ARM64_KERNEL)], It's must be set to current environment used <export HUACHENG_ARM64_KERNEL=...>)
else
ifneq ($(HUACHENG_ARM64_KERNEL), $(wildcard $(HUACHENG_ARM64_KERNEL)))
$(error Directory $(HUACHENG_ARM64_KERNEL) not exists, Please check it first.)
endif
endif

# 华晨 LINUX 平台已经编译成功的内核路径,供编译驱动使用
ifeq ($(HUACHENG_LINUX_KERNEL), )
$(error Unknown HUACHENG_LINUX_KERNEL environment Of [$(HUACHENG_LINUX_KERNEL)], It's must be set to current environment used <export HUACHENG_LINUX_KERNEL=...>)
else
ifneq ($(HUACHENG_LINUX_KERNEL), $(wildcard $(HUACHENG_LINUX_KERNEL)))
$(error Directory $(HUACHENG_LINUX_KERNEL) not exists, Please check it first.)
endif
endif

endif

# @符号添加在执行的命令前,则该命令不会在控制台上打印这条命令执行的信息
ifeq ($(ENABLE_MAKE_LOG), TRUE)
MLOG	:=
else
MLOG	?= @
endif

# 判断构建模式 debug/release
ifeq ($(DEBUG), TRUE)
TARGET_OUT_DIR		?= debug/
else
TARGET_OUT_DIR		?= release/
endif

# 设置安装路径的相对路径
ifeq ($(DIR), )
INSTALL_ROOT 	:= $(addprefix ../,../_install/$(TARGET_OUT_DIR))
else
INSTALL_ROOT 	:= $(addprefix ../,$(DIR)/$(TARGET_OUT_DIR))
endif

# 定义常用命令
RM = rm -rf
MKDIR = mkdir -p
CP = cp -f

ifeq ($(findstring bash, $(SHELL)),)
ECHO_COLOR = echo
else
ECHO_COLOR = echo -e
endif

# 根据环境变量获取内核路径
ifeq ($(TARGET_OBJ), DRV)
ARM64_KERNEL		:= $(HUACHENG_ARM64_KERNEL)
LINUX_KERNEL		:= $(HUACHENG_LINUX_KERNEL)
endif

# 设置 ARM64 平台 SDK 头文件和库文件路径
ARM64_SDK_INCLUDE 	:= $(SDKTARGETSYSROOT)/usr/include
ARM64_SDK_LIBDIR  	:= $(SDKTARGETSYSROOT)/usr/lib

# 设置平台安装子目录
CPU_ARM64_DIR		:= ARM64
CPU_LINUX_DIR		:= LINUX

# 根据类型设置生成目标的扩展名
ifeq ($(TARGET_TYPE), KO)
TARGET_EXT := .ko
else ifeq ($(TARGET_TYPE), DLL)
TARGET_EXT := .so
else ifeq ($(TARGET_TYPE), SDK)
TARGET_EXT := .so
else ifeq ($(TARGET_TYPE), LIB)
TARGET_EXT := .a
else ifeq ($(TARGET_TYPE), EXE)
TARGET_EXT := .exe
else ifeq ($(TARGET_TYPE), SH)
UNMAKE_PROCESS := TRUE
else
$(error Unknown TARGET_TYPE Value Of [$(TARGET_TYPE)], It's Must Be Set Of KO/EXE/DLL/LIB/SDK)
endif

# 如果生成类型为库文件,则在生成目标的文件名前加上 lib 前缀
ifeq ($(TARGET_TYPE), LIB)
TARGET_PREFIX	:= lib
else ifeq ($(TARGET_TYPE), SDK)
TARGET_PREFIX	:= lib
else
TARGET_PREFIX	:=
endif

# 定义各个类型关键字段控制台显示颜色
ifneq ($(MAKE_TARGET), )
MAKECMD_COLOR		:= \033[36;48m\033[1m$(shell env printf "%-10s" {$(MAKE_TARGET)}) \033[0m
else
MAKECMD_COLOR		:=
endif

CLEAN_COLOR					:= $(MAKECMD_COLOR)\033[31;48m\033[1m[CLEAN]\033[0m
PATH_COLOR					:= \033[34;48m\033[1m($(CURDIR))\033[0m
INSTALL_PATH_COLOR			:= \033[34;48m\033[1m(TO $(INSTALL_ROOT))\033[0m
INSTALL_COLOR				:= \033[36;48m\033[1m[INSTALL]\033[0m
PRE_INSTALL_COLOR			:= \033[36;48m\033[1m[PRE INSTALL]\033[0m
INSTALL_USER_ITEM_COLOR		:= \033[36;48m\033[1m[INSTALL USER ITEMS]\033[0m
INSTALL_MULT_PLAT_COLOR		:= \033[36;48m\033[1m[INSTALL MULTPLATFORM ITEMS]\033[0m
INSTALL_IDK_ITEM_COLOR		:= \033[36;48m\033[1m[INSTALL IDK ITEMS]\033[0m


TARGET_TYPE_COLOR		:= \t\033[35;48m\033[1m$(shell env printf "%5s" [$(TARGET_TYPE)])\033[0m
TARGET_OBJ_COLOR		:= \t\033[34;48m\033[1m$(shell env printf "%5s" [$(TARGET_OBJ)])\033[0m
TARGET_MIX_COLOR		:= $(TARGET_TYPE_COLOR)$(TARGET_OBJ_COLOR)
PLAT_ARM64_COLOR		:= $(MAKECMD_COLOR)\033[32;48m\033[1m$(shell env printf "%-8s" [ARM64])\033[0m$(TARGET_MIX_COLOR)
PLAT_LINUX_COLOR		:= $(MAKECMD_COLOR)\033[32;48m\033[1m$(shell env printf "%-8s" [LINUX])\033[0m$(TARGET_MIX_COLOR)

# debug 模式 gcc 以 g3 参数添加调试信息
ifeq ($(DEBUG), TRUE)
DEBUG_CFLAGS 	:= -g3
endif

# 设置 gcc 编译优化等级参数
#DEBUG_CFLAGS 	+= -O2

LINUX_EXTFLAG 	+= $(DEBUG_CFLAGS)

# 如果视编译警告为错误,开启此开关
ifeq ($(DISABLE_WARRING), TRUE)
LINUX_EXTFLAG += -w
endif

TARGET_BOX ?= $(TARGET_NAME)

# 设置编译参数
ifeq ($(TARGET_OBJ), DRV)

ifeq ($(PLAT_LINUX), TRUE)
LINUX_SYSTEM = $(shell $(CC) -print-file-name=include)
endif

ifeq ($(PLAT_ARM64), TRUE)
ARM64_SYSTEM = $(shell $(ARM64_CROSS_CC) -print-file-name=include)
endif

# linux 内核模块编译参数,提取自 x86 模块编译命令行
LINUX_DRV_CFLAGS := -nostdinc -isystem $(LINUX_SYSTEM) \
					-D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing \
					-fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security \
					-std=gnu89 -fno-PIE -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -falign-jumps=1 \
					-falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup \
					-mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args \
					-DCONFIG_X86_X32_ABI -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 \
					-DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 \
					-DCONFIG_AS_AVX512=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare \
					-fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register \
					-DRETPOLINE -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation \
					-Wno-format-overflow -Wno-int-in-bool-context -Wno-attribute-alias \
					--param=allow-store-data-races=0 -DCC_HAVE_ASM_GOTO -Wframe-larger-than=1024 \
					-fstack-protector-strong -Wno-unused-but-set-variable -Wno-unused-const-variable \
					-fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments \
					-g -gdwarf-4 -pg -mfentry -DCC_USING_FENTRY -Wdeclaration-after-statement -Wno-pointer-sign \
					-fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack \
					-Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -Werror=incompatible-pointer-types \
					-DMODULE  -DKBUILD_BASENAME='"$(TARGET_NAME).mod"'  -DKBUILD_MODNAME='"$(TARGET_NAME)"'

LINUX_EXTFLAG 	+= $(DEBUG_CFLAGS) $(LINUX_DRV_CFLAGS) \
					-I$(LINUX_KERNEL)/arch/x86/include \
					-I$(LINUX_KERNEL)/arch/x86/include/generated/uapi \
					-I$(LINUX_KERNEL)/arch/x86/include/generated  \
					-I$(LINUX_KERNEL)/include -I$(LINUX_KERNEL)/arch/x86/include/uapi \
					-I$(LINUX_KERNEL)/include/uapi \
					-I$(LINUX_KERNEL)/include/generated/uapi \
					-include $(LINUX_KERNEL)/include/linux/kconfig.h

# ARM64 linux 内核模块编译参数,提取自 arm 模块编译命令行
ARM64_DRV_CFLAGS := -nostdinc -isystem $(ARM64_SYSTEM) -mabi=lp64 -Werror=designated-init \
					-D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing \
					-fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 \
					-fno-PIE -mgeneral-regs-only -DCONFIG_AS_LSE=1 -fno-asynchronous-unwind-tables -mpc-relative-literal-loads \
					-fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow \
					-Wno-int-in-bool-context -O2 --param=allow-store-data-races=0 -DCC_HAVE_ASM_GOTO -Wframe-larger-than=2048 \
					-fno-stack-protector -Wno-unused-but-set-variable -Wno-unused-const-variable -fno-omit-frame-pointer \
					-fno-optimize-sibling-calls -fno-var-tracking-assignments -g -Wdeclaration-after-statement -Wno-pointer-sign \
					-fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack \
					-Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -Werror=incompatible-pointer-types  \
					-DKBUILD_BASENAME='"$(TARGET_NAME).mod"'  -DKBUILD_MODNAME='"$(TARGET_NAME)"' -DMODULE -mcmodel=large

ARM64_EXTFLAG 	+= $(DEBUG_CFLAGS) $(ARM64_DRV_CFLAGS) \
					-I$(ARM64_KERNEL)/arch/arm64/include \
					-I$(ARM64_KERNEL)/arch/arm64/include/generated/uapi \
					-I$(ARM64_KERNEL)/arch/arm64/include/generated  \
					-I$(ARM64_KERNEL)/include \
					-I$(ARM64_KERNEL)/arch/arm64/include/uapi \
					-I$(ARM64_KERNEL)/include/uapi \
					-I$(ARM64_KERNEL)/include/generated/uapi \
					-include $(ARM64_KERNEL)/include/linux/kconfig.h

# x86 Linux 内核模块链接参数,提取自 x86 模块连接命令行
LINUX_DRV_LDFLAGS	= -r -m elf_x86_64  -z max-page-size=0x200000 -T $(LINUX_KERNEL)/scripts/module-common.lds --build-id
# arm64 Linux 内核模块链接参数,提取自 arm64 模块连接命令行
ARM64_DRV_LDFLAGS 	= -EL -r -maarch64linux -T $(ARM64_KERNEL)/scripts/module-common.lds  --build-id
else ifeq ($(TARGET_OBJ), APP)
# 用户态模块编译参数
ARM64_EXTFLAG += $(DEBUG_CFLAGS) -I$(ARM64_SDK_INCLUDE)

# show all warring
CFLAGS += -Wall

# 设置 ARM64 交叉编译链接目录
ARM64_DRV_LDFLAGS		:= --sysroot=${SDKTARGETSYSROOT}
else ifeq ($(TARGET_OBJ), SH)
else
$(error Unknown TARGET_OBJ Value Of [$(TARGET_OBJ)], It's Must Be Set Of APP/DRV)
endif

# 根据 debug/release 模式设置目录名称
ifeq ($(DEBUG), TRUE)
BUILD_DIR		:= debug
else
BUILD_DIR		:= release
endif

# 编译生成中间文件存放临时子目录
OUTPUT_DIR 		:= ./.build/

# 编译中间文件存放相对路径
ARM64_DIR		:= $(OUTPUT_DIR)$(TARGET_NAME)_$(TARGET_TYPE)_$(TARGET_OBJ)_arm64_$(BUILD_DIR)
LINUX_DIR		:= $(OUTPUT_DIR)$(TARGET_NAME)_$(TARGET_TYPE)_$(TARGET_OBJ)_linux_$(BUILD_DIR)

# 设置安装路径
ifeq ($(TARGET_TYPE), SDK)
LINUX_PUBLISH_DIR		:= $(INSTALL_ROOT)/sdk/$(CPU_LINUX_DIR)/
PUBLISH_DEBUG_DIR	:= $(INSTALL_ROOT)/sdk.debug/$(CPU_LINUX_DIR)/
else
ifeq ($(TARGET_BOX), )
ARM64_PUBLISH_DIR	:= $(INSTALL_ROOT)/targets/$(CPU_ARM64_DIR)/$(TARGET_BOX)/

ifeq ($(LINUX_USER_INS_DIR), )
LINUX_PUBLISH_DIR	:= $(INSTALL_ROOT)/targets/$(CPU_LINUX_DIR)/$(TARGET_BOX)/
else
LINUX_PUBLISH_DIR	:= $(INSTALL_ROOT)/$(LINUX_USER_INS_DIR)/$(CPU_LINUX_DIR)/$(TARGET_BOX)/
endif

ARM64_PUBLISH_DEBUG_DIR	:= $(INSTALL_ROOT)/targets.debug/$(CPU_ARM64_DIR)/$(TARGET_BOX)/

ifeq ($(LINUX_USER_INS_DIR), )
PUBLISH_DEBUG_DIR	:= $(INSTALL_ROOT)/targets.debug/$(CPU_LINUX_DIR)/$(TARGET_BOX)/
else
PUBLISH_DEBUG_DIR	:= $(INSTALL_ROOT)/$(LINUX_USER_INS_DIR).debug/$(CPU_LINUX_DIR)/$(TARGET_BOX)/
endif

else
ARM64_PUBLISH_DIR	:= $(INSTALL_ROOT)/targets/$(CPU_ARM64_DIR)/$(TARGET_BOX)-arm64/

ifeq ($(LINUX_USER_INS_DIR), )
LINUX_PUBLISH_DIR	:= $(INSTALL_ROOT)/targets/$(CPU_LINUX_DIR)/$(TARGET_BOX)-linux/
else
LINUX_PUBLISH_DIR	:= $(INSTALL_ROOT)/$(LINUX_USER_INS_DIR)/$(CPU_LINUX_DIR)/$(TARGET_BOX)-linux/
endif
ARM64_PUBLISH_DEBUG_DIR	:= $(INSTALL_ROOT)/targets.debug/$(CPU_ARM64_DIR)/$(TARGET_BOX)-arm64/

ifeq ($(LINUX_USER_INS_DIR), )
PUBLISH_DEBUG_DIR	:= $(INSTALL_ROOT)/targets.debug/$(CPU_LINUX_DIR)/$(TARGET_BOX)-linux/
else
PUBLISH_DEBUG_DIR	:= $(INSTALL_ROOT)/$(LINUX_USER_INS_DIR).debug/$(CPU_LINUX_DIR)/$(TARGET_BOX)-linux/
endif
endif

endif

# 定义编译目标
BUILD_TARGET :=

ifneq ($(UNMAKE_PROCESS), TRUE)

# 定义最终生成目标文件名
ARM64_TARGET			:= $(TARGET_PREFIX)$(TARGET_NAME)-$(ARM64_OBJ_TARGET)$(TARGET_EXT)
LINUX_TARGET			:= $(TARGET_PREFIX)$(TARGET_NAME)-$(LINUX_OBJ_TARGET)$(TARGET_EXT)

# ARM64 平台生成目标、编译参数、链接参数、依赖库
ifeq ($(PLAT_ARM64), TRUE)
	BUILD_TARGET 		+= $(ARM64_TARGET)
	ARM64_CFLAGS		:= $(PLAT_ARM64_CFLAGS) -DPLATFORM_ARM64 $(ARM64_EXTFLAG)
	ARM64_LDFLAGS 		:= $(PLAT_ARM64_LDFLAGS) $(ARM64_DRV_LDFLAGS) -L ./debug
	ARM64_LIBFLAGS		:= $(PLAT_ARM64_LIBFLAGS)
	ARM64_LIBS			:= $(PLAT_ARM64_LIBS)
endif

# ARM64 平台生成目标、编译参数、链接参数、依赖库
ifeq ($(PLAT_LINUX), TRUE)
	BUILD_TARGET 		+= $(LINUX_TARGET)
	LINUX_CFLAGS		:= $(PLAT_LINUX_CFLAGS) -DPLATFORM_LINUX $(LINUX_EXTFLAG)
	LINUX_LDFLAGS		:= $(PLAT_LINUX_LDFLAGS) $(LINUX_DRV_LDFLAGS) -L ./debug
	LINUX_LIBFLAGS		:= $(PLAT_LINUX_LIBFLAGS)
	LINUX_LIBS			:= $(PLAT_LINUX_LIBS)
endif

# 根据源文件推算出生成目标的依赖项
ifeq ($(PLAT_ARM64), TRUE)
PLAT_ARM64_OBJS  	:= $(PLAT_ARM64_SRCS:%.c=$(ARM64_DIR)/%.o)
PLAT_ARM64_OBJS  	+= $(PLAT_ARM64_AS_SRCS:%.s=$(ARM64_DIR)/%.o)
PLAT_ARM64_DEPS  	:= $(PLAT_ARM64_SRCS:%.c=$(ARM64_DIR)/%.d)
else
PLAT_ARM64_OBJS 	:=
PLAT_ARM64_DEPS  	:=
endif

ifeq ($(PLAT_LINUX), TRUE)
PLAT_LINUX_OBJS  	:= $(PLAT_LINUX_SRCS:%.c=$(LINUX_DIR)/%.o)
PLAT_LINUX_OBJS  	+= $(PLAT_LINUX_AS_SRCS:%.s=$(LINUX_DIR)/%.o)
PLAT_LINUX_DEPS  	:= $(PLAT_LINUX_SRCS:%.c=$(LINUX_DIR)/%.d)
else
PLAT_LINUX_OBJS 	:=
PLAT_LINUX_DEPS  	:=
endif

# 构建系统最终需要生成的目标,包含 ARM64 和 Linux 平台
ALL_OBJS += $(PLAT_ARM64_OBJS) $(PLAT_LINUX_OBJS)
ALL_DEPS += $(PLAT_ARM64_DEPS) $(PLAT_LINUX_DEPS)

ifneq ($(MAKECMDGOALS), clean)
ifneq ($(MAKECMDGOALS), cleanall)
ifneq ($(strip $(ALL_DEPS)),)
-include $(ALL_DEPS)
endif
endif
endif
# ifneq $(UNMAKE_PROCESS)
endif

ifeq ($(UNMAKE_PROCESS), TRUE)
BUILD_TARGET	:=
endif

ifneq ($(OPT), clean)
ifneq ($(OPT), install)
ifneq ($(MAKECMDGOALS), clean)
ifneq ($(MAKECMDGOALS), cleanall)
ifeq ($(MAKE_TARGET), )
$(info  ---------------------------------------------------------------------)
$(info  |    CPU     | TYPE | OBJECT |  Command   |      Source/Target      |)
$(info  ---------------------------------------------------------------------)
else
$(info  ------------------------------------------------------------------------------)
$(info  |  Name  |    CPU     | TYPE | OBJECT |  Command   |         Source          |)
$(info  ------------------------------------------------------------------------------)
endif
endif
endif
endif
endif

.PHONY : all
all: $(BUILD_TARGET)
# Build ARM64
ifeq ($(PLAT_ARM64), TRUE)
$(ARM64_TARGET): $(PLAT_ARM64_OBJS)
# 创建构建需要的目录结构
	-@test -d $(TARGET_OUT_DIR) || $(MKDIR) $(TARGET_OUT_DIR)
ifeq ($(TARGET_TYPE), LIB)
# 打包生成库文件
	@$(ECHO_COLOR) "$(PLAT_ARM64_COLOR)   AR            $@"
	$(MLOG)$(ARM64_CROSS_AR) $(ARM64_LIBFLAGS) $(TARGET_OUT_DIR)$@ $+ $(ARM64_LIBS)
else
# 链接生成可执行文件
	@$(ECHO_COLOR) "$(PLAT_ARM64_COLOR)   LD            $@"
	$(MLOG)$(ARM64_CROSS_LD) -o $(TARGET_OUT_DIR)$@ $(ARM64_LDFLAGS) $+ $(ARM64_LIBS)
ifeq ($(TARGET_STRIP), TRUE)
# 将目标的调试信息复制到另外一个新文件中
	@$(ECHO_COLOR) "$(PLAT_ARM64_COLOR)   OBJCOPY       $@.debug"
	$(MLOG)$(ARM64_CROSS_OBJCOPY) --only-keep-debug $(TARGET_OUT_DIR)$@ $(TARGET_OUT_DIR)/$@.debug
# 清理掉目标中的调试信息
	@$(ECHO_COLOR) "$(PLAT_ARM64_COLOR)   STRIP         $@"
	$(MLOG)$(ARM64_CROSS_STRIP) -g $(TARGET_OUT_DIR)$@
# 建立目标文件和调试信息文件的管理,供 gdb 自动识别
	@$(ECHO_COLOR) "$(PLAT_ARM64_COLOR)   OBJCOPY       $@"
	$(MLOG)$(ARM64_CROSS_OBJCOPY) --add-gnu-debuglink=$(TARGET_OUT_DIR)$@.debug $(TARGET_OUT_DIR)$@
endif
endif
# C 源文件编译规则
$(ARM64_DIR)/%.o : %.c
	-@test -d $(dir $@) || $(MKDIR) $(dir $@)
	@$(ECHO_COLOR) "$(PLAT_ARM64_COLOR)   CC            $<"
	$(MLOG)$(ARM64_CROSS_CC) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" $(ARM64_CFLAGS) -o $@ -c $<

# 汇编文件编译规则
$(ARM64_DIR)/%.o : %.s
	@$(ECHO_COLOR) "$(PLAT_ARM64_COLOR)   CC            $<"
	$(MLOG)$(ARM64_CROSS_CC) -c $< -o $@
endif

# Build LINUX Board
ifeq ($(PLAT_LINUX), TRUE)
$(LINUX_TARGET): $(PLAT_LINUX_OBJS)
	-@test -d $(TARGET_OUT_DIR) || $(MKDIR) $(TARGET_OUT_DIR)

ifeq ($(TARGET_TYPE), LIB)
# 打包生成库文件
	@$(ECHO_COLOR) "$(PLAT_LINUX_COLOR)   AR            $@"
	$(MLOG)$(AR) $(LINUX_LIBFLAGS) $(TARGET_OUT_DIR)$@ $+ $(LINUX_LIBS)
else
# 链接生成可执行文件
	@$(ECHO_COLOR) "$(PLAT_LINUX_COLOR)   LD            $@"
	$(MLOG)$(LINUX_CROSS_LD) -o $(TARGET_OUT_DIR)$@ $(LINUX_LDFLAGS) $+ $(LINUX_LIBS)
ifeq ($(TARGET_STRIP), TRUE)
# 将目标的调试信息复制到另外一个新文件中
	@$(ECHO_COLOR) "$(PLAT_LINUX_COLOR)   OBJCOPY       $@.debug"
	$(MLOG)$(OBJCOPY) --only-keep-debug $(TARGET_OUT_DIR)$@ $(TARGET_OUT_DIR)$@.debug
# 清理掉目标中的调试信息
	@$(ECHO_COLOR) "$(PLAT_LINUX_COLOR)   STRIP         $@"
	$(MLOG)$(STRIP) -g $(TARGET_OUT_DIR)$@
# 建立目标文件和调试信息文件的管理,供 gdb 自动识别
	@$(ECHO_COLOR) "$(PLAT_LINUX_COLOR)   OBJCOPY       $@"
	$(MLOG)$(OBJCOPY) --add-gnu-debuglink=$(TARGET_OUT_DIR)$@.debug $(TARGET_OUT_DIR)$@
endif
endif

# C 源文件编译规则
$(LINUX_DIR)/%.o : %.c
	-@test -d $(dir $@) || $(MKDIR) $(dir $@)
	@$(ECHO_COLOR) "$(PLAT_LINUX_COLOR)   CC            $<"
	$(MLOG)$(CC) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" $(LINUX_CFLAGS) -o $@ -c $<

# 汇编文件编译规则
$(LINUX_DIR)/%.o : %.s
	@$(ECHO_COLOR) "$(PLAT_LINUX_COLOR)   CC            $<"
	$(MLOG)$(CC) -c $< -o $@
endif

# 安装功能
.PHONY : install
install:
ifeq ($(INSTALL_ROOT), )
	$(error usage: make install DIR=<path>)
endif

ifneq ($(PLAT_ARM64_DONT_INSTALL), TRUE)
# ARM64 targets install
ifeq ($(PLAT_ARM64), TRUE)
	-@test -d $(ARM64_PUBLISH_DIR) || $(MKDIR) $(ARM64_PUBLISH_DIR)
	-@test -d $(ARM64_PUBLISH_DEBUG_DIR) || $(MKDIR) $(ARM64_PUBLISH_DEBUG_DIR)
ifneq ($(UNMAKE_PROCESS), TRUE)
	@$(ECHO_COLOR) "$(INSTALL_COLOR) $(PLAT_ARM64_COLOR) $(TARGET_OUT_DIR)$(ARM64_TARGET) $(ARM64_TARGET).debug $(INSTALL_PATH_COLOR)"
	@$(CP) $(TARGET_OUT_DIR)/$(ARM64_TARGET) $(ARM64_PUBLISH_DIR)
	@$(CP) $(TARGET_OUT_DIR)/$(ARM64_TARGET).debug $(ARM64_PUBLISH_DEBUG_DIR)
endif
ifneq ($(PLAT_ARM64_USER_INS_ITEMS), )
	@$(ECHO_COLOR) "$(INSTALL_USER_ITEM_COLOR) $(PLAT_ARM64_COLOR) $(notdir $(PLAT_ARM64_USER_INS_ITEMS)) $(INSTALL_PATH_COLOR)"
	@$(CP) $(PLAT_ARM64_USER_INS_ITEMS) $(ARM64_PUBLISH_DIR)
endif
endif
endif

ifneq ($(PLAT_LINUX_DONT_INSTALL), TRUE)
# LINUX board targets install
ifeq ($(PLAT_LINUX), TRUE)
	-@test -d $(LINUX_PUBLISH_DIR) || $(MKDIR) $(LINUX_PUBLISH_DIR)
	-@test -d $(PUBLISH_DEBUG_DIR) || $(MKDIR) $(PUBLISH_DEBUG_DIR)
ifneq ($(UNMAKE_PROCESS), TRUE)
	@$(ECHO_COLOR) "$(INSTALL_COLOR) $(PLAT_LINUX_COLOR) $(TARGET_OUT_DIR)$(LINUX_TARGET) $(LINUX_TARGET).debug $(INSTALL_PATH_COLOR)"
	@$(CP) $(TARGET_OUT_DIR)/$(LINUX_TARGET) $(LINUX_PUBLISH_DIR)
	@$(CP) $(TARGET_OUT_DIR)/$(LINUX_TARGET).debug $(PUBLISH_DEBUG_DIR)
endif
ifneq ($(PLAT_LINUX_USER_INS_ITEMS), )
	@$(ECHO_COLOR) "$(INSTALL_USER_ITEM_COLOR) $(PLAT_LINUX_COLOR) $(notdir $(PLAT_LINUX_USER_INS_ITEMS)) $(INSTALL_PATH_COLOR)"
	@$(CP) $(PLAT_LINUX_USER_INS_ITEMS) $(LINUX_PUBLISH_DIR)
endif
ifneq ($(USER_MULTILE_PLATFORM_HEAD_ITEMS), )
	@$(ECHO_COLOR) "$(INSTALL_MULT_PLAT_COLOR) $(PLAT_LINUX_COLOR) $(notdir $(USER_MULTILE_PLATFORM_HEAD_ITEMS)) $(INSTALL_PATH_COLOR)"
	@$(CP) $(USER_MULTILE_PLATFORM_HEAD_ITEMS) $(SDK_HEADFILE_PUBLIST_DIR)
endif
endif
endif

# end of ($(DONT_INSTALL), TRUE)

# 清理功能
.PHONY : cleanall
cleanall:
	@$(ECHO_COLOR) "$(CLEAN_COLOR) $(PATH_COLOR) $(OUTPUT_DIR) $(BUILD_TARGET) $(USER_CLEAN_ITEMS) $(notdir $(DEPEND_LIB)) $(TARGET_OUT_DIR) *.debug"
	@-$(RM) $(TARGET_OUT_DIR) $(OUTPUT_DIR) $(BUILD_TARGET) $(notdir $(DEPEND_LIB)) $(USER_CLEAN_ITEMS) *.debug

.PHONY : clean
clean:
	@$(ECHO_COLOR) "$(CLEAN_COLOR) $(PATH_COLOR) $(ALL_OBJS) $(BUILD_TARGET) $(ALL_DEPS) $(USER_CLEAN_ITEMS) $(notdir $(DEPEND_LIB)) $(TARGET_OUT_DIR) *.debug"
	@-$(RM) $(TARGET_OUT_DIR) $(ALL_OBJS) $(BUILD_TARGET) $(ALL_DEPS) $(USER_CLEAN_ITEMS) $(notdir $(DEPEND_LIB)) *.debug