使用PGI PGCC编译链接LAPACK/BLAS库报未定义引用如何解决
问题根因
当前配置存在4个核心错误:
- 编译器选型错误:
pgcc是NVIDIA HPC SDK(原PGI)提供的纯C编译器,不支持C语法(包括extern "C"链接声明),用其编译.cpp后缀的C源文件本身就不匹配,这也是之前添加extern "C"后直接编译失败的核心原因。 - 库路径配置生效阶段错误:
LD_LIBRARY_PATH是程序运行阶段查找动态依赖库的环境变量,编译链接阶段不会读取该变量,未在链接参数中明确指定LAPACK/BLAS库存放路径时,链接器会在默认搜索路径中查找,无法定位到NVHPC安装目录下的库文件。 - 函数声明错误:BLAS、LAPACK均为Fortran实现的库,
dgemm_、dgesvd_属于Fortran子例程,无返回值,对应C/C++中的返回值类型为void,原声明写为int返回值,即使链接成功也会触发调用栈错误。 - 链接参数逻辑错误:库路径参数需要放在链接项最前方,原配置未指定路径直接写库名,链接器无法定位到目标库。
修复步骤
- 调整Makefile配置,替换C++编译器为NVHPC配套的
pgc++,补充链接阶段库搜索路径,修正后的Makefile如下:
LIBRARIES := -lm # C++编译使用pgc++,保留原OpenACC编译选项 PGCXX = pgc++ -Minfo=accel -fast -acc -ta=multicore -tp=nehalem -DDEBUG # 显式指定链接阶段库搜索路径 LIB_SEARCH_PATH := -L/opt/nvidia/hpc_sdk/Linux_x86_64/21.9/compilers/lib/ CFLAGS = -O3 ################################################################################ all: build build: VD VD.o: VD.cpp $(PGCXX) -o $@ -c $< -w VD: VD.o $(PGCXX) $(CFLAGS) -o $@ $+ $(LIB_SEARCH_PATH) -llapack -lblas $(LIBRARIES) clean: rm -f VD.o VD
可选优化:若需要更好的多核性能,可将
-llapack -lblas替换为-mkl=multicore(需安装Intel MKL)或-lacml -lacml_mv(NVHPC自带优化BLAS库,关联LAPACK自动链接),性能优于通用开源BLAS/LAPACK实现。
- 修正源文件中的函数声明,使用
extern "C"包裹Fortran库函数声明,避免C++名字修饰导致符号不匹配,同时修正返回值类型:
// 原有标准库、OpenACC头文件、宏定义保持不变 // 用extern "C"块包裹Fortran库函数声明,指定使用C链接规则 extern "C" { // 修正返回值为void,Fortran子例程无返回值 void dgemm_(char *transa, char *transb, int *m, int * n, int *k, double *alpha, double *a, int *lda, double *b, int *ldb, double *beta, double *c, int *ldc); void dgesvd_(char *jobu, char *jobvt, int *m, int *n, double *a, int *lda, double *s, double *u, int * ldu, double *vt, int *ldvt, double *work, int *lwork, int *info); }
说明:之前添加
extern "C"编译失败,完全是因为误用纯C编译器pgcc编译C++代码,C编译器不识别extern "C"语法,替换为pgc++后该问题会自动解决。
- 重新编译前先执行
make clean清除旧的目标文件,再执行make即可完成编译链接。若仍提示符号找不到,可执行nm /opt/nvidia/hpc_sdk/Linux_x86_64/21.9/compilers/lib/liblapack.so | grep dgesvd查看库内实际符号名,若符号名不带尾部下划线,对应去掉函数名末尾的_即可。
内容的提问来源于stack exchange,提问作者gamersensual
相关产品推荐
相关产品推荐

