# ---------------------------------------------------------------------------
# shfolder.dll (Altium license hook) -- 还原工程构建
#
#   make           使用 MinGW-w64 交叉编译 (在 Linux 上验证语义/可编译性)
#   make check     构建后用 crc32_zero.py 把全文件 CRC32 归零
#   make slim      体积优化构建 (gc-sections + strip)
#   make nocrt     无 CRT 构建 (对应 MSVC 的 ReleaseNoCRT 配置)
#
# 注意: 原始样本由 MSVC x64 编译 (/GS /guard:cf /hotpatch 风格),
#       产物字节必然与原始 DLL 不同, 本工程目标是**行为等价**的源码还原。
# ---------------------------------------------------------------------------
# 交叉工具链前缀: 默认 MinGW-w64; 用 `make CROSS=` 可切换到本机编译器
CROSS   ?= x86_64-w64-mingw32-
CC      := $(CROSS)gcc
# -Wno-cast-function-type : GetProcAddress 的 FARPROC -> 函数指针转换(MinHook 自身也这么做)
CFLAGS  ?= -O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type \
           -DWIN32_LEAN_AND_MEAN -Iinclude -Isrc
LDFLAGS ?= -shared -Wl,-Map=build/shfolder.map
LIBS    ?= -lkernel32 -lshell32

SRC_DIR   := src
MINHOOK   := $(SRC_DIR)/minhook/src
# 注: MinHook 1.3.x 之后 thread.c 已被合并进 hook.c, 故这里只需要以下文件
SRCS := \
	$(SRC_DIR)/dllmain.c \
	$(SRC_DIR)/detour_crypt.c \
	$(SRC_DIR)/crc_pad.c \
	$(SRC_DIR)/exports.c \
	$(MINHOOK)/hook.c \
	$(MINHOOK)/trampoline.c \
	$(MINHOOK)/buffer.c \
	$(MINHOOK)/hde/hde64.c

OUT := build/shfolder.dll

.PHONY: all clean check dirs
all: dirs $(OUT)

dirs:
	@mkdir -p build

$(OUT): $(SRCS) $(SRC_DIR)/shfolder.def $(SRC_DIR)/keys.h $(SRC_DIR)/crc32_table.h
	$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) $(SRC_DIR)/shfolder.def $(LIBS)
	@echo "[+] built $@"

# 原始 DLL 的 DllMain 要求自身文件 CRC32 == 0 才安装 hook
check: $(OUT)
	python3 tools/crc32_zero.py $(OUT)
	python3 tools/crc32_zero.py $(OUT) --check
	python3 tools/verify_build.py $(OUT)
	python3 tools/validate_msvc.py

# 只校验 msvc/ 工程文件（Linux 上即可运行，防止"VS 打不开工程"）
.PHONY: check-msvc
check-msvc:
	python3 tools/validate_msvc.py

clean:
	rm -rf build

# ---------------------------------------------------------------------------
# 可选: 体积优化构建
#
#   make slim
#
# 与 make 的差别（实测 115,553 -> 30,720 字节，-73%）:
#   * -ffunction-sections -fdata-sections + -Wl,--gc-sections
#       删除未被引用的函数/数据（例如 MinHook 中本 DLL 用不到的 API）
#   * -s (strip)
#       去掉 MinGW 默认生成的 DWARF 调试节（约 51.6 KB，占默认产物 45%）
#
# 仍无法降到原始样本的 16,896 字节：剩余差额来自 MinGW 的 CRT 启动代码、
# msvcrt 导入表，以及缺少 MSVC 的 LTCG/ICF 折叠。
#   进一步缩小：`make nocrt`（去掉 CRT，实测 23,040 B）
#   或 MSVC 的 ReleaseNoCRT 配置（实测 17,408 B，见 msvc/README.md）。
# ---------------------------------------------------------------------------
SLIM_DIR     := build/slim
SLIM_OUT     := $(SLIM_DIR)/shfolder.dll
SLIM_CFLAGS  := $(CFLAGS) -ffunction-sections -fdata-sections -fno-ident
SLIM_LDFLAGS := -shared -Wl,--gc-sections -s

.PHONY: slim
slim: dirs
	@mkdir -p $(SLIM_DIR)
	$(CC) $(SLIM_CFLAGS) $(SRCS) -o $(SLIM_OUT) $(SLIM_LDFLAGS) $(SRC_DIR)/shfolder.def $(LIBS)
	@echo "[+] built $(SLIM_OUT)  $$(stat -c%s $(SLIM_OUT)) bytes"
	python3 tools/crc32_zero.py $(SLIM_OUT)
	python3 tools/verify_build.py $(SLIM_OUT)

# ---------------------------------------------------------------------------
# 可选: 无 CRT 构建（与 MSVC 的 ReleaseNoCRT|x64 等价思路）
#
#   make nocrt
#
# 配方:
#   * -nostdlib               不链接 MinGW 的 CRT/msvcrt
#   * -DSHFOLDER_NOCRT        启用 src/nocrt.c（提供 memcpy/memmove/memset/memcmp）
#   * -Wl,-e,DllMain          MinGW 侧直接用 DllMain 作为 PE 入口
#                             （MSVC 侧对应 src/nocrt.c 里的 _DllMainCRTStartup）
#   * --gc-sections -s        删除死代码 + strip 调试信息
# 效果: 导入表只剩 KERNEL32+SHELL32（与原始样本一致），实测 23,040 字节
#       （vs 默认 115,553 / slim 30,720；MSVC ReleaseNoCRT 为 17,408）
# ---------------------------------------------------------------------------
NOCRT_DIR     := build/nocrt
NOCRT_OUT     := $(NOCRT_DIR)/shfolder.dll
NOCRT_CFLAGS  := $(CFLAGS) -ffunction-sections -fdata-sections -DSHFOLDER_NOCRT
NOCRT_LDFLAGS := -shared -nostdlib -Wl,-e,DllMain -Wl,--gc-sections -s
NOCRT_SRCS    := $(SRC_DIR)/nocrt.c $(SRCS)

.PHONY: nocrt
nocrt: dirs
	@mkdir -p $(NOCRT_DIR)
	$(CC) $(NOCRT_CFLAGS) $(NOCRT_SRCS) -o $(NOCRT_OUT) $(NOCRT_LDFLAGS) $(SRC_DIR)/shfolder.def $(LIBS)
	@echo "[+] built $(NOCRT_OUT)   $$(stat -c%s $(NOCRT_OUT)) bytes"
	python3 tools/crc32_zero.py $(NOCRT_OUT)
	python3 tools/verify_build.py $(NOCRT_OUT)
