C++项目结构配置与Makefile编译运行问题求助
C++ Makefile配置异常与可执行文件运行问题排查
现有项目目录结构
/project Makefile .gitignore /bin /src file1.cpp file2.cpp file3.cpp /include definitions.h /obj
历次配置与问题表现
第一版Makefile与编译报错
第一版编写的Makefile内容如下:
CC = g++ CFLAGS = -std=c++2b -Wno-parentheses -Iinclude/ All: build obj/%.o: src/%.cpp $(CC) $(CFLAGS) -c $^ build: $(CC) $(CFLAGS) file1.o file2.o file3.o -o bin/main$(compiler)
执行make命令直接返回错误:
make: *** No rule to make target 'file1.o', needed by 'build'. Stop.
报错原因:build目标声明的依赖是根目录下的file1.o等文件,但定义的模式规则只匹配obj/目录下的.o文件,make找不到生成根目录下.o文件的规则,直接终止。
第二版Makefile与存在的问题
调整模式规则后的第二版配置如下:
CC = g++ CFLAGS = -std=c++2b -Wno-parentheses -Iinclude/ All: build %.o: src/%.cpp $(CC) $(CFLAGS) -c $^ build: $(CC) $(CFLAGS) file1.o file2.o file3.o -o bin/main$(compiler)
该版本可以完成编译,但存在两个明显问题:
- 所有
.o目标文件全部生成在项目根目录,不符合目录规划 - 可执行文件运行逻辑异常:仅在项目根目录打开终端,输入
./bin/maing++可以正常运行;进入bin目录执行./maing++、或者直接双击exe文件都无法启动
预期要实现的效果: - 所有.o文件统一输出到
obj目录 - 编译生成的可执行文件可以直接双击/在任意路径下通过终端启动
第三版Makefile与遗留问题
后续调整的第三版配置已经解决了.o文件输出路径的问题,配置如下:
CC = g++ CFLAGS = -std=c++2b -Wno-parentheses -Iinclude/ -Idoc/ SOURCES := $(wildcard src/*.cpp) OBJECTS := $(patsubst src/%.cpp, obj/%.o, $(SOURCES)) All: build obj/%.o: src/%.cpp $(CC) $(CFLAGS) -c $< -o $@ build: $(OBJECTS) $(CC) $(CFLAGS) $^ -o bin/is$(compiler)
但可执行文件的运行异常仍然存在,程序是仅输出指定文本的简单终端程序,正常运行时会弹出终端窗口打印内容。
修复方案
1. 修正Makefile配置
现有Makefile存在几个明显错误:
- 输出文件名中引用了未定义的
$(compiler)变量,导致生成的文件名混乱 - 没有提前创建
bin、obj目录,首次编译时会报目录不存在错误 - 没有声明伪目标,当目录下存在名为
All/build的文件时,对应规则会失效 - 没有配置静态链接参数(Windows平台下会出现找不到依赖dll的问题)
修复后的完整可用Makefile如下:
CC = g++ CFLAGS = -std=c++2b -Wno-parentheses -Iinclude/ # 不需要引入doc目录头文件就删掉-Idoc/,Windows平台需要静态链接就加-static LDFLAGS = -static # 自动扫描源文件,映射为obj目录下的目标文件 SOURCES := $(wildcard src/*.cpp) OBJECTS := $(patsubst src/%.cpp, obj/%.o, $(SOURCES)) # 定义最终输出的可执行文件路径,不要带未定义变量 TARGET := bin/main # 声明伪目标 .PHONY: all build clean all: build # 自动创建编译产物目录的规则 obj bin: mkdir -p $@ # 编译.o文件,依赖obj目录提前存在 obj/%.o: src/%.cpp | obj $(CC) $(CFLAGS) -c $< -o $@ # 链接生成可执行文件,依赖bin目录提前存在 build: $(OBJECTS) | bin $(CC) $(CFLAGS) $^ -o $(TARGET) $(LDFLAGS) # 清理编译产物规则 clean: rm -rf obj/*.o $(TARGET)
2. 修复可执行文件运行异常
- 文件名问题:上述配置会把可执行文件输出为
bin/main(Windows下自动生成main.exe),不要再使用未定义的$(compiler)变量拼接文件名。 - 工作目录问题:如果代码中使用相对路径读取外部资源(配置文件、文本素材等),程序启动时的工作目录就是执行命令所在的目录,进入bin目录启动、双击启动时工作目录是bin,找不到根目录下的资源就会启动失败。如果是纯打印文本的程序没有外部资源依赖,忽略此条;如果有资源读取逻辑,要么把资源复制到bin目录,要么在代码中获取可执行文件自身路径后拼接资源的绝对路径。
- Windows双击闪退问题:终端程序执行完逻辑后会自动关闭窗口,属于系统默认行为,可以在代码主函数return前加
getchar()或者system("pause")等待用户输入,就能看到输出内容。 - 依赖缺失问题:如果双击提示缺少dll,确认LDFLAGS中加了
-static参数,静态链接libstdc++等依赖库后,生成的exe可以独立运行。
内容的提问来源于stack exchange,提问作者Cheesewaffle
相关产品推荐
相关产品推荐

