OpenBLAS:改进OpenBLASConfig.cmake生成方式,解除cmake脚本的路径依赖

问题描述

当我们用OpenBLAS提供的Makefile进行编译,并用make install PREFIX=/you/install/path,安装到指定的路径时,你会发现,/you/install/path/lib/cmake/openblas/OpenBLASConfig.cmake文件中OpenBLAS_INCLUDE_DIRS和OpenBLAS_LIBRARIES的值都是绝对路径,如下:

/you/install/path/lib/cmake/openblas/OpenBLASConfig.cmake (linux下生成动态库)

SET(OpenBLAS_VERSION "0.2.18")
SET(OpenBLAS_INCLUDE_DIRS /home/hadoop/Desktop/caffe-static/release/OpenBLAS_linux_x86_64/include)
SET(OpenBLAS_LIBRARIES /home/hadoop/Desktop/caffe-static/release/OpenBLAS_linux_x86_64/bin/libopenblas.so)

(linux下生成静态库)

SET(OpenBLAS_VERSION "0.2.18")
SET(OpenBLAS_INCLUDE_DIRS /home/hadoop/Desktop/caffe-static/release/OpenBLAS_linux_x86_64/include)
SET(OpenBLAS_LIBRARIES /home/hadoop/Desktop/caffe-static/release/OpenBLAS_linux_x86_64/lib/libopenblas.a)

(windows下生成动态库)

SET(OpenBLAS_VERSION "0.2.18")
SET(OpenBLAS_INCLUDE_DIRS D:/caffe-static/release/OpenBLAS_windows_vc140_x86_mt/include)
SET(OpenBLAS_LIBRARIES D:/caffe-static/release/OpenBLAS_windows_vc140_x86_mt/bin/libopenblas.dll)

关于windows下如何用MinGW编译OpenBLAS,参见我的另一篇博客《Windows下MSYS2中编译OpenBLAS过程记录》

如果你编译OpenBLAS只是在本机使用,那没啥问题,如果想把这个编译好的OpenBLAS 移到别的位置或提供给别人使用,并且也是用cmake编译项目。那么问题就来了,因为OpenBLASConfig.cmake中的路径依赖问题,导致cmake脚本中调用find_package( OpenBLAS NO_MODULE )返回的OpenBLAS_LIBRARIES和OpenBLAS_LIBRARIES的值都是错的!

而且你发现没有?上面Windows下生成的OpenBLASConfig.cmake中OpenBLAS_LIBRARIES的值居然是.dll的路径。而不是动态库导入库(import library)(.dll.a)的路径,也就是说OpenBLAS在生成OpenBLASConfig.cmake没有考虑到linux和windows的区别,只是按linux的方式将OpenBLAS_LIBRARIES置为静态库/动态库(.a,.so,dll)的路径。

如果你是用手工在Visual Studio中创建工程并设置工程参数,那么这都不是问题,对你没有任何影响,但如果你像我一样,用cmake进行工程编译,这是个很要命的问题,因为cmake根据这些错误的信息无法生成正确的Makefile,当然也不能正常编译。

原因分析

怎么办呢?指望OpenBLAS官方修改这个问题怕是来不及了,只能自己想办法解决。 于是我仔细研究了OpenBLAS的Makefile的体系。算是基本搞清楚了OpenBLAS源码下那一大堆Makefile.*的作用。最终找到了问题的关键点: Makefile.install 这个文件是OpenBLAS的安装脚本,当执行 make install时其实就是执行这个脚本来执行安装工作的。

而在这其中生成OpenBLASConfig.cmake的代码就是如下几行(line 97-116 OpenBLAS 0.2.18) (中文注释为本文作者所加)

