在ROS的程式設計過程中,如果CMakeLists.txt如果寫不好,編譯就很難成功。如果看不懂CMakeLists.txt那麼很多錯誤你也不知道時什麼回事。是以深入了解它是很有必要的。
我們使用cmake進行程式編譯的時候,會根據CMakeLists.txt這個檔案進行一步一步的處理,然後形成一個MakeFile檔案,系統再通過這個檔案的設定進行程式的編譯。
ROS中的CMakeLists.txt主要包括以下内容
(1)Required CMake Version (cmake_minimum_required)
(2)PackageName (project())
(3)Find other CMake/Catkin packages needed for build(find_package())
(4)Message/Service/Action Generators
(add_message_files(),add_service_files(),add_action_files())
(5)Invoke message/service/action generation (generate_messages())
(6)Specify package build info export(catkin_package())
(7)Libraries/Executables to build(add_library()/add_executable()/target_link_libraries())
(8)Tests to build (catkin_add_gtest())
(9)Install rules (install())
1.cmake_minimum_required
CMakeLists.txt都要以此開始,catkin編譯需要2.8.3版本以上的cmake。
2.project()
通過project()這個函數指定包的名字,在CMake中指定後,你可在其他地方通過使用變量${PROJECT_NAME}來引用它
3.find_package()
這裡指明建構這個package需要依賴的package,我們使用catkin_make的編譯方式,至少需要catkin這個包。
find_package(catkin REQUIRED)
一個包被find_package,那麼就會導緻一些CMake變量的産生,這些變量後面将在CMake的腳本中用到,這些變量描述了所依賴的包輸出的頭檔案、源檔案、庫檔案在哪裡。這些變量的名字依照的慣例是 < PACKAGENAME>_< PROPERTY>,比如:
< NAME>_FOUND:這個變量說明這個庫是否被找到,如果找到就被設定為true,否則設為false;
< NAME>_INCLUDE_DIRS or < NAME>_INCLUDES:這個包輸出的頭檔案目錄;
< NAME>_LIBRARIES or < NAME>_LIBS:這個包輸出的庫檔案。
需要的所有包我們都可用這種方式包含進來,比如我們需要roscpp,rospy,std_msgs。我們可以寫成:
find_package(roscpp REQUIRED)
find_package(rospy REQUIRED)
find_package(std_msgs REQUIRED)
這樣的話,每個依賴的package都會産生幾個變量,這樣很不友善。是以還有另外一種方式:
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
這樣,它會把所有pacakge裡面的頭檔案和庫檔案等等目錄加到一組變量上,比如:catkin_INCLUDE_DIRS,這樣,我們就可以用這個變量查找需要的檔案了。最終就隻産生一組變量了。
4.Declare messages,Services and Actions
當我們需要使用.msg/.srv/.action形式的檔案時,我們需要特殊的預處理器把他們轉化為系統可以識别特定程式設計語言(.h/.cpp)。系統會用裡面所有的(一些程式設計語言)生成器(比如gencpp,genpy,genlisp,etc)生成相應的.cpp.py檔案。這就需要三個宏:add_message_files,add_service_files,add_action_files來相應的控制.msg.srv.action。這些宏後面必須跟着一個調用generate_messages()。他們的運用要注意一下幾點:
1)這些宏必須在catkin_package()宏前面,即:
find_package(catkinREQUIREDCOMPONENTS…)
add_message_files(…)
add_service_files(…)
add_action_files(…)
generate_messages(…)
catkin_package(…)
…
2)宏catkin_package()中必須有CATKIN_DEPENDS依賴于message_runtime,即:
catkin_package(
…
CATKIN_DEPENDS message_runtime…
…)
3)find_package()中必須有message_generation
find_package(catkinREQUIRED COMPONENTS message_generation)
4)package.xml檔案中
build_depend必須包含message_generation,
run_depend必須包含message_runtime。
5)如果你有一個包編譯.msg.srv,并且可執行檔案要使用他們,那麼你就需要建立一個顯式的依賴項,自動生成message的target。這樣才能按順序來進行編譯:
add_dependencies(some_target${PROJECT_NAME}_generate_messages_cpp)
這裡的some_target是add_executable()設定的target的名字。
5.catkin_package()
這是一個catkin提供的cmake宏,當我們要給建構系統指定catkin的特定的資訊時就需要了,或者反過來利用他産生pkg-config和CMake檔案。這個函數必須在聲明add_library()或者add_executable()生成target之前使用。
catkin_package()是catkin提供的CMake宏,對生成的pkg和CMake檔案進行配置,如果去掉編譯也能通過,但是配置會發生變化,比如生成的可執行檔案會在工作空間中的build檔案夾中而不是devel/lib檔案夾中,這樣可能導緻的一個後果是無法使用rosrun指令來運作可執行檔案。
6.指定編譯的target
編譯産生的target有多種形式,通常有兩種:程式可以運作的可執行檔案以及在可執行檔案編譯和運作時要用到的庫。
(1)target的命名:
target的命名很重要,在catkin中target的名字必須是唯一的,和你之前建構産生的和安裝的都不能相同。這隻是cmake内部的需要。可以利用set_target_properties()函數将這個target進行重命名。例如:
set_target_properties(rviz_image_view
PROPERTIESOUTPUT_NAMEimage_view
PREFIX”“)
這樣就可将那個target rviz_image_view改為image_view。
(2)設定輸出路徑:
ROS中的輸出路徑時預設的,但是也可通過下面進行修改:
set_target_properties(python_module_library
PROPERTIESLIBRARY_OUTPUT_DIRECTORY CATKINDEVELPREFIX/ C A T K I N D E V E L P R E F I X / {CATKIN_PACKAGE_PYTHON_DESTINATION})
(3)頭檔案路徑和庫檔案路徑:
在我們指定target之前,我們需要指明對target而言,在哪裡找源檔案,特别是在哪裡找頭檔案,在哪裡找庫檔案。
IncludePaths:指明編譯代碼時在哪裡尋找頭檔案;
LibraryPaths:指明可執行檔案需要的庫檔案在哪裡。
函數:
include_directories:他的參數是通過find_package産生的*_INCLUDE_DIRS變量和其他所有額外的頭檔案路徑。例如:
include_directories(include BoostINCLUDEDIRS B o o s t I N C L U D E D I R S {catkin_INCLUDE_DIRS})
這裡”include”表示你的pacakge裡面的include這個路徑也包含在裡面。
link_directories():這個函數用來添加額外的庫的路徑,然而,這并不鼓勵使用,因為所有的catkin和cmake的package在使用find_package時就已經自動的有他們的連結資訊。簡單的連接配接可以通過target_link_libraries()來進行。
(4)可執行target:
例如:
add_executable(myProgram src/main.cpp src/some_file.cpp src/another_file.cpp)
(5)庫target:
add_library()用來指定編譯産生的庫。預設的catkin編譯産生共享庫:
add_library( PROJECTNAME P R O J E C T N A M E {${PROJECT_NAME}_SRCS})
(6)連結庫:
使用target_link_libraries函數來指定可執行檔案連結的庫。這個要用在add_executable()後面。形如:
target_link_libraries(,,,…)
比如,将可執行檔案foo連結到庫檔案libmoo.so。
add_executable(foo src/foo.cpp)
add_library(moo src/moo.cpp)
target_link_libraries(foo moo)
轉載自:
https://blog.csdn.net/buzaishihaizi/article/details/78524929