当使用cmake编译caffe的情况下,在 cmake生成Makefile时会自动找到系统安装的glog,gflag,但是如是我们自己编译了一个glog,gflag,并没有安装在(/usr)系统目录下,而是放在用户目录(/home)下,要想使用这个glog,gflag版本,不做处理cmake是找不到的。
要想在cmake编译caffe时指定glog,gflag路径,需要下面两步:
#定义GLOG_ROOT_DIR,GFLAGS_ROOT_DIR参数
#$caffe_root caffe源码根目录
cmake $caffe_root -G "Unix Makefiles" \
-DGLOG_ROOT_DIR=$glog_source_root \
-DGFLAGS_ROOT_DIR=$gflags_source_root
这里
$glog_source_root,gflags_source_root
是指glog,gflag源码所在的文件夹。
#修改FindGlog.cmake,FindGFlags.cmake
$caffe_root/cmake/Modules/下的FindGlog.cmake,FindGFlags.cmake
中关于调用find_package寻找glog,gflag的代码有bug(目前还没修改),导致即使如上一步通过GLOG_ROOT_DIR,GFLAGS_ROOT_DIR
指定了glog,gflag路径,cmake也不会找到该路径下的glog,gflag,如果你的/usr
下安装了glog,gflag,它依然会找到系统路径下的版本。所以要对$caffe_root/cmake/Modules/下的FindGlog.cmake,FindGFlags.cmake
做修改:
FindGlog.cmake修改如下:
# modified by guyadong
set(GLOG_ROOT_DIR "" CACHE PATH "Folder contains Google glog")
if(WIN32)
# 增加代码
find_path(GLOG_INCLUDE_DIR glog/logging.h
PATHS ${GLOG_ROOT_DIR}/src/windows NO_DEFAULT_PATH)
find_path(GLOG_INCLUDE_DIR glog/logging.h
PATHS ${GLOG_ROOT_DIR}/src/windows)
else()
# 增加代码
find_path(GLOG_INCLUDE_DIR glog/logging.h
PATHS ${GLOG_ROOT_DIR}
NO_DEFAULT_PATH)
find_path(GLOG_INCLUDE_DIR glog/logging.h
PATHS ${GLOG_ROOT_DIR})
endif()
if(MSVC)
find_library(GLOG_LIBRARY_RELEASE libglog_static
PATHS ${GLOG_ROOT_DIR}
PATH_SUFFIXES Release NO_DEFAULT_PATH)
find_library(GLOG_LIBRARY_RELEASE libglog_static
PATHS ${GLOG_ROOT_DIR}
PATH_SUFFIXES Release)
find_library(GLOG_LIBRARY_DEBUG libglog_static
PATHS ${GLOG_ROOT_DIR}
PATH_SUFFIXES Debug NO_DEFAULT_PATH)
find_library(GLOG_LIBRARY_DEBUG libglog_static
PATHS ${GLOG_ROOT_DIR}
PATH_SUFFIXES Debug)
set(GLOG_LIBRARY optimized ${GLOG_LIBRARY_RELEASE} debug ${GLOG_LIBRARY_DEBUG})
else()
# 增加代码
find_library(GLOG_LIBRARY glog
PATHS ${GLOG_ROOT_DIR}
PATH_SUFFIXES lib lib64
NO_DEFAULT_PATH)
find_library(GLOG_LIBRARY glog
PATHS ${GLOG_ROOT_DIR}
PATH_SUFFIXES lib lib64)
endif()
FindGFlags.cmake修改如下
# modified by guyadong
# We are testing only a couple of files in the include directories
if(WIN32)
# 增加代码
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h
PATHS ${GFLAGS_ROOT_DIR}/src/windows NO_DEFAULT_PATH)
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h
PATHS ${GFLAGS_ROOT_DIR}/src/windows)
else()
# 增加代码
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h
PATHS ${GFLAGS_ROOT_DIR}/include
NO_DEFAULT_PATH)
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h
PATHS ${GFLAGS_ROOT_DIR}/include)
endif()
if(MSVC)
# 增加代码
find_library(GFLAGS_LIBRARY_RELEASE
NAMES libgflags
PATHS ${GFLAGS_ROOT_DIR}
PATH_SUFFIXES Release NO_DEFAULT_PATH)
find_library(GFLAGS_LIBRARY_RELEASE
NAMES libgflags
PATHS ${GFLAGS_ROOT_DIR}
PATH_SUFFIXES Release)
# 增加代码
find_library(GFLAGS_LIBRARY_DEBUG
NAMES libgflags-debug
PATHS ${GFLAGS_ROOT_DIR}
PATH_SUFFIXES Debug NO_DEFAULT_PATH)
find_library(GFLAGS_LIBRARY_DEBUG
NAMES libgflags-debug
PATHS ${GFLAGS_ROOT_DIR}
PATH_SUFFIXES Debug)
set(GFLAGS_LIBRARY optimized ${GFLAGS_LIBRARY_RELEASE} debug ${GFLAGS_LIBRARY_DEBUG})
else()
find_library(GFLAGS_LIBRARY gflags PATHS ${GFLAGS_ROOT_DIR}/lib NO_DEFAULT_PATH)
find_library(GFLAGS_LIBRARY gflags PATHS ${GFLAGS_ROOT_DIR}/lib)
endif()
比对原始代码 ,就可以发现,只是将每个find_library
调用增加了NO_DEFAULT_PATH
参数再执行一次
#原因分析
这个问题的根本原因在于代码作者对cmake的find_library的查找机制没有全搞明白
简单说就是调用find_library时,会以从一组路径中顺序查找指定的库,这有一个优先序问题,如果没有指定了NO_DEFAULT_PATH
,则会先查找默认的系统库路径
如果指定了NO_DEFAULT_PATH
,则只查找PATHS提供的路径,不会查找系统库路径。因为所以原始代码中没有加NO_DEFAULT_PATH
导致每次只能找到系统路径下的库。
如何保证PATHS指定的路径优先被搜索呢?
解决的办法cmake官网也给出来了,就是调用两次find_library,第一次加NO_DEFAULT_PATH
,第二次则不加。
The default search order is designed to be most-specific to least-specific for common use cases. Projects may override the order by simply calling the command multiple times and using the NO_* options:
find_library ( NAMES name PATHS paths… NO_DEFAULT_PATH)
find_library ( NAMES name)
Once one of the calls succeeds the result variable will be set and stored in the cache so that no call will search again.
另外,$caffe_root/cmake/Modules/
下的FindLevelDB.cmake,FindLMDB.cmake,FindOpenBLAS.cmake,FindSnappy.cmake都存在相同的问题。解决办法是一样的。
#参数资料
《find_library》