#Generating OpenBLASConfig.cmake
    @echo Generating $(OPENBLAS_CMAKE_CONFIG) in $(DESTDIR)$(OPENBLAS_CMAKE_DIR)
    # 对应OpenBLASConfig.cmake中line 1
    @echo "SET(OpenBLAS_VERSION \"${VERSION}\")" > $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)    
    # 对应OpenBLASConfig.cmake中line 2
    @echo "SET(OpenBLAS_INCLUDE_DIRS ${OPENBLAS_INCLUDE_DIR})" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)

ifndef NO_SHARED
#ifeq logical or
# 判断操作系统将OpenBLAS_LIBRARIES置为动态库文件路径
ifeq ($(OSNAME), $(filter $(OSNAME),Linux FreeBSD NetBSD))
    # 对应OpenBLASConfig.cmake中line 3
    @echo "SET(OpenBLAS_LIBRARIES ${OPENBLAS_LIBRARY_DIR}/$(LIBPREFIX).so)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif
ifeq ($(OSNAME), $(filter $(OSNAME),WINNT CYGWIN_NT))
    # 对应OpenBLASConfig.cmake中line 3
    # 这里 LIBDLLNAME   = $(LIBPREFIX).dll 参见 Makefile.system
    @echo "SET(OpenBLAS_LIBRARIES ${OPENBLAS_BINARY_DIR}/$(LIBDLLNAME))" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif
ifeq ($(OSNAME), Darwin)
    # 对应OpenBLASConfig.cmake中line 3
    @echo "SET(OpenBLAS_LIBRARIES ${OPENBLAS_LIBRARY_DIR}/$(LIBPREFIX).dylib)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif
else
# 将OpenBLAS_LIBRARIES置为静态库文件路径
#only static
    # 对应OpenBLASConfig.cmake中line 3
    @echo "SET(OpenBLAS_LIBRARIES ${OPENBLAS_LIBRARY_DIR}/$(LIBPREFIX).$(LIBSUFFIX))" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif

OPENBLAS_INCLUDE_DIR,OPENBLAS_LIBRARY_DIR,OPENBLAS_BINARY_DIR在Makefile.install文件开头定义 (line 8-10 OpenBLAS 0.2.18)

上面的三行@echo的代码清晰的对应着OpenBLASConfig.cmake中的三行代码,由此我们理解为什么OpenBLASConfig.cmake中的路径都是绝对路径,而且windows下OpenBLAS_LIBRARIES的值是.dll文件的路径了。

解决方法

原因搞清楚就好办了,要解决问题,只要修改上面这段代码,改进生成OpenBLASConfig.cmake的逻辑就可以了。

以下是上面代码(Makefile.install)修改后的版本:

