# PROTO_FORWARD BUILD SYSTEM
# 2026-03-27 (origin)
# 2026-08-28 (support customer build, sync from 1.97.x)
MAKEFLAGS += -r -R

.DEFAULT_GOAL := all

TARGET := proto_forward

ifdef CUSTOM
  BUILD_SRC_DIR := build/combined_src
  CUSTOM_SRC := ../customer/$(CUSTOM)/src
  $(info EMS Target Custom: $(CUSTOM))
else
  BUILD_SRC_DIR := .
endif

EMS_BUILD_DIR := build/mainline

WITH_OPC ?= 1

VERSION_YEAR     := $(shell date +%Y)
VERSION_MAJOR    := $(shell expr $(VERSION_YEAR) - 2018)
VERSION_MINOR    := $(shell date +%02V%u)
VERSION_REVISION := 0000

PACKAGE_VERSION  := $(shell jq -r '.version // empty' ../package.json 2>/dev/null)
CURRENT_BRANCH   := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
CURRENT_COMMIT   := $(shell git rev-parse --short HEAD 2>/dev/null)
BUILD_TIME := $(shell date +%Y%m%d%H%M)

ifdef CUSTOM
PROJECT_VERSION  := $(shell tail -n 1 ../customer/$(CUSTOM)/pro_changelog.md 2>/dev/null | cut -d ':' -f 1)
else
PROJECT_VERSION  := $(shell tail -n 1 ../pro_changelog.md 2>/dev/null | cut -d ':' -f 1)
endif

ifndef SOFT_VERSION
  ifneq ($(strip $(PACKAGE_VERSION)),)
    ifdef CUSTOM
      SOFT_VERSION := "$(PACKAGE_VERSION)_$(PROJECT_VERSION)_$(CURRENT_BRANCH)_$(CURRENT_COMMIT)_$(CUSTOM)"
    else
      SOFT_VERSION := "$(PACKAGE_VERSION)_$(PROJECT_VERSION)_$(CURRENT_BRANCH)_$(CURRENT_COMMIT)"
    endif
    PRODUCT_VERSION := "$(PACKAGE_VERSION).$(BUILD_TIME)"
  else
    $(warning .version not found in ../package.json)
    SOFT_VERSION := "$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_REVISION)"
    PRODUCT_VERSION := "$(VERSION_MAJOR).$(BUILD_TIME).Release"
  endif
endif

$(shell echo $(PRODUCT_VERSION) > version-for-ipkg) # IPK包使用

ifneq ($(strip $(PACKAGE_VERSION)),)
MAJOR_PRO_VERSION := "$(PACKAGE_VERSION)_$(PROJECT_VERSION)"
else
MAJOR_PRO_VERSION := "$(VERSION_MAJOR).$(VERSION_MINOR)"
endif

$(shell echo $(PRODUCT_VERSION) > version.log) # 生产elf的时候添加版本使用

ifdef NON_OPENWRT_LED
SUPPORT_LED := $(NON_OPENWRT_LED)
else
SUPPORT_LED := 1
endif

STRICT_CFLAGS = -Werror -Wextra \
				-Wno-unused-parameter \
				-Wno-sign-compare \
				-Wno-empty-body \
				-Wno-old-style-declaration \
				-Wlogical-op \
				-Wduplicated-cond \
				-Wduplicated-branches \
				-Wformat-overflow=2
BASE_CFLAGS := $(CFLAGS) $(STRICT_CFLAGS) -Wall -fstack-protector-all -fno-strict-aliasing -D_GNU_SOURCE
ifdef WITH_DEBUG
BASE_CFLAGS += -g
else
BASE_CFLAGS += -DNDEBUG -g -O0
endif

EMS_CFLAGS := $(BASE_CFLAGS)
EMS_CFLAGS += -DSUPPORT_LED=$(SUPPORT_LED)
EMS_CFLAGS += '-DSW_VERSION=$(PRODUCT_VERSION)' '-DMAJOR_PRO_VERSION=$(MAJOR_PRO_VERSION)' '-DDISPLAY_VERSION=$(SOFT_VERSION)'

COMMON_INCLUDES := -I$(BUILD_SRC_DIR)/libmodbus -I$(BUILD_SRC_DIR) -I$(BUILD_SRC_DIR)/cloud -I$(BUILD_SRC_DIR)/log_module -I$(BUILD_SRC_DIR)/business_log -I$(BUILD_SRC_DIR)/ems
COMMON_INCLUDES += $(if $(STAGING_DIR),-I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/usr/include/lib60870 -I$(STAGING_DIR)/usr/include/open62541)


EMS_CFLAGS += $(COMMON_INCLUDES)
EMS_CFLAGS += -I$(BUILD_SRC_DIR)/mqtt_emms2 -I$(BUILD_SRC_DIR)/snapshoot -I$(BUILD_SRC_DIR)/abnormal_log

