最近在学习caffe
,先是在服务器(Ubuntu 14.04)上安装测试,BLAS
使用的是atlas
。Intel的parallel studio太大了(3.9G),来不及下载,暂时就没有使用。后来又在自己的笔记本上安装,这次使用intel MKL
库,结果就在一个问题上折腾了好久。
问题的大致情况是,编译好了libcaffe.so
,后续编译其他工具,链接这个so的时候,报undefined reference
错误。
CXX/LD -o .build_release/tools/convert_imageset.bin
.build_release/lib/libcaffe.so:对‘cblas_ddot’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_daxpy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dasum’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dcopy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sdot’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dscal’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sgemm’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dgemm’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sgemv’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sscal’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_scopy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_saxpy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dgemv’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sasum’未定义的引用
undefined reference
算是一个经典错误。如果出现在源码编译的时候,则可能是没有正确include
头文件。这里的错误出现在链接阶段,根据出错信息,问题应该是libcaffe.so
缺少需要的定义。
make -n
输出具体的编译命令。echo CXX/LD -o .build_release/tools/upgrade_net_proto_text.bin
g++ .build_release/tools/upgrade_net_proto_text.o -o .build_release/tools/upgrade_net_proto_text.bin -pthread -fPIC -DNDEBUG -O2 -DUSE_CUDNN -I/usr/include/python2.7 -I/usr/lib/python2.7/dist-packages/numpy/core/include -I/usr/local/include -I/opt/opencv/include -I.build_release/src -I./src -I./include -I/usr/local/cuda/include -Wall -Wno-sign-compare -lcaffe -L/usr/lib -L/usr/local/lib -L/usr/lib -L/opt/opencv/lib -L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -L.build_release/lib -lcudart -lcublas -lcurand -lglog -lgflags -lprotobuf -lleveldb -lsnappy -llmdb -lboost_system -lhdf5_hl -lhdf5 -lm -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lboost_thread -lstdc++ -lcudnn \
-Wl,-rpath,\$ORIGIN/../lib
命令有点长,不过细看一下也不难。找到了出错命令,我们就可以直接执行这条语句测试问题所在了。
cblas_*
,所以在caffe目录搜索用到这些函数的hpp
/cpp
文件find . -name *.[hc]pp |xargs grep cblas
vi include/caffe/util/mkl_alternate.hpp
#ifdef USE_MKL
#include <mkl.h>
#else // If use MKL, simply include the MKL header
extern "C" {
#include <cblas.h>
}
如果定义了宏USE_MKL
,则包含头文件mkl.h
。继续在Makefile
中搜索 USE_MKL:
# BLAS configuration (default = ATLAS)
BLAS ?= atlas
ifeq ($(BLAS), mkl)
# MKL
LIBRARIES += mkl_rt
COMMON_FLAGS += -DUSE_MKL
MKLROOT ?= /opt/intel/mkl
BLAS_INCLUDE ?= $(MKLROOT)/include
BLAS_LIB ?= $(MKLROOT)/lib $(MKLROOT)/lib/intel64
else ifeq ($(BLAS), open)
Makefile
写得一点问题没有。查看Intel MKL
安装目录/opt/intel
,权限没有问题,头文件也在,这里找不到问题。
-lcaffe
参数,出错信息就变了,基本确定是libcaffe.so有问题。没办法,搜索“link error so undefined reference to”,这个页面的问题有点类似。
ldd
分析依赖,nm
列出symbol。我发现编译出的libcaffe.so
的依赖里竟然没有找到关键字blas
或intel
,而symbol里确实有一大串出错函数。学习了下nm
输出结果的Undefined symbol
的含义,这些symbol应该由其他库来定义,而现在依赖都没有!
到/opt/intel/mkl/lib/intel64
目录下,nm -A *.so | grep cblas_ddot
,找到了3个so,那么到底需要哪一个呢?好不容易搜索找到一个页面,列出mkl
里各个so文件的用途,我们要用的应该是libmkl_rt.so
。(其实应该搜索intel mkl user guide)
在出错命令相应位置加入-L/opt/intel/mkl/lib/intel64 -lmkl_rt
,运行成功!
Makefile
中正确生成呢?不知道怎么调试makefile
,只能一步步echo
变量内容,最后定位到问题所在:
编辑配置文件Makefile.config
,设置BLAS
,vim
编辑的时候,dw
删除atlas
,光标移动到空格位置,按i
插入,按空格,输入mkl
。mkl
后面多了一个空格,导致后续Makefile
条件判断出错!这里应该按a
插入...
这鸟说明的意思有点难以理解,还是实操体验一下吧……
低级错误,虽然又多了一点经验,但太耗时。只希望遇到问题时,能够冷静分析,精确定位到问题,不然绕了好长的路发现是无用功。
另外,不知道有什么makefile
的调试工具,跟踪每个变量的实际内容,我估计实时打印到标准输出应该就很不错了。