使用Makefile链接目标文件时出现undefined reference错误求助
问题:链接FFTW3库时出现
undefined reference错误 在使用分层Makefile链接目标文件生成可执行文件时,出现FFTW3函数的未定义引用错误。已确认头文件路径和库链接参数正确(若路径错误编译时会提示cannot find -lfftw3,但未出现该提示),所有编译环节使用相同参数,单文件版本可正常编译。
错误日志
g++ -g -O3 -lm -I/public/home/AAAAA/BBBBB/IBM/../../fftw3/include -L/public/home/AAAAA/BBBBB/IBM/../../fftw3/lib -lfftw3 -fopenmp -std=c++1z -o /public/home/AAAAA/BBBBB/IBM/build/bin/IBM build/obj/*.o build/obj/main.o: In function `NeumannPESolver2D::NeumannPESolver2D(unsigned int, unsigned int)': /public/home/AAAAA/BBBBB/IBM/src/pe_solver/neumann_pe_solver_2d.h:48: undefined reference to `fftw_plan_dft_r2c_1d' build/obj/neumann_pe_solver_2d.o: In function `NeumannPESolver2D::solve(No_bound_field&, Neumann_field&) [clone ._omp_fn.0]': neumann_pe_solver_2d.cpp:(.text+0x6c8): undefined reference to `fftw_execute_dft_r2c' build/obj/neumann_pe_solver_2d.o: In function `NeumannPESolver2D::solve(No_bound_field&, Neumann_field&) [clone ._omp_fn.2]': neumann_pe_solver_2d.cpp:(.text+0xe90): undefined reference to `fftw_execute_dft_r2c' neumann_pe_solver_2d.cpp:(.text+0xf10): undefined reference to `fftw_execute_dft_r2c' collect2: error: ld returned 1 exit status make: *** [all] Error 1
目录结构
└─AAAAA └─BBBBB ├─fftw3 └─IBM │ Makefile │ └─src │ CMakeLists.txt │ main.cpp │ Makefile │ ... │ ├─helper │ airfoil_reader.hpp │ Makefile │ ├─ns_solver │ ib_cylinder.hpp │ ... │ Makefile │ ├─pe_solver │ Makefile │ neumann_pe_solver_2d.cpp │ neumann_pe_solver_2d.h │ └─structs field.hpp Makefile var.hpp
递归Makefile(子目录中)
INCLUDE_DIR = -I../ FFTW_DIR = $(ROOT_DIR)/../../fftw3 C_FLAGS = -g -O3 -lm -I${FFTW_DIR}/include -L${FFTW_DIR}/lib -lfftw3 -fopenmp -std=c++1z SUBDIRS = $(shell ls -l | grep ^d | awk '{print $$9}') CUR_SOURCE = ${wildcard *.cpp} CUR_OBJS = ${patsubst %.cpp, %.o, $(CUR_SOURCE)} all:$(SUBDIRS) $(CUR_OBJS) $(SUBDIRS):ECHO make -C $@ $(CUR_OBJS):%.o:%.cpp $(CC) $(INCLUDE_DIR) $(C_FLAGS) -c $^ -o $(ROOT_DIR)/$(OBJS_DIR)/$@ ECHO: @echo $(SUBDIRS)
顶层Makefile
CC = g++ SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') ROOT_DIR=$(shell pwd) BIN=IBM OBJS_DIR=build/obj BIN_DIR=build/bin export CC BIN OBJS_DIR BIN_DIR ROOT_DIR FFTW_DIR = $(ROOT_DIR)/../../fftw3 C_FLAGS = -g -O3 -lm -I${FFTW_DIR}/include -L${FFTW_DIR}/lib -lfftw3 -fopenmp -std=c++1z all: make -C $(SUBDIRS) $(CC) $(C_FLAGS) -o $(ROOT_DIR)/$(BIN_DIR)/$(BIN) $(OBJS_DIR)/*.o .PHONY: clean cleanall clean: rm -rf ${BIN_DIR} cleanall: rm -rf build mkdir build mkdir ${OBJS_DIR} mkdir ${BIN_DIR}
可正常编译的单文件Makefile
FFTW_DIR = ../../fftw3 IBM: ./c_oop_ib_demo.cpp g++ $^ -g -O3 -lm -I${FFTW_DIR}/include -L${FFTW_DIR}/lib -lfftw3 -fopenmp -std=c++11 -o $@
解决方案
问题出在编译阶段冗余的链接参数和链接时库的顺序:
编译目标文件时无需链接库:
子目录Makefile编译.o文件时,不需要-lfftw3、-L、-lm这类链接参数,仅需头文件路径和编译参数。修改子目录的C_FLAGS:# 子目录Makefile中的C_FLAGS修改为: C_FLAGS = -g -O3 -I${FFTW_DIR}/include -fopenmp -std=c++1z调整链接时的参数顺序:
GCC链接器按顺序查找符号,库必须放在目标文件之后。修改顶层Makefile的链接命令,将目标文件移到链接参数前面:# 顶层Makefile的all目标修改为: all: make -C $(SUBDIRS) $(CC) $(OBJS_DIR)/*.o $(C_FLAGS) -o $(ROOT_DIR)/$(BIN_DIR)/$(BIN)
更规范的做法是拆分编译和链接参数:
- 顶层Makefile中新增拆分参数:
链接命令改为:CFLAGS = -g -O3 -I${FFTW_DIR}/include -fopenmp -std=c++1z LDFLAGS = -lm -L${FFTW_DIR}/lib -lfftw3$(CC) $(OBJS_DIR)/*.o $(CFLAGS) $(LDFLAGS) -o $(ROOT_DIR)/$(BIN_DIR)/$(BIN) - 子目录Makefile中使用
CFLAGS代替原来的C_FLAGS。
修改后即可正确链接FFTW3库,解决未定义引用问题。
内容的提问来源于stack exchange,提问作者CheapMeow
相关产品推荐
相关产品推荐