COMMON_LIBS := $(LDFLAGS) -ldyutils -lpthread -lmqtt_session -llib60870 -llz4
COMMON_LIBS += -lcrypto -lmbedtls -lmbedx509 -lmbedcrypto -lcurl -llua -lxlsxwriter -lz -lm -llnxhal -luv -lrt -lubuslog -lubox

EMS_LIBS := $(COMMON_LIBS)

ROOT_SRCS := $(wildcard $(BUILD_SRC_DIR)/*.c)
ADAPTER_SRCS := $(wildcard $(BUILD_SRC_DIR)/adapter/*.c) $(wildcard $(BUILD_SRC_DIR)/adapter/*/*.c)
COMMON_SRCS := $(ROOT_SRCS)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/libmodbus/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/cloud/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/mac_mul/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/mqtt_emms2/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/log_module/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/iec104_server/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/snapshoot/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/north_mqtt/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/ota_upgrade/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/rate/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/automatic_north/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/dlt698_asn1/generated/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/abnormal_log/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/business_log/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/frpc_proxy/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/mqtt_dp/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/bmser/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/pcs_business_adapter/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/alarm_control/*.c)
COMMON_SRCS += $(wildcard $(BUILD_SRC_DIR)/frpc_cut/*.c)
COMMON_SRCS += $(ADAPTER_SRCS)

EMS_SRCS := $(COMMON_SRCS)

ifeq ($(filter iMX6ULL,$(LNX_TARGET_DEV)),)
EMS_CFLAGS += -DEN_ACCIDENT
EMS_SRCS += $(wildcard $(BUILD_SRC_DIR)/accident/*.c)
endif

ifeq ($(WITH_OPC),1)
EMS_CFLAGS += -DEN_OPCUA -I$(LNXDESTPFX)/include/open62541/
EMS_SRCS += $(wildcard $(BUILD_SRC_DIR)/opcua/*.c)
EMS_LIBS += -lopen62541 -lsqlite3
endif

EMS_CFLAGS += -DEN_EMS -I$(BUILD_SRC_DIR)/cc_lc_com
EMS_SRCS += $(wildcard $(BUILD_SRC_DIR)/cc_lc_com/*.c)
EMS_SRCS += $(wildcard $(BUILD_SRC_DIR)/ems/*.c)

ifdef EN_BMSER_LIB
ifneq ($(EN_BMSER_DB_CTROL_LIB),0)
EMS_CFLAGS += -DEN_BMSER_DB_CTROL_LIB -DEN_BMSER_VIRTUAL_DEV
EMS_LIBS += -ldb_control
endif
endif

ifeq ($(MMCK),true)
EMS_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
EMS_LIBS += -fsanitize=address -fno-omit-frame-pointer
endif

# four level platform
TOP_LAYERS := system platform service bussiness
MODULE_CFLAGS :=
MODULE_SRCS :=
MODULE_LIBS :=
# find all module mk
MODULE_MKS := $(foreach LAYER_SUB_MODULE, $(TOP_LAYERS), $(wildcard $(LAYER_SUB_MODULE)/*/module.mk))
# include all module mk
include $(MODULE_MKS)
# add to ems makefile
EMS_CFLAGS += $(MODULE_CFLAGS)
EMS_SRCS += $(MODULE_SRCS)
EMS_LIBS += $(MODULE_LIBS)

ifneq ($(strip $(COLNT_DIR)),)
ifneq ($(wildcard $(COLNT_DIR)),)
$(info Trying to linting C/C++ sources files...)
PCLNT_WRAPPER := pclnt_wrapper
endif
endif

EMS_SRCS := $(sort $(patsubst ./%,%,$(EMS_SRCS)))
ifdef CUSTOM
	EMS_OBJS := $(patsubst $(BUILD_SRC_DIR)/%.c,$(EMS_BUILD_DIR)/%.o,$(EMS_SRCS))
else
	EMS_OBJS := $(patsubst %.c,$(EMS_BUILD_DIR)/%.o,$(EMS_SRCS))
endif
EMS_DEPS := $(EMS_OBJS:.o=.d)

