You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Valgrind构建时自动禁用Sanitizer并强制重编译目标的方法

Valgrind与Sanitizer兼容问题的Makefile优化方案

问题背景

当前Makefile中valgrind目标依赖默认编译的$(TARGET),但默认编译启用了AddressSanitizer等一系列Sanitizer选项,而Valgrind与这些Sanitizer无法兼容。每次运行make valgrind都需要手动执行make clean、注释Sanitizer选项,完成后还要恢复注释,操作繁琐。需要实现:

  • valgrind目标触发时,无条件重编译目标程序
  • 编译时自动禁用所有Sanitizer选项

解决方案

核心思路是为Valgrind单独构建一个不带Sanitizer的目标程序,避免与默认编译产物冲突,同时强制每次构建。以下是修改后的完整Makefile:

CC = gcc-13

# 基础编译参数(不含Sanitizer)
BASE_CFLAGS += -DBENCHMARKING
BASE_CFLAGS += -O3
BASE_CFLAGS += -std=c2x
BASE_CFLAGS += -s
BASE_CFLAGS += -no-pie

BASE_CFLAGS += -fno-builtin
BASE_CFLAGS += -fno-common
BASE_CFLAGS += -fno-omit-frame-pointer

BASE_CFLAGS += -Wall
BASE_CFLAGS += -Wextra
BASE_CFLAGS += -Warray-bounds
BASE_CFLAGS += -Wconversion
BASE_CFLAGS += -Wformat-signedness
BASE_CFLAGS += -Wno-parentheses
BASE_CFLAGS += -Wpedantic
BASE_CFLAGS += -pedantic-errors
BASE_CFLAGS += -Wstrict-prototypes
BASE_CFLAGS += -Wwrite-strings
BASE_CFLAGS += -Wno-missing-braces
BASE_CFLAGS += -Wno-missing-field-initializers

# Sanitizer专属参数
SANITIZER_FLAGS += -fsanitize=address
SANITIZER_FLAGS += -fsanitize=undefined
SANITIZER_FLAGS += -fsanitize=bounds-strict
SANITIZER_FLAGS += -fsanitize=leak
SANITIZER_FLAGS += -fsanitize=null
SANITIZER_FLAGS += -fsanitize=signed-integer-overflow
SANITIZER_FLAGS += -fsanitize=bool
SANITIZER_FLAGS += -fsanitize=pointer-overflow
SANITIZER_FLAGS += -fsanitize-address-use-after-scope
SANITIZER_FLAGS += -fanalyzer

# 默认编译包含Sanitizer
CFLAGS = $(BASE_CFLAGS) $(SANITIZER_FLAGS)

SRC_DIR = src
SRCS = $(wildcard $(SRC_DIR)/*.c)
OBJ_DIR = obj
VALGRIND_OBJ_DIR = obj-valgrind
OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))
VALGRIND_OBJS = $(patsubst $(SRC_DIR)/%.c,$(VALGRIND_OBJ_DIR)/%.o,$(SRCS))
DEPS = $(OBJS:.o=.d)
VALGRIND_DEPS = $(VALGRIND_OBJS:.o=.d)

TARGET = read_file
VALGRIND_TARGET = $(TARGET)-valgrind

all: $(TARGET)
    
# 默认带Sanitizer的目标
$(TARGET): $(OBJ_DIR) $(OBJS)
    $(CC) $(CFLAGS) -o $@ $(OBJS)

# Valgrind专用目标(不带Sanitizer)
$(VALGRIND_TARGET): $(VALGRIND_OBJ_DIR) $(VALGRIND_OBJS)
    $(CC) $(BASE_CFLAGS) -o $@ $(VALGRIND_OBJS)

$(OBJ_DIR):
    mkdir -p $(OBJ_DIR)

$(VALGRIND_OBJ_DIR):
    mkdir -p $(VALGRIND_OBJ_DIR)

# 默认编译规则
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(CFLAGS) -MMD -c -o $@ $<

# Valgrind专属编译规则
$(VALGRIND_OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(BASE_CFLAGS) -MMD -c -o $@ $<

-include $(DEPS)
-include $(VALGRIND_DEPS)

# Valgrind目标:依赖专用编译产物,强制每次构建
valgrind: FORCE $(VALGRIND_TARGET)
    valgrind --tool=memcheck --leak-check=yes ./$(VALGRIND_TARGET) --mmap_memchr $(TARGET)
    valgrind --tool=memcheck --leak-check=yes ./$(VALGRIND_TARGET) --getline $(TARGET)
    valgrind --tool=memcheck --leak-check=yes ./$(VALGRIND_TARGET) --mmap_getline $(TARGET)
    valgrind --tool=memcheck --leak-check=yes ./$(VALGRIND_TARGET) --fread $(TARGET)

# 强制目标:确保valgrind每次都触发重新编译
FORCE:

# 扩展clean目标,清理所有产物
clean:
    rm -rf $(OBJ_DIR) $(VALGRIND_OBJ_DIR) $(TARGET) $(VALGRIND_TARGET)

关键修改说明

  1. 拆分编译参数:将基础编译选项和Sanitizer选项分离,默认CFLAGS包含两者,Valgrind编译时仅使用基础参数。
  2. 独立产物目录:为Valgrind版本的目标文件创建单独的obj-valgrind目录,避免与默认编译的目标文件冲突,无需手动clean默认产物。
  3. 专用目标程序:生成$(TARGET)-valgrind作为Valgrind专用的可执行文件,与默认的$(TARGET)共存,互不影响。
  4. 强制重编译:通过FORCE伪目标,确保每次执行make valgrind都会重新编译Valgrind版本的程序,无需手动触发clean。
  5. 扩展clean:统一清理所有编译产物,包括默认和Valgrind版本的目标文件与可执行程序。

现在执行make valgrind即可直接编译不带Sanitizer的版本并运行Valgrind,无需任何手动修改;执行make all则保持默认带Sanitizer的编译流程。

内容的提问来源于stack exchange,提问作者Madagascar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:12:45