catkin_make生成信息的理解 & ROS中的cmakelist.txt
标签(空格分隔): ROS
src: 代码空间
build: 编译空间,存放编译时生成的中间文件,二进制文件
devel: 开发空间,存放终止编译的可执行文件和环境变量;
install: 安装空间,最终生成的可执行文件,与devel有点类似,但包行了安装指令,ROS编译结果最终安装的地方,类似Windows的Program Files
创建工作空间
ROS使用 python3 https://www.cnblogs.com/h46incon/p/6207145.html?utm_source=itdadao&utm_medium=referral
$ catkin_make
Base path: /home/alex/code_ROS/pkg_template_ws //基本路径
Source space: /home/alex/code_ROS/pkg_template_ws/src
Build space: /home/alex/code_ROS/pkg_template_ws/build
Devel space: /home/alex/code_ROS/pkg_template_ws/devel
Install space: /home/alex/code_ROS/pkg_template_ws/install
####
#### Running command: "make cmake_check_build_system" in "/home/alex/code_ROS/pkg_template_ws/build"
####
-- Using CATKIN_DEVEL_PREFIX: /home/alex/code_ROS/pkg_template_ws/devel
-- Using CMAKE_PREFIX_PATH: /opt/ros/melodic //cmake 前缀路径 这个路径就是ros的安装路径
-- This workspace overlays: /opt/ros/melodic //
-- Found PythonInterp: /usr/bin/python2 (found suitable version "2.7.15", minimum required is "2") //ROS支持所支持的python版本
-- Using PYTHON_EXECUTABLE: /usr/bin/python2 //Python2的bin文件
//python的解释器,回忆python文件的第一行,`#!/usr/bin/python`,即指定该文件用什么语言解释
//这里就解释了为什么ROS默认支持python2
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/alex/code_ROS/pkg_template_ws/build/test_results
-- Found gtest sources under '/usr/src/googletest': gtests will be built
-- Found gmock sources under '/usr/src/googletest': gmock will be built
-- Found PythonInterp: /usr/bin/python2 (found version "2.7.15")
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.19
-- BUILD_SHARED_LIBS is on
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~ traversing 1 packages in topological order:
-- ~~ - ros_pkg_template
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'ros_pkg_template'
-- ==> add_subdirectory(ros_package_template)//当前包视作总的catkin package下的一个sub 路径
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/code_ROS/pkg_template_ws/build
####
#### Running command: "make -j8 -l8" in "/home/alex/code_ROS/pkg_template_ws/build"
####
Scanning dependencies of target class_template
[ 50%] Building CXX object ros_package_template/CMakeFiles/class_template.dir/src/class_template.cpp.o
[100%] Linking CXX executable /home/alex/code_ROS/pkg_template_ws/devel/lib/ros_pkg_template/class_template
[100%] Built target class_template
Cmakelist 详解
cmake_minimum_required(VERSION 2.8.3)
project(ros_pkg_template)
## Find catkin macros and libraries
find_package(catkin REQUIRED COMPONENTS
roscpp
geometry_msgs
joy
)
include_directories(${catkin_INCLUDE_DIRS})
catkin_package(INCLUDE_DIRS CATKIN_DEPENDS
roscpp
geometry_msgs
joy
DEPENDS
)
###########
## Build ##
###########
add_executable(class_template src/class_template.cpp)
target_link_libraries(class_template ${catkin_LIBRARIES})
#############
## Install ##
#############
find_package(…)
参考资料:https://blog.csdn.net/u011092188/article/details/61425924
查找catkin宏和库
find_package(catkin REQUIRED COMPONENTS
roscpp
geometry_msgs
joy
)
为什么要使用find_package?
因为:如果编译软件使用了外部库,事先并不知道它的头文件和链接库的位置(路径)。得在编译命令中加上包含它们的查找路径。CMake使用find_package命令来解决这个问题。如果找到了,就可以在接下来的语句中使用
${XXX_INCLUDE_DIRS}
和${XXX_LIBRARIES}
这两个变量,将我们自己写的cpp文件链接这些库。(这种变量名应该是很常见了吧~)这让我想起了自己当初的一些骚操作,最开始没搞明白这些关系的时候,自己调用的库编译总通过不了,索性干脆#inclue头文件的时候使用绝对路径,链接.so库的时候直接把绝对路径写进去,也是傻得不行。。。
那么,计算机如何找到这些库和头文件的路径的呢?
首先需要知道的是,
${XXX_INCLUDE_DIRS}
和${XXX_LIBRARIES}
这两个变量是需要定义的,那么他们的定义是由谁完成的呢?答案就是.cmake
文件,在.cmake
文件里。一共有两个.cmake
文件对这两个变量进行了定义,分别是FindXXX.cmake
和XXXConfig.cmake
(为什么是两个,这个下面会讲到),所以只要找到了.cmake
文件,就能定义以上两个变量。
那么cmake文件去哪里找?
我们以一个开源库ceres为例,下载下来之后,里面紧接着必然有一个cmake文件夹,与之并列的还有cmakelist.txt。我们往常的正常操作是同目录下新建build文件夹,cd进去然后
cmake ..
,执行上一级的cmakelist.txt。然后我们发现,在cmake文件夹中,有一堆的FindXXX.cmake
,比如FindEigen.cmake,FindGlog.cmake等(这些都是ceres库在运行的时候用到的其他库。)这样编译的时候,自然直接就找到了.cmake
文件。
当然你可能会问,这是开源库,人家自己添加了cmake文件夹,里面有FindXXX.cmake之类的文件,我们使用的ROS的package可没有单独的添加cmake文件夹,直接就在cmakelist.txt中find_package(catkin)了。编译的时候直接就catkin_make
就完事了,也没主动提供Findcatkin.cmake
文件啊!
这就涉及到find_package()的查找*.cmake的顺序问题:
说到查找*.cmake的顺序问题就不得不提到cmake的两种模式:
- Module模式:搜索CMAKE_MODULE_PATH指定路径下的FindXXX.cmake文件,执行该文件从而找到XXX库。其中,具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由FindXXX.cmake模块完成。
- Config模式:搜索XXX_DIR指定路径下的XXXConfig.cmake文件,执行该文件从而找到XXX库。其中具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成。
- 不特殊指定的话find_package()执行的是Module模式
1、 find_package()命令首先会在模块路径中寻找FindXXX.cmake,这是查找库的一个典型方式。具体查找路径依次为变量
${CMAKE_MODULE_PATH}
中的所有目录。如果没有,然后再查看它自己的模块目录/share/cmake-x.y/Modules/
(${CMAKE_ROOT}
的具体值可以通过CMake中message命令输出)。这里先运行的是模块模式。
2、 如果没找到这样的文件,find_package()会在~/.cmake/packages/或/usr/local/share/中的各个包目录中查找,寻找<库名字的大写>Config.cmake 或者 <库名字的小写>-config.cmake (比如库Opencv,它会查找/usr/local/share/OpenCV中的OpenCVConfig.cmake或opencv-config.cmake)。这里执行配置模式。
总结:所以,定义
${XXX_INCLUDE_DIRS}
和${XXX_LIBRARIES}
两个变量的,不止可以是FindXXX.cmake
,也可以是XXXConfig.cmake。
也就是说,Findcatkin.cmake
这个文件,系统会根据两种模式自动去一些路径里面找它。但是我们搜索发现,电脑里面并没有Findcatkin.cmake
这个文件,那么${catkin_LIBRARIES}
和${catkin_INCLUDE_DIRS}
两个变量又是如何定义的呢?
说到这里,就不得不提到我们刚学ROS时候那句经典的命令了$ source /opt/ros/Kinect/setup.bash
,这句命令帮我们定义了一些ROS相关的环境变量。包括在我们自己的操作空间下执行source devel/setup.zsh
等操作。这些环境变量,就能够帮助cmake找到ROS相关的package路径:
那么环境变量有哪些?我们可以运行$ env env
,列出当前系统的所有环境变量,找到和ROS相关的环境变量如下:
ROS_DISTRO=melodic
ROS_ETC_DIR=/opt/ros/melodic/etc/ros
ROS_PACKAGE_PATH=/opt/ros/melodic/share
ROS_PYTHON_VERSION=2
ROS_VERSION=1
ROS_ROOT=/opt/ros/melodic/share/ros
ROS_MASTER_URI=http://localhost:11311
找到我们关心的ROS_PACKAGE_PATH
,点进去看一下,我们可以看到ROS自带的各种各样的库的名字(roslaunch,rosbag等等)
随便找一个进去看一下(rosbag):
# alex @ alex in /opt/ros/melodic/share/rosbag [10:13:09]
$ ls
cmake package.xml
看,果然有一个cmake文件夹,点进去瞅一眼:
# alex @ alex in /opt/ros/melodic/share/rosbag/cmake [10:13:57]
$ ls
rosbagConfig.cmake rosbagConfig-version.cmake
到此,我们已经能够解释所有的ROS的catkin相关的包在编译的时候如何找到的问题。
回到最开始的一个问题,${catkin_LIBRARIES}
和${catkin_INCLUDE_DIRS}
两个变量的值都是什么?我们可以在cmakelist.txt中使用message(“INFO: catkin_LIBRARIES value is ${catkin_LIBRARIES}”)将两个变量的值都打出来看一下:
${catkin_LIBRARIES}
#value is /opt/ros/melodic/lib/libroscpp.so;/usr/lib/x86_64-linux-gnu/libboost_filesystem.so;/usr/lib/x86_64-linux-gnu/libboost_signals.so;/opt/ros/melodic/lib/librosconsole.so;/opt/ros/melodic/lib/librosconsole_log4cxx.so;/opt/ros/melodic/lib/librosconsole_backend_interface.so;/usr/lib/x86_64-linux-gnu/liblog4cxx.so;/usr/lib/x86_64-linux-gnu/libboost_regex.so;/opt/ros/melodic/lib/libxmlrpcpp.so;/opt/ros/melodic/lib/libroscpp_serialization.so;/opt/ros/melodic/lib/librostime.so;/opt/ros/melodic/lib/libcpp_common.so;/usr/lib/x86_64-linux-gnu/libboost_system.so;/usr/lib/x86_64-linux-gnu/libboost_thread.so;/usr/lib/x86_64-linux-gnu/libboost_chrono.so;/usr/lib/x86_64-linux-gnu/libboost_date_time.so;/usr/lib/x86_64-linux-gnu/libboost_atomic.so;/usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/libconsole_bridge.so.0.4
${catkin_INCLUDE_DIRS}
:#WARNING: catkin_INCLUDE_DIRS /opt/ros/melodic/include;/opt/ros/melodic/share/xmlrpcpp/cmake/…/…/…/include/xmlrpcpp;/usr/include
以rosbag为例,分别是库地址:/opt/ros/melodic/lib/
$ locate librosbag.so
/opt/ros/melodic/lib/librosbag.so
include的头文件地址:/opt/ros/melodic/include/
$ ls rosbag
bag.h constants.h message_instance.h stream.h
bag_player.h encryptor.h player.h structures.h
buffer.h exceptions.h query.h time_translator.h
chunked_file.h macros.h recorder.h view.h
实际上在使用Clion的时候,就会提示Could not find module Findcatkin.cmake or a configuration file for package catkin
。查看我们配置的clion的启动项
Exec="/home/alex/Software/CLion-2019.2.5/clion-2019.2.5/bin/clion.sh" %f
Exec= zsh -i -c “/home/alex/Software/CLion-2019.2.5/clion-2019.2.5/bin/clion.sh” %f
加载环境变量source /opt/ros/melodic/setup.zsh
具体内容如下:
#!/usr/bin/env zsh
# generated from catkin/cmake/templates/setup.zsh.in
CATKIN_SHELL=zsh
# source setup.sh from same directory as this file
_CATKIN_SETUP_DIR=$(builtin cd -q "`dirname "$0"`" > /dev/null && pwd)
emulate -R zsh -c 'source "$_CATKIN_SETUP_DIR/setup.sh"'
参考:https://blog.csdn.net/robinhjwy/article/details/79597095
这里又涉及到了rospack profile
备注:XXX_DIR变量需要在执行Find_package之前定义,比如set(Caffe_DIR /home/xxx/caffe/build)
,这个路径下包含的就是所需要的.cmake
文件
引用自定义的caffe路径:
set(Caffe_DIR /home/caffe/build) #添加CaffeConfig.cmake的搜索路径
find_package(Caffe REQUIRED)
if (NOT Caffe_FOUND)
message(FATAL_ERROR "Caffe Not Found!")
endif (NOT Caffe_FOUND)
include_directories(${Caffe_INCLUDE_DIRS})
add_executable(useSSD ssd_detect.cpp)
target_link_libraries(useSSD ${Caffe_LIBRARIES})
其实不管使用哪一种模式,只要找到*.cmake,*.cmake里面都会定义下面这些变量:
<NAME>_FOUND
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES
<NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS
<NAME>_DEFINITIONS