#Generating OpenBLASConfig.cmake
# modified by guyadong for windows build
    @echo Generating $(OPENBLAS_CMAKE_CONFIG) in $(DESTDIR)$(OPENBLAS_CMAKE_DIR)  
    @echo "SET(OpenBLAS_VERSION \"${VERSION}\")" > $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)  
    @echo "# modified by guyadong,use relative path instead of absolute path" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)   
    @echo "# Compute the installation prefix relative to this file." >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)    
    @echo "get_filename_component(_IMPORT_PREFIX \"\$${CMAKE_CURRENT_LIST_FILE}\" PATH)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "get_filename_component(_IMPORT_PREFIX \"\$${_IMPORT_PREFIX}\" PATH)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)  
    @echo "get_filename_component(_IMPORT_PREFIX \"\$${_IMPORT_PREFIX}\" PATH)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)  
    @echo "get_filename_component(_IMPORT_PREFIX \"\$${_IMPORT_PREFIX}\" PATH)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)  
    @echo "if(_IMPORT_PREFIX STREQUAL \"/\")" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo " set(_IMPORT_PREFIX \"\")" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "endif()" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "SET(OpenBLAS_INCLUDE_DIRS \$${_IMPORT_PREFIX}/include)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)

ifndef NO_SHARED
#ifeq logical or
ifeq ($(OSNAME), $(filter $(OSNAME),Linux FreeBSD NetBSD))
    @echo "SET(OpenBLAS_LIBRARIES \$${_IMPORT_PREFIX}/lib/$(LIBPREFIX).so)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif
ifeq ($(OSNAME), $(filter $(OSNAME),WINNT CYGWIN_NT))
# windows下编译时生成条件判断语句
    @echo "# use dynamic import library if MSVC" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)    
    @echo "if(MSVC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo " SET(OpenBLAS_LIBRARIES \$${_IMPORT_PREFIX}/lib/$(LIBDLLNAME).a)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "else(MSVC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo " SET(OpenBLAS_LIBRARIES \$${_IMPORT_PREFIX}/bin/$(LIBDLLNAME))" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "endif(MSVC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "SET(OPENBLAS_IS_DYNAMIC true)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif
ifeq ($(OSNAME), Darwin)
    @echo "SET(OpenBLAS_LIBRARIES \$${_IMPORT_PREFIX}/lib/$(LIBPREFIX).dylib)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif
else
#only static
    @echo "SET(OpenBLAS_LIBRARIES \$${_IMPORT_PREFIX}/lib/$(LIBPREFIX).$(LIBSUFFIX))" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
# windows下编译时生成条件判断语句
ifeq ($(OSNAME), $(filter $(OSNAME),WINNT CYGWIN_NT))    
    @echo "if(MSVC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo " message(STATUS \"OpenBLAS_LIBRARIES(static library):\$${OpenBLAS_LIBRARIES}\" )" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo " message(FATAL_ERROR \"With Visual Studio, only dynamic linking is supported,please reinstall OpenBLAS without NO_STATIC=1\" )" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "endif(MSVC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "SET(OPENBLAS_IS_DYNAMIC false)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif   
endif
ifeq ($(OSNAME), $(filter $(OSNAME),WINNT CYGWIN_NT))    
    @echo "# if OpenBlas_USE_STATIC is true,force to use static library with MinGW" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "if(OPENBLAS_IS_DYNAMIC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo " if(EXISTS \"\$${_IMPORT_PREFIX}/lib/$(LIBPREFIX).$(LIBSUFFIX)\" AND OpenBlas_USE_STATIC AND NOT MSVC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "     MESSAGE(STATUS \"use OpenBlas static library\")" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "     SET(OpenBLAS_LIBRARIES \$${_IMPORT_PREFIX}/lib/$(LIBPREFIX).$(LIBSUFFIX))" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo " endif()" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "endif(OPENBLAS_IS_DYNAMIC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
    @echo "unset(OPENBLAS_IS_DYNAMIC)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)
endif
    @echo "unset(_IMPORT_PREFIX)" >> $(DESTDIR)$(OPENBLAS_CMAKE_DIR)/$(OPENBLAS_CMAKE_CONFIG)

经过上面的修改,再重新执行make install PREFIX=/you/install/path,生成的OpenBLASConfig.cmake(中文注释为本文作者所加) (linux下生成静态态库)

# modified by guyadong,use relative path instead of absolute path
# Compute the installation prefix relative to this file.
# 三次调用 get_filename_component 计算 OpenBLAS安装路径
# _IMPORT_PREFIX为OpenBLAS安装路径
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_DIR}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
    set(_IMPORT_PREFIX "")
endif()
SET(OpenBLAS_INCLUDE_DIRS ${_IMPORT_PREFIX}/include)
SET(OpenBLAS_LIBRARIES ${_IMPORT_PREFIX}/lib/libopenblas.a)
unset(_IMPORT_PREFIX)

(windows下生成动态库)

# modified by guyadong,use relative path instead of absolute path
# Compute the installation prefix relative to this file.
# 三次调用 get_filename_component 计算 OpenBLAS安装路径
# _IMPORT_PREFIX为OpenBLAS安装路径
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_DIR}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
    set(_IMPORT_PREFIX "")
endif()
SET(OpenBLAS_INCLUDE_DIRS ${_IMPORT_PREFIX}/include)
# 判断编译器类型,MSVC下置为import library(.dll.a) ,否则(MinGW)置为.dll
if(MSVC)
    SET(OpenBLAS_LIBRARIES ${_IMPORT_PREFIX}/lib/libopenblas.dll.a)
else(MSVC)
    SET(OpenBLAS_LIBRARIES ${_IMPORT_PREFIX}/bin/libopenblas.dll)
endif(MSVC)
SET(openblas_is_dynamic true)
# if OpenBlas_USE_STATIC is true,force to use static library with MinGW
if(openblas_is_dynamic)
    # 使用MinGW编译时,如果定义了OpenBlas_USE_STATIC,则置为静态库
    if(EXISTS "${_IMPORT_PREFIX}/lib/libopenblas.a" AND OpenBlas_USE_STATIC AND NOT MSVC)
        SET(OpenBLAS_LIBRARIES ${_IMPORT_PREFIX}/lib/libopenblas.a)
    endif()
endif(openblas_is_dynamic)
unset(openblas_is_dynamic)
unset(_IMPORT_PREFIX)

完整代码

修改后的OpenBLAS Makefile.install完整代码参见 :

https://gitee.com/l0km/caffe-static/tree/master/patch/OpenBLAS-0.2.18/Makefile.install

后记

本文对 Makefile.install的修改已经申请 Pull Request ,如果被接受,后续OpenBLAS的版本就不需要这样手工修改了。 https://github.com/xianyi/OpenBLAS/pull/1231

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏沃趣科技

ASM 翻译系列第二十二弹:ASM Internal ASM file number 8

原作者:Bane Radulovic 译者: 郭旭瑞 审核: 魏兴华 DBGeeK社群联合出品 ASM file number 8 ASM元信息8号...

3365
来自专栏Hadoop实操

如何在CDH中使用HPLSQL实现存储过程

目前版本的Hive中没有提供类似存储过程的功能,使用Hive做数据应用开发时候,一般有以下两种方法:

7117
来自专栏菩提树下的杨过

puremvc框架之Command

在前一篇 puremvc框架之hello world! 里,已经对这个框架有了一个大概的认识,不过在消息的处理上,有一个不太适合的地方: 为了完成响应消息,Te...

1757
来自专栏沃趣科技

ASM 翻译系列第三十一弹:了解ASM文件的空间分配

原作者:Bane Radulovic 译者: 邱大龙 审核: 魏兴华 DBGeeK社区联合出品 How many allocation units ...

3267
来自专栏杨建荣的学习笔记

一次数据库宕机问题的分析(r6笔记第5天)

今天来到办公室,发现有一台服务器中的数据库实例停掉了。这种情况真是意料之外,尤其是我还不是很熟悉这台机器的服务。 赶紧查看数据库日志,可以看到数据库在昨晚停掉了...

3495
来自专栏三杯水

使用ELK分析腾讯云CLB日志

最近在使用腾讯云,想对访问日志进行收集与分析,发现CLB(负责均衡)日志只能保存到COS上面,而且是每个CLB没小时压发送个gz压缩包到COS。

1073
来自专栏jeremy的技术点滴

nagios安装配置

3677
来自专栏杨建荣的学习笔记

生产系统中EXP-00000的问题及解决(66天)

早上刚来的时候,客户的dba就急忙找到我说生产系统exp出问题了。exp的时候报了错误,让我帮着看一下。 > exp xxxxx file=tui.dmp l...

2976
来自专栏乐沙弥的世界

publickey,gssapi-with-mic,Unspecified GSS failure

        最近的MHA配置时碰到了Permission denied (publickey,gssapi-with-mic,password)这个错误提示...

632
来自专栏杨建荣的学习笔记

Oracle备库无法连接主库的问题分析

今天在搭建DG的时候碰到了一个蛮有意思的问题,耗费了不少脑细胞,简单记录一下。 首先主库是Queuedb,备库是s2queuedb,使用RMAN的duplica...

3446

扫码关注云+社区