编写Makefile实现单源文件生成带架构后缀二进制文件报错
问题排查:Makefile无法生成带架构后缀的二进制文件
需求与问题背景
需要将目录中所有C/C++源文件编译为二进制文件,要求文件名格式为「源文件basename+架构后缀」。编写的Makefile如下:
CC = gcc CPP = g++ CFLAGS = -std=c89 -std=c99 -fpermissive CPPFLAGS = -std=c++17 -fpermissive BINDIR = ./bin LIBS = -lm ARCH = $(shell uname -m) # 收集所有C/C++源文件 SRCS=$(wildcard *.c) CPP_SRCS=$(wildcard *.cpp) # 生成带架构后缀的目标文件列表 OBJS := $(patsubst %.c, $(BINDIR)/%-$(ARCH), $(SRCS)) OBJS += $(patsubst %.cpp, $(BINDIR)/%-$(ARCH), $(CPP_SRCS)) all: $(OBJS) # C++源文件编译规则 $(BINDIR)/% : %.cpp Makefile $(CPP) -o $@ $< $(CPPFLAGS) # C源文件编译规则 $(BINDIR)/% : %.c Makefile $(CC) -o $@ $< $(CFLAGS) $(LIBS)
执行时触发错误:
make: *** No rule to make target `bin/file1-arm64', needed by `all'. Stop.
问题根源
当前的模式规则$(BINDIR)/% : %.cpp和$(BINDIR)/% : %.c无法匹配目标bin/file1-arm64:
- 模式中的
%会匹配file1-arm64,但对应的源文件是file1.cpp或file1.c,两者名称结构不对应——规则没有处理目标里的-$(ARCH)后缀部分,导致Make找不到生成目标的有效方法。
修复方案
方案一:使用静态模式规则(推荐)
静态模式规则可以精准关联带后缀的目标和对应的源文件,同时补充目录生成规则避免报错:
CC = gcc CPP = g++ CFLAGS = -std=c99 -fpermissive # 注:不可同时指定-std=c89和c99,保留c99即可 CPPFLAGS = -std=c++17 -fpermissive BINDIR = ./bin LIBS = -lm ARCH = $(shell uname -m) SRCS=$(wildcard *.c) CPP_SRCS=$(wildcard *.cpp) OBJS := $(patsubst %.c, $(BINDIR)/%-$(ARCH), $(SRCS)) OBJS += $(patsubst %.cpp, $(BINDIR)/%-$(ARCH), $(CPP_SRCS)) all: $(OBJS) # 确保输出目录存在 $(BINDIR): mkdir -p $(BINDIR) # C源文件编译规则:匹配bin/xxx-架构 → xxx.c $(OBJS): $(BINDIR)/%-$(ARCH): %.c $(BINDIR) $(CC) -o $@ $< $(CFLAGS) $(LIBS) # C++源文件编译规则:匹配bin/xxx-架构 → xxx.cpp $(OBJS): $(BINDIR)/%-$(ARCH): %.cpp $(BINDIR) $(CPP) -o $@ $< $(CPPFLAGS)
方案二:普通模式规则结合字符串处理
如果偏好普通模式规则,可以通过字符串截取提取源文件basename,再匹配对应源文件:
CC = gcc CPP = g++ CFLAGS = -std=c99 -fpermissive CPPFLAGS = -std=c++17 -fpermissive BINDIR = ./bin LIBS = -lm ARCH = $(shell uname -m) ARCH_SUFFIX = -$(ARCH) SRCS=$(wildcard *.c) CPP_SRCS=$(wildcard *.cpp) OBJS := $(patsubst %.c, $(BINDIR)/%-$(ARCH), $(SRCS)) OBJS += $(patsubst %.cpp, $(BINDIR)/%-$(ARCH), $(CPP_SRCS)) all: $(OBJS) $(BINDIR): mkdir -p $(BINDIR) # 通用编译规则:移除目标的架构后缀,匹配对应源文件 $(BINDIR)/%: $(BINDIR) @if [ -f $(subst $(ARCH_SUFFIX),,$*).c ]; then \ $(CC) -o $@ $(subst $(ARCH_SUFFIX),,$*).c $(CFLAGS) $(LIBS); \ elif [ -f $(subst $(ARCH_SUFFIX),,$*).cpp ]; then \ $(CPP) -o $@ $(subst $(ARCH_SUFFIX),,$*).cpp $(CPPFLAGS); \ fi
内容的提问来源于stack exchange,提问作者David Kovar
相关产品推荐
相关产品推荐

