Cmake语句find_package()函数

参考:

Cmake语句find_package()函数 https://blog.youkuaiyun.com/sen873591769/article/details/90183015

深入理解CMake(3):find_package()的使用  https://www.jianshu.com/p/39fc5e548310

find_package()函数  https://blog.youkuaiyun.com/fb_941219/article/details/88526157

 

背景

如果我们在cmake某个程序的时候,经常会提示找不到某个所依赖的库,那么这是时候我们就需要检查我们引入依赖库的路径对不对了, Cmake中一个自动寻找函数find_package()可以帮我们实现这个功能。

//以slam十四讲中的joinMap程序Cmake文件为例:
cmake_minimum_required( VERSION 2.8 )
project( joinMap )

set( CMAKE_BUILD_TYPE Release )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )

# opencv 
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )

# eigen 
include_directories( "/usr/include/eigen3/" )

# pcl 
find_package( PCL REQUIRED COMPONENT common io )
include_directories( ${PCL_INCLUDE_DIRS} )
add_definitions( ${PCL_DEFINITIONS} )

list(REMOVE_ITEM PCL_LIBRARIES "vtkproj4")
add_executable( joinMap joinMap.cpp )
target_link_libraries( joinMap ${OpenCV_LIBS} ${PCL_LIBRARIES} )


概括来说,以opencv为例:find_package()函数,如果找到了相关的头文件和库文件,则会相应保存在OpenCV_INCLUDE_DIRS OpenCV_LIBRARIES (OpenCV_LIBS) 中。
我们可以输出一下看看上面两个cmake变量是什么内容,在上述文件后面加如下代码:

message("!!!!!!!!OpenCV_INCLUDE_DIRS:" ${OpenCV_INCLUDE_DIRS})
message("!!!!!!!!OpenCV_LIBRARIES:" ${OpenCV_LIBRARIES} )

可以看出我们实际上拿到了所有这个依赖库的头文件路径和所有库文件

关键字解释

下面我们说一说find_package()的语法:

  • version和EXACT: 都是可选的,version指定的是版本,如果指定就必须检查找到的包的版本是否和version兼容。如果指定EXACT则表示必须完全匹配的版本而不是兼容版本就可以。
  • QUIET 可选字段,表示如果查找失败,不会在屏幕进行输出(但是如果指定了REQUIRED字段,则QUIET无效,仍然会输出查找失败提示语)。
  • MODULE可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如设定了MODULE选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。
  • CONFIG可选字段。直接在Config模式中查找。下文会介绍什么是Moudule模式什么是Config模式。
  • REQUIRED可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定REQUIRED则cmake会继续执行。
  • COMPONENTS:可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于REQUIRED,导致cmake停止执行。上面的例子中find_package( PCL REQUIRED COMPONENT common io )我们就利用了该关键字寻找了common和io包。
  • OPTIONAL_COMPONENTS:可选的模块,找不到也不会让cmake停止执行。

find_package原理

首先,cmake本身不提供任何搜索库的便捷方法,所有搜索库并给变量赋值的操作必须由cmake代码完成,比如FindXXX.cmake和XXXConfig.cmake。只不过,库的作者通常会提供这两个文件,以方便使用者调用。
find_package采用两种模式搜索库:

  • Module模式:搜索CMAKE_MODULE_PATH指定路径下的FindXXX.cmake文件,执行该文件从而找到XXX库。其中,具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由FindXXX.cmake模块完成(先搜索当前项目里面的Module文件夹里面提供的FindXXX.cmake,然后再搜索系统路径/usr/local/share/cmake-x.y/Modules/FindXXX.cmake)
  • Config模式:搜索XXX_DIR指定路径下的XXXConfig.cmake文件,执行该文件从而找到XXX库。其中具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成。

对于可能没有***.cmake和***Config.cmake的库文件,可以直接找到其头文件和库文件所在文件夹,直接进行路径赋值:

SET(LAPACK_DIR /usr/local/lib/) 
SET(LAPACK_INCLUDE_DIRS /usr/local/include) 
SET(LAPACK_LIBRARIES /usr/local/lib)


相关命令:pkg-config

pkg-config可用与列举出某个库的相关信息,比如此库的路径、相关头文件路径等,这在程序编译时将非常有用。例如,现在要编译一个依赖librtmp.so库的程序。去哪找librtmp.so相关的头文件呢?librtmp.so库又在哪呢?这是一个大问题,但有了pkg-config后这些都不是问题。先使用以下命令看看:


yuan@yuan:~$ pkg-config --cflags yaml-cpp
-I/usr/local/include
yuan@yuan:~$ pkg-config --libs yaml-cpp
-L/usr/local/lib -lyaml-cpp
yuan@yuan:~$ pkg-config --libs opencv
-lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_videostab 
-lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib 
-lopencv_datasets -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy 
-lopencv_hdf -lopencv_line_descriptor -lopencv_optflow -lopencv_video 
-lopencv_plot -lopencv_reg -lopencv_saliency -lopencv_stereo 
-lopencv_structured_light -lopencv_phase_unwrapping -lopencv_rgbd 
-lopencv_viz -lopencv_surface_matching -lopencv_text -lopencv_ximgproc 
-lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_xobjdetect 
-lopencv_objdetect -lopencv_ml -lopencv_xphoto -lopencv_highgui 
-lopencv_videoio -lopencv_imgcodecs -lopencv_photo -lopencv_imgproc -lopencv_core



看到没,pkg-config能找出头文件的路径,也能找出库存放在哪而且还能知道依赖的其它库

有了pkg-config后,当我编译程序要使用librtmp.so库时,就可以这么写:

