Files
Just-DataInspector/Makefile
T
DeepSeek-V4.1-Flash 94fc1c45da perf(size): Release 关闭异步展开表 + 修正 Debug 构建参数
1. Release 专用 `-fno-asynchronous-unwind-tables`(新增 RELEASE_ONLY_OPT,只加在
   Release 的两条编译规则上)。-fno-exceptions 下绝大多数函数不再需要 .pdata/.xdata:
   实测 829,440 -> 793,088 B(-36,352);.pdata 30,420 -> 12,684、.xdata 28,904 -> 10,156。
   Release 不再生成可靠的栈回溯(崩溃诊断);Debug 保留完整展开表。

2. 修正真实缺陷:Makefile 的 DEBUG_OPT = -O0 从未被使用 —— Debug 两条编译规则误用了
   $(RELEASE_OPT)(即 -Oz),且全程没有 -g,因此所谓 Debug 构建其实只是"不 strip 的
   Release"。现在 Debug 规则改用 $(DEBUG_OPT) -g,链接也加 -g。
   代价:Debug 产物 1,734,578 -> 5,992,064 B(真实 -O0 -g,属预期)。

release(全量)790KB 零警告;debug(全量 -O0 -g)零警告。
2026-11-04 02:52:13 +08:00

335 lines
13 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 目标文件名称
TARGET_FILE_NAME = Target
# 编译目录
BUILD_DIR = Build
# Release 编译子目录
SUB_DIR_RELEASE = Release
# Debug 编译子目录
SUB_DIR_DEBUG = Debug
# ⚠️ 产物体积**预警阈值**(用户 2026-10-29 更新):**1MB(1,048,576 B)**。
# 这不是"不许超过":**超过仍可发布**,但到达阈值时必须主动提醒用户,
# 并说明"超在哪一段(`.text` / `.rdata` / `.xdata`+`.pdata` / `.rsrc`)、由哪个改动贡献"。
# 旧红线 900KB / 800KB 均已作废。
# 查段构成的命令(排查超限原因的标准做法):objdump -h Build/Release/Target.exe
RELEASE_OPT = -Oz
# ---- 体积相关编译开关 ------------------------------------------------------
# ⚠️ 曾经有一个 `LAYOUT_BOUNDS` 开关(声称能剔除"显示布局边界"调试叠加层),
# 但它从来没有被任何 `#if` 引用过 —— 是个**名实不符**的死开关,已删除(2026-10-29 审计)。
# 该叠加层现在是**正式功能**(设置菜单里的开关),随产物一起编译;
# 要真正把它变成可剔除项,需要给每个组件的 `BuildBoxes` 重载都加 `#if`,
# 代价远大于它占的十几 KB(当前产物 791,552 B,离 1MB 预警线还有 250+ KB)。
# NO_EXCEPTIONS:1 = 用 `-fno-exceptions` 构建(省 `.xdata`+`.pdata` 约 28KB)。
# ⚠️ 代价:所有"按数据规模预留大块内存"的地方必须用 `MemProbe.hpp` 的
# `MemReserveIfRoom()` **预检验**,不能再靠 try/catch。
# 兜底:`Application::Initialize` 里安装了 `MemInstallTerminateHandler()`
# (万一仍有遗漏,OOM 时弹一次带建议的模态提示后干净退出,而不是静默消失)。
NO_EXCEPTIONS = 1
# LTO:1 = 链接时优化(实测 −94KB)。构建时间约翻倍。
# ⚠️ **切换 LTO 必须 `make clean`**:LTO 与非 LTO 目标文件混链会让
# GCC 15.2.0 在 `binds_to_current_def_p` 处 ICE(已实测复现)。
# ⚠️ 开启 LTO 后 `-Wa,...,-ahlms` 的 `.lst` 汇编清单不再生成(lto-wrapper 会丢弃并告警),
# 因此 `ASM_LISTING` 在 LTO 下为空。
LTO = 1
# ---------------------------------------------------------------------------
# Debug 优化等级
DEBUG_OPT = -O0
# GUI或CUI编译选项 [0]CUI/Console [1]GUI
GUI = 1
# C编译标准
C_STD = c17
# C++编译标准
CXX_STD = c++17
# 源文件编码定义
INPUT_CHAR_ENCODING = UTF-8
# 编译产物单字节字符(char)编码定义
OUTPUT_CHAR_ENCODING = GBK
# 编译产物宽字符(wchar_t)编码定义
OUTPUT_WCHAR_ENCODING = UTF-16LE
# 编译工具前缀
COMPLIER_PREFIX = \
# C编译工具
C_COMPLIER = $(strip $(COMPLIER_PREFIX))gcc
# C++编译工具
CXX_COMPLIER = $(strip $(COMPLIER_PREFIX))g++
# Windows 资源文件编译工具
WIN_RES_COMPLIER = windres
##################################################################################
# 链接库
LIB_LINK = \
-lgdi32 \
-lgdiplus \
-lmsimg32 \
-lcomdlg32 \
-ld3d11 \
-ldwmapi \
-ld3dcompiler \
# C定义
C_DEFS = \
_UNICODE \
UNICODE \
# C头文件目录
C_INCLUDES_PATHS = \
# C源文件目录
C_SOURCES_PATHS = \
# C额外单个源文件
C_EXTERA_SOURCES = \
# C++定义
CXX_DEFS = \
_UNICODE \
UNICODE \
# C++ 头文件目录
# ⚠️ 目录约定:**所有头文件(.hpp)只放在 `Inc`**,`Src` 只放实现(.cpp)。
# `*Internal.hpp`(组件内部共享的常量/工具,如 `PlotViewInternal.hpp`)同样属于头文件,
# 历史上曾被放在 `Src` 下(那里也能编译,因为编译器会先找 `#include` 所在目录),
# 但那是靠“同目录优先”隐式生效的 —— 一旦文件被搬走就会无声失效。现已全部移入 `Inc`。
CXX_INCLUDES_PATHS = \
Utilities/Inc \
Resources/Inc \
Components/Main/Inc \
Components/Shared/Inc \
Components/Application/Inc \
Components/TabBar/Inc \
Components/Toolbar/Inc \
Components/SignalPanel/Inc \
Components/PlotView/Inc \
# C++源文件目录
CXX_SOURCES_PATHS = \
Utilities/Src \
Components/Main/Src \
Components/Shared/Src \
Components/Application/Src \
Components/TabBar/Src \
Components/Toolbar/Src \
Components/SignalPanel/Src \
Components/PlotView/Src \
# C++额外单个源文件
CXX_EXTERA_SOURCES = \
# Windows 资源文件脚本头文件路径
WIN_RESOURCE_INCLUDES_PATHS = \
Resources \
Resources/Inc \
# Windows 资源文件脚本输入代码页(对应 INPUT_CHAR_ENCODING = UTF-8)
WIN_RESOURCE_CODEPAGE = 65001
# Windows 资源文件脚本列表
WIN_RESOURCE_SCRIPTS = \
Resources/JustDataInspector.rc \
##################################################################################
# C编译选项
CFLAGS = $(foreach text,$(C_DEFS),$(addprefix -D,$(text))) \
$(foreach path,$(C_INCLUDES_PATHS),$(addprefix -I,$(path))) \
-std=$(strip $(C_STD)) \
-finput-charset=$(strip $(INPUT_CHAR_ENCODING)) \
-fexec-charset=$(strip $(OUTPUT_CHAR_ENCODING)) \
-fwide-exec-charset=$(strip $(OUTPUT_WCHAR_ENCODING)) \
-static \
$(FUNC_SECTIONS) \
-Wall \
-MMD -MP -MF"$(@:%.o=%.d)" \
# C++编译选项
CXXFLAGS = $(foreach text,$(CXX_DEFS),$(addprefix -D,$(text))) \
$(foreach path,$(CXX_INCLUDES_PATHS),$(addprefix -I,$(path))) \
-std=$(strip $(CXX_STD)) \
-finput-charset=$(strip $(INPUT_CHAR_ENCODING)) \
-fexec-charset=$(strip $(OUTPUT_CHAR_ENCODING)) \
-fwide-exec-charset=$(strip $(OUTPUT_WCHAR_ENCODING)) \
-static \
$(FUNC_SECTIONS) \
-Wall \
-MMD -MP -MF"$(@:%.o=%.d)" \
-lstdc++ \
# 链接选项
LDFLAGS = -Wl,-Map,$(basename $@).map \
$(GC_SECTIONS) \
##################################################################################
# GUI与CUI选项附加
ifeq ($(GUI), 1)
LDFLAGS += -mwindows
else
LDFLAGS += -mconsole
endif
# ---- 体积/行为相关开关(必须在 CFLAGS / CXXFLAGS / LDFLAGS 定义之后)--------
# 说明:这些是 `=` / `+=` 的递归变量,make 在展开 recipe 时才求值,
# 因此放在 LDFLAGS 定义之后仍然能正确作用到前面的 CFLAGS / LDFLAGS。
ifeq ($(strip $(NO_EXCEPTIONS)), 1)
CXXFLAGS += -fno-exceptions
endif
# ---- RTTI:全项目不使用 `dynamic_cast` / `typeid` ----
# 2026-11-04 审查:唯一的 `dynamic_cast`(Toolbar::BuildBoxes)是多余的强转,
# 已改为直接使用已有的 `UiButtonWidget*`。RTTI 会链入 `cp-demangle.o`
# (Release map 实测 56,320 B)+ `type_info` 表,最小复现程序实测 +75,264 B。
NO_RTTI = 1
ifeq ($(strip $(NO_RTTI)), 1)
CXXFLAGS += -fno-rtti
endif
# ---- SEH 展开表:只对 Release 关闭 `-fasynchronous-unwind-tables` ----
# 2026-11-04 审查实测:**只对 Release** 关闭后产物从 829,440 → 793,088 B(**−36,352 B**),
# 因为 `-fno-exceptions` 下绝大多数函数不再需要 `.pdata`/`.xdata`。
# * `.pdata` 只用于栈回溯(崩溃诊断);本程序不打印栈回溯,功能不受影响。
# * ⚠️ 代价:Release 崩溃时 WER 拿不到可靠调用栈(Debug 构建保留完整展开表)。
# * ⚠️ 全关(`-fno-unwind-tables`)会链接失败(历史踩坑),**不要**打开。
RELEASE_ONLY_OPT = -fno-asynchronous-unwind-tables
# 丢弃未被引用的函数/数据(非 LTO 时还需要配合 -ffunction-sections 才有粒度)。
GC_SECTIONS = -Wl,--gc-sections
ifeq ($(strip $(LTO)), 1)
# LTO 自己就做跨编译单元的内联与去重,不需要再开 function-sections;
# 实测 `-flto` 与 `-ffunction-sections -fdata-sections` 同时打开会让
# GCC 15.2.0 在 `binds_to_current_def_p (symtab.cc:2598)` 处 ICE。
FUNC_SECTIONS =
CFLAGS += -flto
CXXFLAGS += -flto
# ⚠️ `-flto-partition=one` 是绕过上面那个 ICE 的关键:
# 默认的多分区 LTRANS 在解析 COMDAT 定义时必崩(同一份代码拆成 11 个分区稳定复现,
# 单分区从未复现)。代价是 LTRANS 只能串行,全量构建比非 LTO 慢约一倍。
LDFLAGS += -flto -flto-partition=one
# lto-wrapper 会丢弃 -Wa 的汇编清单并告警,故 LTO 下不生成 .lst。
ASM_LISTING =
ASM_LISTING_C =
else
FUNC_SECTIONS = -ffunction-sections -fdata-sections
ASM_LISTING = -Wa,-a,-ad,-ahlms=$(@:%.o=%.lst)
ASM_LISTING_C = -Wa,-a,-ad,-alms=$(@:%.o=%.lst)
endif
# ---------------------------------------------------------------------------
# C目标文件及索引目录关联
OBJECTS = $(notdir $(C_EXTERA_SOURCES:.c=.o))
OBJECTS += $(subst .c,.o,$(notdir $(foreach path,$(C_SOURCES_PATHS),$(wildcard $(path)/*.c))))
vpath %.c $(sort $(dir $(C_EXTERA_SOURCES))) $(sort $(C_SOURCES_PATHS))
# C++目标文件及索引目录关联
OBJECTS += $(notdir $(CXX_EXTERA_SOURCES:.cpp=.o))
OBJECTS += $(subst .cpp,.o,$(notdir $(foreach path,$(CXX_SOURCES_PATHS),$(wildcard $(path)/*.cpp))))
vpath %.cpp $(sort $(dir $(CXX_EXTERA_SOURCES))) $(sort $(CXX_SOURCES_PATHS))
# Windows资源文件及索引目录关联
OBJECTS += $(notdir $(WIN_RESOURCE_SCRIPTS:.rc=.o))
vpath %.rc $(sort $(dir $(WIN_RESOURCE_SCRIPTS)))
# Release 目标文件
RELEASE_OBJECTS = $(addprefix $(BUILD_DIR)/$(SUB_DIR_RELEASE)/,$(OBJECTS))
# Debug 目标文件
DEBUG_OBJECTS = $(addprefix $(BUILD_DIR)/$(SUB_DIR_DEBUG)/,$(OBJECTS))
##################################################################################
# all任务 目标为 release 和 debug 产物
all: $(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(TARGET_FILE_NAME).exe $(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(TARGET_FILE_NAME).exe
@echo ====== [All] Build Procedure Accomplished ======
# release任务 目标为 release 产物
release: $(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(TARGET_FILE_NAME).exe
@echo ====== [Release] Build Procedure Accomplished ======
# debug任务 目标为 debug 产物
debug: $(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(TARGET_FILE_NAME).exe
@echo ====== [Debug] Build Procedure Accomplished ======
# 清理任务
clean: $(BUILD_DIR)
powershell rm -r $(BUILD_DIR)
# 构建目录生成
$(BUILD_DIR):
powershell mkdir $@
# Release 工作目录生成
$(BUILD_DIR)/$(SUB_DIR_RELEASE): | $(BUILD_DIR)
powershell mkdir $@
# Debug 工作目录生成
$(BUILD_DIR)/$(SUB_DIR_DEBUG): | $(BUILD_DIR)
powershell mkdir $@
# Release 最终可执行文件编译任务
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(TARGET_FILE_NAME).exe: $(RELEASE_OBJECTS)
@echo ====== [Release] All File Compiled. Now Linking... ======
$(CXX_COMPLIER) $(RELEASE_OBJECTS) -static -s -o $@ $(LIB_LINK) $(LDFLAGS)
@echo ====== [Release] Program Link Finished ======
# Debug 最终可执行文件编译任务
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(TARGET_FILE_NAME).exe: $(DEBUG_OBJECTS)
@echo ====== [Debug] All File Compiled. Now Linking... ======
$(CXX_COMPLIER) $(DEBUG_OBJECTS) -static -g -o $@ $(LIB_LINK) $(LDFLAGS)
@echo ====== [Debug] Program Link Finished ======
# C Release 目标文件编译
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.c Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
@echo ====== [Release] C Source File "$<" Compiling... ======
$(C_COMPLIER) -c $(CFLAGS) $(RELEASE_OPT) $(RELEASE_ONLY_OPT) $(ASM_LISTING_C) $< -o $@
# C++ Release 目标文件编译
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.cpp Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
@echo ====== [Release] C++ Source File "$<" Compiling... ======
$(CXX_COMPLIER) -c $(CXXFLAGS) $(RELEASE_OPT) $(RELEASE_ONLY_OPT) $(ASM_LISTING) $< -o $@
# Release 资源脚本文件编译
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.rc Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
@echo ====== [Release] Windows Resource Script File "$<" Compiling... ======
$(WIN_RES_COMPLIER) -c $(WIN_RESOURCE_CODEPAGE) $(foreach path,$(WIN_RESOURCE_INCLUDES_PATHS),$(addprefix -I,$(path))) $< -o $@
# C Debug 目标文件编译
# ⚠️ 2026-11-04 审查修正:原来这里误用了 `$(RELEASE_OPT)`,导致 `DEBUG_OPT = -O0`
# **从未生效**(Debug 实际上也是 -Oz,且不带 `-g`,根本无法调试)。
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.c Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
@echo ====== [Debug] C Source File "$<" Compiling... ======
$(C_COMPLIER) -c $(CFLAGS) $(DEBUG_OPT) -g $(ASM_LISTING_C) $< -o $@
# C++ Debug 目标文件编译
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.cpp Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
@echo ====== [Debug] C++ Source File "$<" Compiling... ======
$(CXX_COMPLIER) -c $(CXXFLAGS) $(DEBUG_OPT) -g $(ASM_LISTING) $< -o $@
# Debug 资源脚本文件编译
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.rc Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
@echo ====== [Debug] Windows Resource Script File "$<" Compiling... ======
$(WIN_RES_COMPLIER) -c $(WIN_RESOURCE_CODEPAGE) $(foreach path,$(WIN_RESOURCE_INCLUDES_PATHS),$(addprefix -I,$(path))) $< -o $@
# 依赖关系
-include $(RELEASE_OBJECTS:.o=.d)
-include $(DEBUG_OBJECTS:.o=.d)