前言:
在Ubuntu14.04 LTS版本上编译安装Caffe的教程非常多,安装过程也较为顺利,然而在更新版本系统上编译安装Caffe的过程中,仍会遇到很多问题。其中,在make过程中遇到undefined reference to ‘xxx’,在make runtest 过程中遇到Segmentation faul这两个错误非常常见,在github的BVLC/caffe issues中有非常多类似的问题,e.g.
Caffe 1.0.0-rc3 make failed on Ubuntu 16.04 / CUDA 8.0 #4492
ubuntu16.04 runtest failed #4235
它们的表现形式不同,但是最终都指向一个原因——用GCC4.9本地编译的Caffe和系统自带源中GCC 5.2 编译的库不兼容,无法正确链接。针对这个问题,我专门在github的BVLC/caffe issues中发了帖子指明问题:
ubuntu 15.10 /16.04 runtest : Segmentation fault (core dumped)—— Be sure to link with compatible libraries #4499
由于博主主机的CPU是六代skylake架构,经典的14.04LTS内核较旧不支持,因此选用Linux4.2内核的Ubuntu 15.10。在编译CUDA 7.5时发现:Ubuntu 15.10以及Ubuntu 16.04 LTS 采用gcc 5.X编译器,而cuda7.5不支持gcc5以上(默认不支持,实际支持),因此有两种选择安装CUDA 7.5:
GCC 5.X降级到低版本(e.g. GCC 4.9)。即下载旧版本GCC共享库,然后建立软链接。
【注意】GCC降级后最后也将g++降级到对应版本,否则会在c++程序的编译过程中出现难以发现的错误(可以参考博文: Theano 配置GPU出错:g++: error trying to exec ‘cc1plus’: No such file or directory )
不降级GCC,而是修改/usr/local/cuda-7.5/include中的host_config.h文件,解除对编译器的版本检查。
具体可以参考以下博文:
Ubuntu16.04系统下CUDA7.5配置Caffe教程
其中,降级GCC的方案网上教程用的最多,我也采用该方法,也导致了后来编译Caffe时出现的动态库因编译版本不兼容出现的链接错误。相较而言,我更推荐第二种方法:因为15.10 / 16.04 的默认源(repository)中预编译的库是采用GCC 5的。用GCC 5.x 编译CUDA和Caffe能避免库的兼容性问题。
此外,cuda 8已经完全支持GCC 5编译,读者也可以直接使用CUDA 8.
以下是我在Ubuntu 15.10上采用GCC 4.9.3 编译Caffe时遇到的问题几解决方案:
完整报错信息:
.build_debug/tools/caffe: error while loading shared libraries: libhdf5_hl.so.10: cannot open shared object file: No such file or directory
然而libhdf5.so实际是安装好的,只不过在Ubuntu 15.10中是安装到目录:
/usr/lib/x86_64-linux-gnu/hdf5/serial
解决方案:
因此需要修改Caffe的Makefile.config文件,在INCLUDE_DIRS ,LIBRARY_DIRS中添加如下路径(不同路径间以空格隔开):
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial/
LIBRARY_DIRS := $(PYTHON_LIB) /usr/lib /usr/local/cuda/lib64 /usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/hdf5/serial
apt-get命令下载的libprotobuf、glog、gflags,其共享库.so文件存于/usr/lib/x86-linux-gnu目录,但是make时会出现:
找不到protoc.so.8
使用find命令查找 protoc*,在/usr/lib/x86-linux-gnu中找到protoc.so.9共享库版本不匹配。
解决方法:
下载protobuf源码,手动编译安装。
【注意】手动编译的库采用GCC 4.9编译器,共享库地址在/usr/local/lib, 需要将该路径配置到共享库搜索路径中。
apt-get安装了glog和gflag后,make时在链接阶段 –la 出现undefined reference to ‘xxx’的错误,部分报错信息如下:
CXX/LD -o .build_debug/tools/device_query.bin
CXX/LD -o .build_debug/tools/upgrade_net_proto_binary.bin
.build_debug/lib/libcaffe.so: undefined reference to `google::base::CheckOpMessageBuilder::NewString()'
collect2: error: ld returned 1 exit status
Makefile:616: recipe for target '.build_debug/tools/upgrade_net_proto_binary.bin' failed
make: *** [.build_debug/tools/upgrade_net_proto_binary.bin] Error 1
make: *** Waiting for unfinished jobs....
.build_debug/tools/compute_image_mean.o: In function `std::string* google::MakeCheckOpString(int const&, int const&, char const*)':
/usr/include/glog/logging.h:672: undefined reference to `google::base::CheckOpMessageBuilder::NewString()'
分析: CheckOpMessageBuilder是glog库的类,这说明虽然glog , gflags 等库虽然已经安装(存储于 /usr/lib),但是没有正确链接。
解决方案:
首先autoremove 原先安装的glog, gflags等依赖库;然后使用GCC 4.9 手动编译glob,gflags等依赖库。具体方法参考Caffe官方教程:Ubuntu Installation
问题描述:
在make和make test都成功通过后,运行make runtest进行单元测试。但是一些程序无法通过单元测试,报错信息如下:
[----------] 12 tests from SGDSolverTest/2, where TypeParam = caffe::GPUDevice
[ RUN ] SGDSolverTest/2.TestLeastSquaresUpdateWithWeightDecay
*** Aborted at 1468899438 (unix time) try "date -d @1468899438" if you are using GNU date ***
PC: @ 0x0 (unknown)
*** SIGSEGV (@0x706d742f) received by PID 17550 (TID 0x7f0ef7016a80) from PID 1886221359; stack trace: ***
@ 0x7f0eeffc4d10 (unknown)
@ 0x7f0ef2a41263 boost::filesystem::path::operator/=()
@ 0x4b6dd4 caffe::MakeTempDir()
@ 0x4cf3cf caffe::GradientBasedSolverTest<>::RunLeastSquaresSolver()
@ 0x4e2410 caffe::GradientBasedSolverTest<>::TestLeastSquaresUpdate()
@ 0x4e26ff caffe::SGDSolverTest_TestLeastSquaresUpdateWithWeightDecay_Test<>::TestBody()
@ 0x9327c3 testing::internal::HandleExceptionsInMethodIfSupported<>()
@ 0x92a95a testing::Test::Run()
@ 0x92aaa8 testing::TestInfo::Run()
@ 0x92ab85 testing::TestCase::Run()
@ 0x92b518 testing::internal::UnitTestImpl::RunAllTests()
@ 0x92b7e3 testing::UnitTest::Run()
@ 0x46ea3f main
@ 0x7f0eefc0aac0 __libc_start_main
@ 0x476579 _start
@ 0x0 (unknown)
Makefile:523: recipe for target 'runtest' failed
make: *** [runtest] Segmentation fault (core dumped)
这是一个很隐蔽的错误,在github的Caffe issues中可以搜索到很多类似的问题.
ubuntu16.04 runtest failed #4235中Sean Bell提出错误可能发生在 MakeTempDir,该函数位于caffe/include/caffe/util/io.hpp中
https://github.com/BVLC/caffe/blob/be163be0ea5befada208dbf0db29e6fa5811dc86/include/caffe/util/io.hpp#L24
问题分析与解决方案:
发现函数MakeTempDir用于处理路径的字符串,相关的库有boost和protobuf。
因此我怀疑是apt-get安装boost库出现了问题,于是删除原先安装的libboost-all-dev,下载源码用GCC 4.9手动编译。
最终make runtest 单元测试全部通过。
上述的问题存在一些共性:
1.已经按照教程,使用apt-get命令安装好了Caffe的依赖库protobuf,glog,gflags等,但是make过程中无法编译通过,主要是存在链接错误,未定义的函数。
2. 都是通过手动编译解决的问题。特别是make runtest中的Segmentation fault错误,看似与共享库的链接关系不大,但是最终还是由于boost库的错误引起的。
问题的本质原因:
在Ubuntu 15.10/16.04中默认的编译器是GCC 5.x, 然而CUDA不能被GCC 5以上版本编译(目前最新的CUDA 8已经可以用GCC 5编译) 。于是我将GCC降级到GCC 4.9,但是Ubuntu 15.10/16.04的默认源(repository)中编译好的库采用GCC 5.x。GCC 4.9 和 GCC 5.x的C++ ABI(C++ 二进制兼容接口)不同,ABI::string 已经发生改变。因此,需要确保所链接的共享库具有兼容性!凡是export function中涉及到std::string, std::vector等的库,都必须用同一种编译器编译。
综上,使用与编译Cafffe一致的GCC 4.9编译glog,gflags,boost库能够起作用的真正原因已经找到。
ubuntu 15.10 /16.04 runtest : Segmentation fault (core dumped)—— Be sure to link with compatible libraries #4499
https://github.com/BVLC/caffe/issues/4499Ubuntu16.04系统下CUDA7.5配置Caffe教程
http://blog.csdn.net/g0m3e/article/details/51420565Ubuntu 16.04 or 15.10 Installation Guide
https://github.com/BVLC/caffe/wiki/Ubuntu-16.04-or-15.10-Installation-Guide