今天在编译组内代码时遇到了Find_package问题,具体来说就是找不到redis的库及相关头文件。

CMake Error at cmake/micros.cmake:75 (find_package):
  By not providing "Findclass_loader.cmake" in CMAKE_MODULE_PATH this project
  has asked CMake to find a package configuration file provided by
  "class_loader", but CMake did not find one.

  Could not find a package configuration file provided by "class_loader" with
  any of the following names:

    class_loaderConfig.cmake
    class_loader-config.cmake

  Add the installation prefix of "class_loader" to CMAKE_PREFIX_PATH or set
  "class_loader_DIR" to a directory containing one of the above files.  If
  "class_loader" provides a separate development package or SDK, be sure it
  has been installed.

 针对上述问题,我们查找并安装了class_loader的开发库,上述问题就解决了。也就是

ok@u20:~/code/micros_information-dev_v2/build$ sudo apt-cache search class_loader
libclass-loader-dev - development files for Robot OS class_loader library
libclass-loader1d - ROS class_loader library
ok@u20:~/code/micros_information-dev_v2/build$ sudo apt-get install libclass-loader-dev
正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
下列软件包是自动安装的并且现在不需要了:
  apport-symptoms python3-systemd
使用'sudo apt autoremove'来卸载它(它们)。
将会同时安装下列软件:
xxxxxx

继续执行cmake,又出现了问题,找不到hiredis库

Could not find a package configuration file provided by "hiredis" with any
  of the following names:

    hiredisConfig.cmake
    hiredis-config.cmake

  Add the installation prefix of "hiredis" to CMAKE_PREFIX_PATH or set
  "hiredis_DIR" to a directory containing one of the above files.  If
  "hiredis" provides a separate development package or SDK, be sure it has
  been installed.

使用前面的方法,发现安装hiredis的开发库之后,仍然报错。

ok@u20:~/code/micros_information-dev_v2/build$ sudo apt-get install libhiredis-dev
正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
下列软件包是自动安装的并且现在不需要了:
  apport-symptoms python3-systemd
使用'sudo apt autoremove'来卸载它(它们)。
下列【新】软件包将被安装:
  libhiredis-dev
xxxxx

然后使用whereis查找hiredis对应的头文件和库。分别在/usr/include/hiredis下面和/usr/lib/x86_64-linux-gnu下面。

ok@u20:/usr/include/hiredis$ ls
adapters  alloc.h  async.h  hiredis.h  read.h  sds.h
ok@u20:/usr/lib/x86_64-linux-gnu$ ls libhi
libhiredis.a        libhiredis.so.0.14  libhistory.so.8.0
libhiredis.so       libhistory.so.8     

于是决定重建hiredis对应的cmake文件,创建/usr/local/lib/cmake/hiredis/hiredisConfig.cmake文件,内容如下:

FIND_PATH(HIREDIS_INCLUDE_DIR hiredis.h
          /usr/local/include
          /usr/include
          )

FIND_LIBRARY(HIREDIS_LIBRARIES NAMES HIREDIS
             PATHS
             /usr/local/lib
             /usr/lib
             /usr/lib/x86_64-linux-gnu
             )

然后重新执行cmake,成功。

上述出现这些错误的原因是因为我们在CMakeLists.txt中使用了find_package操作

find_package(hiredis REQUIRED)

 但是实际上libclass_loader.so和libhireids.so在相同目录下:

ok@u20:/usr/lib/x86_64-linux-gnu$ ls libcl
libclass_loader.so                  libclucene-shared.so.2.3.3.4
libclass_loader.so.0.4.1            libclutter-1.0.so.0
libclass_loader.so.1d               libclutter-1.0.so.0.2600.4
libclucene-contribs-lib.so.1        libclutter-glx-1.0.so.0
libclucene-contribs-lib.so.2.3.3.4  libclutter-gst-3.0.so.0
libclucene-core.so.1                libclutter-gst-3.0.so.0.27.0
libclucene-core.so.2.3.3.4          libclutter-gtk-1.0.so.0
libclucene-shared.so.1              libclutter-gtk-1.0.so.0.800.4

但是为什么class_loader安装后就可以使用了,而hiredis不行呢?因为安装class_loader后,已经有了对应的cmake文件。使用模糊查找如下:

ok@u20:/$ sudo find / -iname "*loaderConfig.cmake"
find: ‘/run/user/1000/doc’: 权限不够
find: ‘/run/user/1000/gvfs’: 权限不够
find: ‘/run/user/125/gvfs’: 权限不够
/usr/share/class_loader/cmake/class_loaderConfig.cmake

 而查找hiredis的cmake文件:

ok@u20:/$ sudo find / -iname "*redisConfig.cmake"
find: ‘/run/user/1000/doc’: 权限不够
find: ‘/run/user/1000/gvfs’: 权限不够
find: ‘/run/user/125/gvfs’: 权限不够
/usr/local/lib/cmake/hiredis/hiredisConfig.cmake
/usr/lib/cmake/Poco/PocoRedisConfig.cmake
/usr/lib/x86_64-linux-gnu/cmake/Hiredis/HiredisConfig.cmake

 可以发现,实际上也是有的,只不过所在位置为/urs/local/x86_64-linux-gnu目录下,而这个目录估计不在Cmake的find_package的查找路径下。因此,针对hiredis这个配置,除了前面编写cmake文件外,也可以修改find_package的搜索路径。

Find_Package()的原理

首先,我们简单了解下Find_Package()的原理,它在搜索包时有两种模式:“Module(模块)”模式和“Config(配置)”模式

在Module模式中,CMake会搜索所有名为Find<package>.cmake的文件,此文件的路径由安装CMake时指定的CMAKE_MODULE_PATH变量指定。如果找到了该文件,它会被CMAKE读取并进行处理,会生成以下相关变量:

// 是否发现该库
<LibaryName>_FOUND
// 头文件
<LibaryName>_INCLUDE_DIR or <LibaryName>_INCLUDES 
// 库文件
<LibaryName>_LIBRARY or <LibaryName>_LIBRARIES

如果在Module模式中没有找到Find<package>.cmake文件,那么会进入Config模式,Cmake会搜索名为<package>Config.cmake与<package>-config.cmake文件,Cmake路径有很多,有兴趣的可以参考下CMake官方教程,这里提供一个常用路径:/usr/local/lib/cmake/xxx/。该配置文件中指定了依赖库的头文件、库文件地址。通过Config模式找到依赖库后,同样也是会生成库的相应变量,供调用者使用。如果没有找到该配置文件,可以自己创建一个,并不复杂。

对于Module模式,用户也可以自己编写对应的文件,方便自定义模块在Cmake中使用。具体可以参考:Cmake中find_package命令的搜索模式之模块模式(Module mode) - 简书 (jianshu.com)

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