cmake中添加引用动态链接_CMake解决动态链接库RPATH错误问题

最近在做C++开发,在MBP上用Cmake构建项目的时候,发现make install之后生成的执行文件会运行出错:

dyld: Library not loaded: @rpath/libadk.dylib

Referenced from: /Users/kesco/Documents/workspaces/cpp/apue_practise/build/bin/./thread

Reason: image not found

[1] 52362 trace trap ./thread

提示我,动态链接库(libadk.dylib也是工程内的一个子项目)找不着。这就奇怪了,因为我make install安装的时候,是把动态链接库和执行文件都放在同一个目录下的。为啥会找不着呢,而之前在Windows下是没问题的,后来查了下Cmake的文档,原来是Cmake版本的问题=_+。

如果你的CMakeList.txt上写的cmake_minium_required为2.6的话,会报下面异常:

....

CMake Warning (dev):

Policy CMP0042 is not set: MACOSX_RPATH is enabled by default. Run "cmake

--help-policy CMP0042" for policy details. Use the cmake_policy command to

set the policy and suppress this warning.

MACOSX_RPATH is not specified for the following targets:

cjson

iniparser

stemmer

word2vec

This warning is for project developers. Use -Wno-dev to suppress it.

-- Generating done

....

而在CMP0042更新,也就是Cmake 2.8.1.2之后,如果你声明的cmake_minium_required为2.8以上,MACOSX_RPATH会默认启动,这时候编译的执行文件在查找链接库的时候会往@rpath上搜索,所以就找不到要链接的库(libadk.dylib在同一个目录下)。我们可以用otool -L 命令来查看执行文件的链接库依赖。

bin git:master ❯ otool -L thread

thread:

@rpath/libadk.dylib (compatibility version 0.0.0, current version 0.0.0)

/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)

知道原因之后就好办了,我们只需在CMakeList.txt上把MACOSX_RPATH关掉就好了。

set(CMAKE_MACOSX_RPATH 0)

add_subdirectory(adk)

add_subdirectory(thread)

....

重新用cmake生成MakeFile构建就不会报错了。不过,RPATH是啥呢?以前写C++的时候都是在Windows上开着VS来的,没遇到过这样的问题,现在遇到了,自然要查清楚。

什么是RPATH?

在Linux环境下,使用动态链接的程序在运行时会自动链接ld.so这个库(OS X上是dyld),然后通过ld.so来查找链接其它的库。而RPATH就是编译的时候链接到执行文件的链接库路径。OS X在RPATH的设置上和Linux还是有点出入的,OS X的RPATH采用的是绝对路径。

ld.so搜索路径的优先级是这样的:

1. RPATH,编译链接时加入-rpath参数指明所谓的RUNPATH,这样可执行文件(或者依赖其他动态链接库的动态链接库)就能告诉ld.so到哪里去搜索对应的动态链接库了。

2. LD_LIBRARY_PATH,对于没有设定RPATH的可执行文件或者动态链接库,我们可以用LD_LIBRARY_PATH这个环境变量通知ld.so往哪里查找链接库。

3. /etc/ld.so.conf,系统对ld.so的路径配置文件。

4. /usr/lib、/lib和/usr/local/lib,系统默认路径。

Cmake和RPATH

在分发程序的时候,执行文件使用的链接库在系统内不一定会有,或者自带了的版本不对,一般都会在程序文件夹内都会附带相应的链接库,所以最好还是把RPATH加上。Cmake对RPATH提供了很多选项支持,我们一般只关注这几个变量就好了:CMAKE_SKIP_BUILD_RPATH、CMAKE_BUILD_WITH_INSTALL_RPATH、CMAKE_INSTALL_RPATH和CMAKE_INSTALL_RPATH_USE_LINK_PATH。

默认RPATH设置

set(CMAKE_SKIP_BUILD_RPATH FALSE) # 编译时加上RPATH

set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # 编译时RPATH不使用安装的RPATH

set(CMAKE_INSTALL_RPATH "") # 安装RPATH为空

set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) # 安装的执行文件不加上RPATH

Cmake在默认情况下,make install会把安装的执行文件的RPATH删掉的,所以就会出现上面我执行安装好的执行文件报错的问题。

加上完整的RPATH

Cmake的默认设置我们肯定是不能使用的,我们需要一个安装的时候也要带上RPATH的设置。

set(INSTALL_LIB_DIR "${PROJECT_BINARY_DIR}/lib") # 假设安装目录在编译目录的lib子目录内

set(CMAKE_SKIP_BUILD_RPATH FALSE)

set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)

set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")

set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

# 确保链接库不在系统默认安装的目录上时更改到项目lib上

list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES ${CMAKE_INSTALL_RPATH} isSystemDir)

if("${isSystemDir}" STREQUAL "-1")

set(CMAKE_INSTALL_RPATH "${INSTALL_LIB_DIR}")

endif("${isSystemDir}" STREQUAL "-1")

现在Cmake在C++项目上应用得越来越多了,但是Cmake的文档很分散,写Cmake构建脚本的时候会踩上很多坑,只能慢慢积累经验总结。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值