COLOR_GRE := \033[1;32m
COLOR_BLU := \033[1;34m
COLOR_RST := \033[0m

ifeq ($(V),1)
Q :=
SHOW_CC = @:
SHOW_LD = @:
SHOW_GEN = @:
SHOW_TAR = @:
else
Q := @
SHOW_CC = @printf  '[ CC  ] $(COLOR_GRE)%s$(COLOR_RST)\n' "$<"
SHOW_LD = @printf  '[ LD  ] $(COLOR_GRE)%s$(COLOR_RST)\n' "$@"
SHOW_GEN = @printf '[ GEN ] $(COLOR_GRE)%s$(COLOR_RST)\n' "$@"
SHOW_TAR = @printf '[ TAR ] $(COLOR_GRE)%s$(COLOR_RST)\n' "$@.tar"
endif

# ------------------------------------------------------------------------
# tools/trace：本地源码树存在时编译调试跟踪工具 lnxall_trace
# （构建逻辑见 tools/trace/Makefile，此处仅做存在性判断并委托子 make）；
# OpenWrt 构建目录未复制 tools/ 时 $(TRACE_TARGET) 为空，自动跳过
# ------------------------------------------------------------------------
TRACE_DIR := $(wildcard ../tools/trace)
ifneq ($(strip $(TRACE_DIR)),)
TRACE_TARGET := $(TRACE_DIR)/lnxall_trace
endif

STAGE_VERSION := version-for-ipkg
STAGE_VERLOG  := version.log

.PHONY: stage
stage:
ifdef CUSTOM
	@echo '[STAGE] preparing $(BUILD_SRC_DIR)'
	@rm -rf $(CURDIR)/$(BUILD_SRC_DIR)
	@mkdir -p $(CURDIR)/$(BUILD_SRC_DIR)
	@find . -type f \( -name '*.c' -o -name '*.h' \) -not -path './build/*' -printf '%P\n' | while read -r f; do \
		[ -n "$$f" ] || continue; \
		mkdir -p "$(CURDIR)/$(BUILD_SRC_DIR)/$$(dirname "$$f")"; \
		cp -a "$$f" "$(CURDIR)/$(BUILD_SRC_DIR)/$$f"; \
	done

	@echo '[STAGE] overlaying custom sources: $(CUSTOM)'
	@cd $(CUSTOM_SRC) && find . -type f \( -name '*.c' -o -name '*.h' \) -not -path './build/*' -printf '%P\n' | while read -r f; do \
		[ -n "$$f" ] || continue; \
		mkdir -p "$(CURDIR)/$(BUILD_SRC_DIR)/$$(dirname "$$f")"; \
		cp -a "$$f" "$(CURDIR)/$(BUILD_SRC_DIR)/$$f"; \
	done
endif

# Staged sources only exist after 'stage', so delegate to a sub-make
# that re-parses this makefile once the combined dir is populated.
all: stage
	$(MAKE) $(TARGET) $(TRACE_TARGET)
	@printf 'ver: %s, %s\n' $(SOFT_VERSION) $(PRODUCT_VERSION)

.PHONY: FORCE
FORCE:

$(STAGE_VERSION) $(STAGE_VERLOG): FORCE
	$(SHOW_GEN)
	$(Q)printf '%s\n' $(PRODUCT_VERSION) > $@

$(TARGET): $(EMS_OBJS) $(STAGE_VERSION) $(STAGE_VERLOG)
	$(SHOW_LD)
	$(Q)$(CC) -o $@ $(EMS_OBJS) $(EMS_LIBS)
	$(SHOW_TAR)
	$(Q)tar -czf $@.tar $@

ifneq ($(strip $(TRACE_DIR)),)
# .PHONY：每次 make 都委托子 make 无条件重新编译，确保产物与本次构建
# 的 $(CC)（与 proto_forward 同一编译器，经 CC=$(CC) 显式下传）严格一致，
# 避免编译器/工具链变化后旧产物被时间戳判断沿用
.PHONY: $(TRACE_TARGET)
$(TRACE_TARGET):
	$(SHOW_LD)
	$(Q)$(MAKE) -C $(TRACE_DIR) CC=$(CC)
endif

# compile rule against the combined sources
ifdef CUSTOM
$(EMS_BUILD_DIR)/%.o: $(BUILD_SRC_DIR)/%.c
	@mkdir -p $(dir $@)
	$(SHOW_CC)
	$(Q)$(PCLNT_WRAPPER) $(CC) $(EMS_CFLAGS) -MMD -MP -c $< -o $@
else
$(EMS_BUILD_DIR)/%.o: %.c
	@mkdir -p $(dir $@)
	$(SHOW_CC)
	$(Q)$(PCLNT_WRAPPER) $(CC) $(EMS_CFLAGS) -MMD -MP -c $< -o $@
endif

po:
	./update_po.sh

clean:
	rm -rf $(TARGET) $(TARGET).tar emu_lc
	rm -rf $(EMS_BUILD_DIR)
ifdef CUSTOM
	rm -rf $(BUILD_SRC_DIR)
endif
	rm -rf .obj_ems .obj_lc .depends_ems .depends_lc
	$(if $(strip $(TRACE_TARGET)),rm -f $(TRACE_TARGET))
	find . -name '*.a' -type f -print -exec rm -f {} \;

rebuild: clean all

.PHONY: all clean po rebuild stage

-include $(EMS_DEPS)
