1343 字
7 分钟
stc8g makefile和用量分析脚本
makefile
#!/usr/bin/make -f# Makefile for SDCC project with automatic library discoveryCC = sdccCFLAGS = --model-medium --opt-code-size
# 定义库名称(只需要在这里添加)LIBRARIES = User System
# 单片机型号MCU = STC8G1K08A# 串口设备SERIAL_PORT = /dev/ttyUSB0
# 生成包含目录路径INCLUDES = $(foreach lib, $(LIBRARIES), -I $(lib)/Inc)
# 查找所有源文件SRCS = $(foreach lib, $(LIBRARIES), $(wildcard $(lib)/Src/*.c))# 获取所有.c文件的基本名称(用于检查重名)BASENAMES = $(foreach src, $(SRCS), $(notdir $(src)))
# 检查是否有重复的源文件名DUPLICATES = $(filter $(words $(BASENAMES)),$(words $(sort $(BASENAMES))))ifneq ($(DUPLICATES),$(words $(BASENAMES))) $(warning 警告: 发现重复的源文件名!) $(warning 重复文件: $(foreach base,$(sort $(foreach b,$(BASENAMES),$(if $(filter 2,$(words $(filter $(b),$(BASENAMES)))),$(b)))),$(base)))endif
# 生成对象文件列表(保持目录结构)OBJS = $(patsubst %.c,%.rel,$(SRCS))
# 项目名称TARGET = pwm
# 构建目录BUILD_DIR = build
# 将对象文件放在build目录中OBJS_BUILD = $(patsubst %.rel,$(BUILD_DIR)/%.rel,$(OBJS))
# 默认目标:构建并生成报告all: check_libs $(BUILD_DIR) $(BUILD_DIR)/report @echo "构建完成: $(BUILD_DIR)/$(TARGET).hex"
# 检查库目录是否存在check_libs: @for lib in $(LIBRARIES); do \ if [ ! -d "$$lib/Inc" ] || [ ! -d "$$lib/Src" ]; then \ echo "错误: 库 $$lib 结构不正确!需要 $$lib/Inc 和 $$lib/Src 目录"; \ exit 1; \ fi; \ done
# 创建构建目录$(BUILD_DIR): @mkdir -p $(BUILD_DIR)
# 编译规则:所有.c文件 -> build/目录下的.rel文件$(BUILD_DIR)/%.rel: %.c @echo "编译: $<" @mkdir -p $(dir $@) @$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@ 2>&1 | head -20
# 链接$(BUILD_DIR)/$(TARGET).ihx: $(OBJS_BUILD) @echo "链接: $(words $(OBJS_BUILD)) 个对象文件..." @cd $(BUILD_DIR) && $(CC) $(CFLAGS) $(patsubst $(BUILD_DIR)/%,%,$(OBJS_BUILD)) -o $(TARGET).ihx
# 生成HEX$(BUILD_DIR)/$(TARGET).hex: $(BUILD_DIR)/$(TARGET).ihx @echo "生成HEX文件..." @cd $(BUILD_DIR) && packihx $(TARGET).ihx > $(TARGET).hex
# report: 调用外部脚本解析 map 并打印报告 $(BUILD_DIR)/report: $(BUILD_DIR)/$(TARGET).hex @echo "生成资源使用报告..." @sh scripts/map_report.sh $(BUILD_DIR)/$(TARGET).map || true
# 下载到单片机flash: $(BUILD_DIR)/$(TARGET).hex @echo "下载到 $(MCU) via $(SERIAL_PORT)..." stcgal -p $(SERIAL_PORT) -t 22168 -o program_eeprom_split=12288 -a $(BUILD_DIR)/$(TARGET).hex
# 编译但不链接(调试用)compile: $(OBJS_BUILD) @echo "编译完成,生成 $(words $(OBJS_BUILD)) 个.rel文件"
# 显示项目信息info: @echo "========================================" @echo "项目: $(TARGET)" @echo "编译器: $(CC)" @echo "库列表: $(LIBRARIES)" @echo "包含目录: $(INCLUDES)" @echo "源文件 ($(words $(SRCS)) 个):" @for src in $(sort $(SRCS)); do echo " $$src"; done @echo "对象文件 ($(words $(OBJS_BUILD)) 个):" @for obj in $(sort $(OBJS_BUILD)); do echo " $$obj"; done @echo "构建目录: $(BUILD_DIR)" @echo "========================================"
# 清理clean: @echo "清理构建文件..." @rm -rf $(BUILD_DIR) @rm -f *.ihx *.hex *.rel *.lk *.map *.mem *.rst *.asm *.lst *.sym *.cdb
# 帮助信息help: @echo "可用命令:" @echo " make - 构建整个项目" @echo " make clean - 清理所有生成文件" @echo " make flash - 下载到单片机" @echo " make info - 显示项目信息" @echo " make compile - 只编译不链接" @echo " make help - 显示此帮助信息"
.PHONY: all clean flash info help check_libs compile tidy资源分析脚本
#!/bin/sh# Enhanced map report for SDCC projects# Usage: map_report.sh <map-file> [ROM_TOTAL_BYTES] [RAM_TOTAL_BYTES]# If ROM_TOTAL_BYTES / RAM_TOTAL_BYTES are not provided, script tries to# - read a companion .mem file (same base name) for ROM total# - otherwise falls back to defaults: ROM=8k+4k (12288), RAM=1k+256 (1280)
MAPFILE="$1"ROM_OVERRIDE="$2"RAM_OVERRIDE="$3"
if [ -z "$MAPFILE" ] || [ ! -f "$MAPFILE" ]; then echo "map 报告: 未提供 map 文件 或 文件不存在: $MAPFILE" exit 0fi
hex2dec() { [ -z "$1" ] && echo 0 && return # accept 0x... or bare hex (without 0x) case "$1" in 0x*|0X*) printf "%d" "$1" ;; *) printf "%d" "0x$1" ;; esac}
# Try to extract code/const/idata/pdata/xdata sizes from map file.# We look for sections by name and take the "Size" column where possible.CSEG_START_HEX=$(awk '/^[[:space:]]*CSEG[[:space:]]+[0-9A-Fa-f]/ {print $2; exit}' "$MAPFILE" | sed 's/0x//g')CSEG_HEX=$(awk '/^[[:space:]]*CSEG[[:space:]]+[0-9A-Fa-f]/ {print $3; exit}' "$MAPFILE" | sed 's/0x//g')CONST_HEX=$(awk '/^[[:space:]]*CONST[[:space:]]+[0-9A-Fa-f]/ {print $3; exit}' "$MAPFILE" | sed 's/0x//g')DSEG_HEX=$(awk '/^[[:space:]]*DSEG[[:space:]]+[0-9A-Fa-f]/ {print $3; exit}' "$MAPFILE" | sed 's/0x//g')PSEG_HEX=$(awk '/^[[:space:]]*PSEG[[:space:]]+[0-9A-Fa-f]/ {print $3; exit}' "$MAPFILE" | sed 's/0x//g')XSEG_HEX=$(awk '/^[[:space:]]*XSEG[[:space:]]+[0-9A-Fa-f]/ {print $3; exit}' "$MAPFILE" | sed 's/0x//g')
CSEG=$(hex2dec "$CSEG_HEX")CONST=$(hex2dec "$CONST_HEX")DSEG=$(hex2dec "$DSEG_HEX")PSEG=$(hex2dec "$PSEG_HEX")XSEG=$(hex2dec "$XSEG_HEX")
USED_ROM=$((CSEG + CONST))USED_RAM=$((DSEG + PSEG + XSEG))
# compute CSEG end for module delta calcCSEG_START=$(hex2dec "$CSEG_START_HEX")CSEG_END=$((CSEG_START + CSEG))
# Determine total ROM (flash) size: prefer override arg, then companion .mem file, then defaultDEFAULT_ROM=$((8*1024 + 4*1024))DEFAULT_RAM=$((1*1024 + 256))
ROM_TOTAL=""if [ -n "$ROM_OVERRIDE" ]; then ROM_TOTAL="$ROM_OVERRIDE"else MEMFILE="${MAPFILE%.map}.mem" if [ -f "$MEMFILE" ]; then # Look for line like: ROM/EPROM/FLASH 0x0000 0x1e73 7796 65536 ROM_TOTAL=$(awk '/ROM\/EPROM\/FLASH/ {print $(NF-1); exit}' "$MEMFILE") fifiif [ -z "$ROM_TOTAL" ]; then ROM_TOTAL=$DEFAULT_ROMfi
RAM_TOTAL=""if [ -n "$RAM_OVERRIDE" ]; then RAM_TOTAL="$RAM_OVERRIDE"else # try to read some RAM hints from .mem (not always present) MEMFILE="${MAPFILE%.map}.mem" if [ -f "$MEMFILE" ]; then # try to find a line like: PAGED EXT. RAM 0x0001 0x00ba 186 256 RAM_TOTAL=$(awk '/PAGED EXT. RAM|EXTERNAL RAM|Internal RAM layout:/ {line=NR} END{ if (line) { for(i=1;i<=NR;i++){} } }' "$MEMFILE") # above attempt is conservative; we won't rely on it — fallback to default if empty RAM_TOTAL="" fifiif [ -z "$RAM_TOTAL" ]; then RAM_TOTAL=$DEFAULT_RAMfi
# Print summary with percentagespercent() { # percent <used> <total> awk "BEGIN{ if ($2==0) printf \"N/A\"; else printf \"%.1f\", ($1/$2)*100 }"}
echo "Map 报告: $MAPFILE"echo "----------------------------------------"echo "ROM 总量: $ROM_TOTAL bytes"echo "ROM 已用: $USED_ROM bytes (code=$CSEG const=$CONST)"echo "ROM 使用率: $(percent $USED_ROM $ROM_TOTAL)%"echo ""echo "RAM 总量: $RAM_TOTAL bytes"echo "RAM 已用: $USED_RAM bytes (idata=$DSEG pdata=$PSEG xdata=$XSEG)"echo "RAM 使用率: $(percent $USED_RAM $RAM_TOTAL)%"echo "----------------------------------------"
# Top modules by C: entries (module name after C:)# We'll convert the hex sizes to decimal using shell helper then aggregate with awk.TMPFILE="/tmp/map_report.$$"rm -f "$TMPFILE"# Build a sorted list of symbol addresses and their moduleawk '/^ *C:/ { addr=$2; sym=$3; mod=$NF; if (addr!="" && sym!="") print addr, sym, mod }' "$MAPFILE" | sed 's/\.rel//; s/\.o//; s/\.obj//' | \while read HEX SYM MOD; do [ -z "$HEX" -o -z "$SYM" ] && continue DEC=$(hex2dec "$HEX") printf "%d %s %s\n" "$DEC" "$SYM" "$MOD" >> "$TMPFILE"done
if [ -f "$TMPFILE" ]; then SORTED="/tmp/map_report_sorted.$$" sort -n "$TMPFILE" > "$SORTED"
# compute deltas between consecutive symbols and attribute delta to the symbol (function) # SORTED format: <addr> <symbol> <module> SYMBOL_SIZES="/tmp/map_report_sym_sizes.$$" awk -v cseg_end="$CSEG_END" ' { addr[NR]=$1; sym[NR]=$2; mod[NR]=$3 } END { for(i=1;i<=NR;i++) { if (i<NR) delta = addr[i+1]-addr[i]; else delta = cseg_end - addr[i]; if (delta<0) delta=0; printf "%d %s %s\n", delta, sym[i], mod[i]; } }' "$SORTED" > "$SYMBOL_SIZES"
echo "Top 20 函数(按占用字节):" # Print header with tabs, then nicely aligned rows: Rank, Bytes, Function, Module printf "%-4s\t%8s\t%-30s\t%s\n" "#" "Bytes" "Function" "Module" sort -nr "$SYMBOL_SIZES" | head -n 20 | awk 'BEGIN{rank=0} {rank++; printf "%-4d\t%8d\t%-30s\t%s\n", rank, $1, $2, $3}'
rm -f "$SYMBOL_SIZES"
rm -f "$TMPFILE" "$SORTED"fi
exit 0 stc8g makefile和用量分析脚本
https://www.mintlab.top/posts/stc8g编译脚本/stc8g_makefile/