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