• 【cmake开发(8)】cmake 编译无法找到库,和编译通过后运行时无法找到库


    这两个问题是比较典型的。

    cmake 编译无法找到库

    这个看《【cmake开发(6)】Cmakelists 使用 gcc/g++指定版本,find_package 基本原理》中find_package 的原理。

    如果不使用find

    确保三个路径配置好了:
    1、#设置包括的头文件

    include_directories(
            ${CMAKE_CURRENT_SOURCE_DIR}
            ${CMAKE_CURRENT_BINARY_DIR}
            ${CMAKE_CURRENT_SOURCE_DIR}/include
     )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、设置搜索的库目录

    link_directories(
        ${CMAKE_CURRENT_SOURCE_DIR}/libs
    )
    
    • 1
    • 2
    • 3

    3、目标生成

    target_link_libraries( demo
                           # 目标库需要链接的库
                           ${log-lib} )
    
    • 1
    • 2
    • 3

    如果使用find

    在CMakeList.txt我们经常看见find_package这个命令,如
    find_package(yaml-cpp REQUIRED)
    当找不到包时,则会报错,停止编译。
    1.2.1 让 find_package 到指定路径找包,有三种方法
    1 设置 DIR

       	  set(yaml-cpp_DIR ~/yaml-cpp)
    	  find_package(yaml-cpp REQUIRED)
    
    • 1
    • 2

    2 设置PATHS

    	  set(yaml-cpp required PATHS ~/yaml-cpp)
    
    • 1

    3 指定 DCMAKE_PREFIX_PATH

    	  cmake -DCMAKE_PREFIX_PATH="~/yaml-cpp" ..
    
    • 1

    另外《【cmake开发(11)】CMake中的CMAKE_PREFIX_PATH使用技巧与示例》会记录DCMAKE_PREFIX_PATH的用法,可以参考

    编译通过后运行时无法找到库

    因为运行和编译是不一样的,编译时 cmake 会组织“材料” 进行加工。运行时,需要使用 系统的寻库程序进行。因此需要依靠系统的工具实现

    查找问题

    在之前的文章《【编译原理】linux动态链接库的路径及依赖的查询objdump 和ldd》提到了工具 ldd 查看。

    1、一个 二进制文件(动态库、可执行程序)还可能依赖别的动态库,可用以下命令去查询[7]:

    $ objdump -x libxxxxx.so | grep NEEDED
    
    • 1

    2、 还可以直接使用ldd命令查看动态库的依赖关系:

    ldd libXXX.so
    
    • 1

    3、通过 file 命令来查看库的编译平台:

    file xxx.so
    
    • 1

    4、readelf命令,一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(.so)或者静态库(.a) 等包含ELF格式的文件。
    使用方式(usage)

          readelf -d test   #test为可执行文件
          readelf -d libc.so.6  #libc.so.6为动态库
    
    • 1
    • 2

    解决问题

    方式 1、/etc/ld.so.conf ,我们帮助系统找到库

    /etc/ld.so.conf 此文件记录了编译时使用的动态库的路径,也就是加载so库的路径

    查到/etc/ld.so.conf这个文件,此文件记录了编译时使用的动态库的路径,也就是加载so库的路径。将/usr/lib加入到文件/etc/ld.so.conf中,执行ldconfig命令,刷新库文件缓存。

    具体分析
    1、默认情况下,编译器只会使用/lib和/usr/lib这两个目录下的库文件,而通常通过源码包进行安装时,如果不指定–prefix会将库安装在/usr/local目录下,而又没有在文件/etc/ld.so.conf中添加/usr/local/lib这个目录。这样虽然安装了源码包,但是使用时仍然找不到相关的.so库,就会报错。也就是说系统不知道安装了源码包。对于此种情况有2种解决办法:

    (1) 在用源码安装时,用–prefix指定安装路径为/usr/lib。
    (2) 直接将路径/usr/local/lib路径加入到文件/etc/ld.so.conf文件的中。在文件/etc/ld.so.conf中末尾直接添加:/usr/local/lib(这个方法给力!)

    ldconfig
    再来看看ldconfig这个程序,位于/sbin下,它的作用是将文件/etc/ld.so.conf列出的路径下的库文件缓存到/etc/ld.so.cache以供使用,因此当安装完一些库文件,或者修改/etc/ld.so.conf增加了库的新的搜索路径,需要运行一下ldconfig,使所有的库文件都被缓存到文件/etc/ld.so.cache中,如果没做,可能会找不到刚安装的库。

    方式 2、修改二进制文件里面的 rpath

    方法1.chrpath 修改rpath

    安装chrpath,sudo apt install chrpath

        #显示rpath路径,比如
          chrpath -l xxx.so  或者 chrpath -l test
         
        #修改rpath路径,比如
          chrpath -r ./lib xxx.so    #其中./lib是需要修改的路径,xxx.so为源路径库
          chrpath -r ./lib test    #其中./lib是需要修改的路径,test可执行文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    方法2.patchelf设置rpath

    安装patchelf sudo apt install patchelf

      patchelf --set-rpath  ./lib  xxx.so   #其中./lib是需要修改的路径,xxx.so为源路径库
    
    • 1
    方法3.gcc 指定rpath 编译选项(推荐)

    GCC详解的-Wl选项说明与测试

    gcc -o test test.c -I. -L. -lc -Wl,-rpath=.   
    
    • 1
    其中
    
    -I. 是指定头文件路径为当前目录下;
    
    -L. 是指定库文件路径为当前目录下;
    
    -lc 是从-L指定库文件路径下去找libc.so.6这个库,也就是库名砍头去尾(类似使用过-lpthread);
    
    -Wl,-rpath=. 为告诉编译器将后面的参数传递给链接器。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    方法 4.cmake中指定rpath选项(推荐)
        IF(UNIX)
        	set(CMAKE_SKIP_BUILD_RPATH TRUE)
    		set(CMAKE_CXX_FLAGS   "-Wl,-z,origin,-rpath,$ORIGIN")
        ENDIF()
    
    • 1
    • 2
    • 3
    • 4

    或者

        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
    
    • 1
    • 2
    • 3
    • 4

    方式 3 修改环境变量

    设置LD_LIBRARY_PATH

      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/yimning/lib  
    
    • 1

    冒号:为设置多个路径下的分割符号。设置之后再去编译即可。

            export -p //列出当前的环境变量值
            export MYENV //定义环境变量
            export MYENV=7 //定义环境变量并赋值
    
    • 1
    • 2
    • 3

    如果直接使用export声明变量,则export 的效力仅限于该次登陆操作。如果想要持久化生效,则需要将export命令写入 /etc/profile 文件或者/root/.bashrc文件中。

    参考

    https://blog.csdn.net/Castlehe/article/details/107630544
    https://cloud.tencent.com/developer/article/1342894
    https://www.runoob.com/linux/linux-comm-export.html

  • 相关阅读:
    DC优化(Optimization)是在做什么?
    机智云无需代码就能搞定IoT小程序开发和管理
    如何优雅的使用contorller层
    [hive]搭建hive3.1.2hiveserver2高可用可hive metastore高可用
    硅纪元AI应用推荐 | 百度橙篇成新宠,能写万字长文
    微信小程序引入字体在部分机型失效不兼容解决办法
    read 方法为什么返回 int 类型
    【数据结构】链表面试题
    docker --建立私有仓库registry
    Jmeter——循环控制器中实现Counter计数器的次数重置
  • 原文地址:https://blog.csdn.net/djfjkj52/article/details/131243531