如何在Makefile中分别编译主程序与共享库的源文件
我来帮你搞定这个Makefile的问题~
首先得说清楚你原来的规则为啥出问题:你写的$(LIBOBJECTS): $(LIBSOURCES)这种规则,会让所有.o目标都依赖所有源文件。执行编译时用$^会把所有源文件一股脑传给编译器,相当于让g++把两个.cpp合并成一个.o,肯定报错;换成$<又只会取第一个源文件,导致所有.o都用同一个.cpp编译,结果完全不对。
核心解决思路就是让每个.o文件只对应它自己的源文件,不用后缀规则的话,最简洁的方式是用静态模式规则,或者直接为每个源文件单独写编译规则。下面是修改后的完整Makefile:
CC=gcc CXX=g++ DIR=. # 这里改成你实际的头文件目录 CFLAGS=-I$(DIR) -fPIC -c -fopenmp # 我把变量名改得更清晰了,你也可以保留原来的CXXLFLAGS CXXLIBFLAGS=-I$(DIR) -fopenmp -O3 -g -march=native -std=gnu++17 -fPIC -c CXXMAINFLAGS=-I$(DIR) -fopenmp -O3 -g -march=native -std=gnu++17 -c LDFLAGS=-lfftw3 -lgomp -lm -larmadillo -lpthread -lX11 -lboost_system -lboost_program_options -L/opt/intel/mkl/lib/intel64 -lmkl_rt # 链接主程序时库要放在目标文件后面,否则可能找不到符号,这里调整了顺序 LDMAINFLAGS=-L. -lfftw3 -lgomp -lm -larmadillo -lpthread -lX11 -lboost_system -lboost_program_options -L/opt/intel/mkl/lib/intel64 -lmkl_rt -lpulse_propagation LIBSOURCES=source/image_processing.cpp source/pulse_propagation.cpp # 自动生成目标文件列表,不用手动维护 LIBOBJECTS=$(LIBSOURCES:.cpp=.o) MAINSOURCES=source/fftw.cpp source/fftw++.cc # 同时处理.cpp和.cc后缀的源文件 MAINOBJECTS=$(MAINSOURCES:.cpp=.o) MAINOBJECTS=$(MAINOBJECTS:.cc=.o) EXECUTABLE=fftw LIBRARY=libpulse_propagation.so .PHONY: default all clean clean_compile default: all all: $(LIBRARY) $(EXECUTABLE) # 链接主程序 $(EXECUTABLE): $(LIBRARY) $(MAINOBJECTS) $(CXX) $(MAINOBJECTS) $(LDMAINFLAGS) -o $@ # 编译生成共享库 $(LIBRARY): $(LIBOBJECTS) $(CXX) -shared $^ $(LDFLAGS) -o $@ # 静态模式规则:逐个编译共享库的.cpp文件到对应的.o $(LIBOBJECTS): source/%.o: source/%.cpp $(CXX) $(CXXLIBFLAGS) $< -o $@ # 单独编译主程序的.cpp文件 source/fftw.o: source/fftw.cpp $(CXX) $(CXXMAINFLAGS) $< -o $@ # 单独编译主程序的.cc文件 source/fftw++.o: source/fftw++.cc $(CXX) $(CXXMAINFLAGS) $< -o $@ clean_compile: rm -f source/*.o clean: rm -f source/*.o $(EXECUTABLE) $(LIBRARY)
我做了几个关键调整:
- 自动生成目标文件列表:用
$(LIBSOURCES:.cpp=.o)这种语法自动推导.o文件路径,不用手动写,避免出错。 - 静态模式规则处理共享库编译:
$(LIBOBJECTS): source/%.o: source/%.cpp会匹配每个source/xxx.o,对应依赖source/xxx.cpp,用$<取当前源文件、$@取当前目标文件,实现逐个编译。 - 单独处理.cc后缀文件:主程序里有
.cc文件,单独写规则确保用正确的编译标志编译。 - 调整链接顺序:把目标文件放在库的前面,解决链接器可能找不到符号的问题。
如果觉得静态模式不够直观,也可以直接为每个源文件写单独的规则,比如:
source/image_processing.o: source/image_processing.cpp $(CXX) $(CXXLIBFLAGS) $< -o $@ source/pulse_propagation.o: source/pulse_propagation.cpp $(CXX) $(CXXLIBFLAGS) $< -o $@
这种方式更直白,适合源文件不多的场景,效果和静态模式完全一致。
这样修改后,Make就会逐个编译每个源文件,分别生成对应的.o,再链接成共享库和主程序,再也不会出现你之前遇到的问题啦~
内容的提问来源于stack exchange,提问作者arc_lupus
相关产品推荐
相关产品推荐