jeason@Mi-Jeason:~$ gcc sample.c -o sample `pkg-config --cflags --libs librtmp`  

哈哈哈哈,有了pkg-config,妈妈再也不用担心我程序编译时找不到库了。

那么,问题也来了,pkg-config又是如何知道库存放路径及头文件路径等信息的呢?

答案就在.pc文件中。库文件编译完成后,会在{installed_home/lib/}下生成产生一个名为pkgconfig的目录,内含该链接库的.pc文件,此文件记录了改库的相关信息。为了能被查找读取到,需要将该.pc文件安装到 /usr/lib/pkgconfig/ 目录中,或在PKG_CONFIG_PATH环境变量中加入该.pc文件的安装路径。这样做的目的是为了使依赖此库的其它程序能够借助pkg-config自动链接该库,避免编译期错误。

  • pkg-config常用参数:
–-list-all 列出所有已安装的共享库
-–cflags 列出指定共享库的预处理和编译flag。
-–libs 列出指定共享库的链接flag。


环境变量 PKG_CONFIG_PATH 用于指定pkg-config查找.pc文件的路径。此外,pkg-config还会查找/usr/lib/pkgconfig/下的.pc文件。

像这样设置环境变量:

export PKG_CONFIG_PATH=/usr/local/lib


 

有一个ros框架项目,现在有一个cpp文件使用了其他项目的头文件,该如何修改ros项目的cmakelists,使得该cpp文件可以正常编译 cmake_minimum_required(VERSION 3.4) project(ssp_gripper) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(catkin REQUIRED COMPONENTS roscpp message_generation control_msgs actionlib sensor_msgs xmlrpcpp actionlib_msgs serial ) find_package(Franka 0.9.0 QUIET) if(NOT Franka_FOUND) find_package(Franka 0.8.0 REQUIRED) endif() find_package(aubo_sdk REQUIRED PATHS /home/robot-nanjing/aubo_sdk-0.26.0-rc.1-Linux_x86_64+ce93216/lib/cmake/aubo_sdk NO_DEFAULT_PATH ) add_action_files( DIRECTORY action FILES Grasp.action Homing.action Stop.action Move.action ) add_message_files( DIRECTORY msg FILES GraspEpsilon.msg ) generate_messages(DEPENDENCIES actionlib_msgs) catkin_package( INCLUDE_DIRS include LIBRARIES ssp_gripper CATKIN_DEPENDS roscpp message_runtime control_msgs actionlib sensor_msgs xmlrpcpp actionlib_msgs serial DEPENDS Franka ) add_library(jodellTool2 SHARED IMPORTED) set_target_properties(jodellTool2 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib/libjodellTool2.so INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include/dh ) add_library(zgGripperV6 SHARED IMPORTED) set_target_properties(zgGripperV6 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib/libzgGripperV6.so INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include;${CMAKE_CURRENT_SOURCE_DIR}/include/zgv6" ) add_library(ssp_gripper src/ssp_gripper.cpp src/jodellgripper.cpp src/dh_device.cpp src/dh_gripper.cpp src/dh_modbus_gripper.cpp src/zg_gripper_v6.cpp src/dh_gripper_ag95.cpp src/dh_ag95/hand_controller.cpp src/dh_ag95/hand_driver.cpp src/dh_ag95/DH_datastream.cpp ) add_dependencies(ssp_gripper ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ${PROJECT_NAME}_generate_messages_cpp ) target_link_libraries(ssp_gripper ${Franka_LIBRARIES} ${catkin_LIBRARIES} jodellTool2 zgGripperV6 ) target_include_directories(ssp_gripper SYSTEM PUBLIC ${Franka_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS} ) target_include_directories(ssp_gripper PUBLIC include ) add_executable(ssp_gripper_node src/ssp_gripper_node.cpp ) add_dependencies(ssp_gripper_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ssp_gripper ) target_link_libraries(ssp_gripper_node ${catkin_LIBRARIES} ssp_gripper ) target_include_directories(ssp_gripper_node SYSTEM PUBLIC ${catkin_INCLUDE_DIRS} ) ## Installation install(TARGETS ssp_gripper ssp_gripper_node ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} ) install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(DIRECTORY config DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(FILES lib/libjodellTool2.so lib/libzgGripperV6.so DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}) ## Tools include(${CMAKE_CURRENT_LIST_DIR}/../cmake/ClangTools.cmake OPTIONAL RESULT_VARIABLE CLANG_TOOLS ) if(CLANG_TOOLS) file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h ) add_format_target(ssp_gripper FILES ${SOURCES} ${HEADERS}) add_tidy_target(ssp_gripper FILES ${SOURCES} DEPENDS ssp_gripper ssp_gripper_node ) endif() #set(CMAKE_INSTALL_RPATH "${CATKIN_PACKAGE_LIB_DESTINATION}") # 测试支持 if(CATKIN_ENABLE_TESTING) find_package(rostest REQUIRED) find_package(GTest REQUIRED) # 包含测试目录 add_subdirectory(ut) endif() ## XSJ add_executable(example_state src/example_state.cpp ) target_link_libraries(example_state ${catkin_LIBRARIES} aubo_sdk::aubo_sdk ) # 设置运行时 rpath,避免手动 export LD_LIBRARY_PATH set_target_properties(example_state PROPERTIES BUILD_RPATH "/home/robot-nanjing/aubo_sdk-0.26.0-rc.1-Linux_x86_64+ce93216/lib" INSTALL_RPATH "/home/robot-nanjing/aubo_sdk-0.26.0-rc.1-Linux_x86_64+ce93216/lib" ) install(TARGETS example_state RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) ## XSJ
09-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值