ROS知识: vanilla(香草) CMakeLists.txt 的语法
(catkin/CMakeLists.txt - ROS Wiki)
前言
首先,對于學習ROS,CMakeLists.txt 的語法非常重要;如果不懂將無法開發!而要想明白?vanilla(香草) CMakeLists.txt 的語法,首先需要掌握常規Cmake語法。
第一章 概述
我們知道,Cmake是關于編譯的事情;然而對于不同的Cmake各有其方言,需要獨立查閱理解;本篇專門針對ROS版本的Cmake語法進行敘述;在讀本文之前,期望讀者已經理解如下幾個文章:C語言編譯:CMakeLists.txt語句? 等。 ??
本片針對文件CMakeLists.txt文件,講述以下四個方面。
- CMakeList.txt的固定格式,
- 以及這些固定格式的內涵。
- 以及如何去修改添加自己的CMakeList.txt文件。
- 最后通過實例講解細節。
第二章 CMakeList.txt約定順序和結構
文件CMakeLists.txt是用于構建軟件包的CMake構建系統的輸入。任何符合CMake的軟件包都包含一個或多個CMakeLists.txt文件,該文件描述如何構建代碼以及將代碼安裝到何處?用于catkin項目的CMakeLists.txt文件是標準的香草CMakeLists.txt文件,帶有一些獨特的約束。
注意:您的CMakeLists.txt文件必須遵循下面格式,否則您的包將無法正確生成。配置中的順序如下。
-
Required CMake Version (cmake_minimum_required)
????????????????????? 指定編譯器版本
-
Package Name (project())
????????????????????? 指定項目名稱
-
Find other CMake/Catkin packages needed for build (find_package())
????????????????????? 查找其他依賴包
-
Enable Python module support (catkin_python_setup())
????????????????????? 包含python支持
-
Message/Service/Action Genera2.3tors
?????? ? ? ? ? ? ? ? ? 加入用戶定義的消息格式文件
(add_message_files(),?add_service_files(),?add_action_files())
-
Invoke message/service/action generation (generate_messages())
???????????????????? 喚醒消息等。
-
Specify package build info export (catkin_package())
??????????????????? 應用包信息導出。
-
Libraries/Executables to build (add_library()/add_executable()/target_link_libraries())
??????????????????? 指定庫路徑
-
Tests to build (catkin_add_gtest())
????????????????????? 指定測試路徑
-
Install rules (install())
??????????????????? 安裝規則
以上就是標準的CMakeList.txt文件格式。
第三章? CMake版本指定
?每個catkin CMakeLists.txt文件必須以所需的CMake版本開始。Catkin需要2.8.3或更高版本。
cmake_minimum_required(VERSION 2.8.3)
第四章 指定包名稱
下一項是由CMake項目功能指定的包的名稱。假設我們正在制作一個名為robot_brain的軟件包。
注意:在CMake中,您可以在以后CMake腳本中的任何位置引用項目名稱,只要需要,就可以使用變量${project_name}。此語句還有隱含的效果,那就是將生成如下的變量:
robot_brain_BINARY_DIR 和 robot_brain_SOURCE_DIR,同時,cmake 自動定義了兩個等價的名稱變量 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。
第五章? 查找依賴的CMake包
然后,我們需要指定需要找到哪些其他CMake包來使用CMake find_package函數構建我們的項目。catkin始終至少有一個依賴項:
以上:catkin是被搜索的項,REQUIRED表示前面的catkin的必須項目;
如果您的項目依賴于其他外來包,則它們會自動轉換為katkin(柳絮)的組件(就CMake而言)。如果您將這些包指定為組件,而不是在這些包上使用find_包,這將使工作更輕松。例如,如果使用包nodelet。
find_package(catkin REQUIRED COMPONENTS nodelet)注意:不應添加運行時依賴項在這里,應該是編譯時的依賴項。
你也可以這樣做:(然而,你會發現這不太方便)
5.1 find_package()的作用是什么?
如果CMake通過find_package找到一個包,它將導致創建幾個CMake環境變量,這些變量提供有關找到的包的信息。這些環境變量可以稍后在CMake腳本中使用。環境變量描述導出的頭文件所在的包、源文件所在的位置、包所依賴的庫以及這些庫的路徑。名稱始終遵循<PACKAGE NAME>的約定。
-
<NAME>_FOUND - Set to true if the library is found, otherwise false
-
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES - The include paths exported by the package
-
<NAME>_LIBRARIES or <NAME>_LIBS - The libraries exported by the package
-
<NAME>_DEFINITIONS - ?
5.2 為什么將Catkin-parkage指定為組件?
Catkin packages不是Catkin的真正組成部分。更確切地說,CMake的組件特性被用于Catkin的設計中,以節省大量的打字時間。
對于catkin包,如果您發現將它們打包為catkin的組件,這是有利的,因為使用catkin前綴創建了一組環境變量。例如,假設您在代碼中使用了包nodelet。查找包的建議方法是:
find_package(catkin REQUIRED COMPONENTS nodelet)這意味著nodelet導出的include路徑、庫等也會附加到catkin變量。例如,catkin_INCLUDE_DIRS不僅包含catkin的包含路徑,還包含nodelet的包含路徑!這將在以后派上用場。
相反地說:我們也可以自己找? find_package找到nodelet:
find_package(nodelet)
這意味著節點路徑、庫等不會添加到catkin變量中。這將導致nodelet_INCLUDE_DIRS、nodelet_LIBRARIES。
為了將少管理一些變量,用:
find_package(catkin REQUIRED COMPONENTS nodelet)
將那些變量集中收集到catkin_INCLUDE_DIRS和catkin_LIBRARIES內部。
5.3 調用Boost
如果使用C++和Boost,則需要調用Booost上的FundPulkAuthor(),并指定您使用的Boost的哪些方面作為組件。例如,如果您想使用Boost線程,您這樣寫:
find_package(Boost REQUIRED COMPONENTS thread)第六章 catkin_package()
是catkin提供的CMake宏。這是為構建系統指定特定于柳絮的信息所必需的,而構建系統又用于生成pkg config和CMake文件。
在使用add_library()或add_executable()聲明任何目標之前,必須調用此函數。該函數有5個可選參數:
- INCLUDE_DIRS-導出的包的INCLUDE路徑(即cflags)
- LIBRARIES-從項目中導出的庫
- CATKIN_DEPENDS-此項目依賴的其他CATKIN項目
- DEPENDS-此項目所依賴的非catkin CMake項目。要更好地理解,請參閱此說明。
- CFG_EXTRAS-其他配置選項
可以找到完整的宏文檔。
catkin_package(INCLUDE_DIRS includeLIBRARIES ${PROJECT_NAME}CATKIN_DEPENDS roscpp nodeletDEPENDS eigen opencv)這表示包文件夾中的文件夾“include”是導出的標題所在的位置。CMake環境變量${PROJECT_NAME}的計算結果與前面傳遞給PROJECT()函數的值相同,在本例中,它將是“robot_brain”。“roscpp”+“nodelet”是構建/運行此軟件包所需的軟件包,“eigen”+“opencv”是構建/運行此軟件包所需的系統依賴項。
第七章? 指定構建目標
構建目標可以有多種形式,但通常它們代表兩種可能性之一:
- 可執行目標-我們可以運行的程序
- 庫目標—可由可執行目標在生成和/或運行時使用的庫
7.1 目標命名
請務必注意,catkin中構建目標的名稱必須是唯一的,無論它們構建/安裝到哪個文件夾。這是CMake的一個要求。但是,唯一的目標名稱僅在CMake內部需要。可以使用set_target_properties()函數將目標重命名為其他對象:
set_target_properties(rviz_image_viewPROPERTIES OUTPUT_NAME image_viewPREFIX "")這將在生成和安裝輸出中將目標rviz_image_視圖的名稱更改為image_視圖。
7.2 自定義輸出目錄
雖然可執行文件和庫的默認輸出目錄通常設置為合理的值,但在某些情況下必須對其進行自定義。即,包含Python綁定的庫必須放在不同的文件夾中,才能在Python中導入:
例子:
set_target_properties(python_module_libraryPROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION})7.3 包括路徑和庫路徑
在指定目標之前,您需要指定在何處可以找到所述目標的資源,特別是頭文件和庫:
例子:
- Include Paths - Where can header files be found for the code (most common in C/C++) being built
- Library Paths - Where are libraries located that executable target build against?
-
include_directories(<dir1>,?<dir2>,?...,?<dirN>)
-
link_directories(<dir1>,?<dir2>,?...,?<dirN>)
7.4 包含目錄()
include_目錄的參數應該是find_包調用生成的*_include_DIRS變量以及需要包含的任何其他目錄。如果您使用的是catkin和Boost,那么include_directories()調用應該如下所示:
例子:
include_directories(include ${Boost_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS})第一個參數“include”表示包中的include/目錄也是路徑的一部分。
link_directories(~/my_libs)請參閱此cmake線程以查看在鏈接目錄link_directories().上使用目標鏈接庫target_link_libraries()的詳細示例。
7.5 可執行目標
要指定必須構建的可執行目標,必須使用add_executable()CMake函數。
add_executable(myProgram src/main.cpp src/some_file.cpp src/another_file.cpp)這將構建一個名為myProgram的目標可執行文件,該文件由3個源文件構建:src/main.cpp、src/some_file.cpp和src/other_file.cpp。
7.6 庫目標
add_library()CMake函數用于指定要生成的庫。默認情況下,catkin構建共享庫。
add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS})7.7 目標鏈接庫
使用target_link_libraries()函數指定可執行目標鏈接所針對的庫。這通常在add_executable()調用之后完成。如果未找到ros,則添加${catkin_LIBRARIES}。
語法:
target_link_libraries(<executableTargetName>, <lib1>, <lib2>, ... <libN>) add_executable(foo src/foo.cpp) add_library(moo src/moo.cpp) target_link_libraries(foo moo) -- This links foo against libmoo.so注意,在大多數用例中不需要使用link_directories(),因為這些信息是通過find_package()自動拉入的。
第八章 消息、服務和操作目標
ROS包生成和使用ROS中的消息(.msg)、服務(.srv)和操作(.action)文件之前,需要特殊的預處理器生成步驟。這些宏的要點是生成特定于編程語言的文件,以便可以使用所選編程語言中的消息、服務和操作。構建系統將使用所有可用的生成器(例如gencpp、genpy、genlisp等)生成綁定。
提供了三個宏分別處理消息、服務和操作:
-
add_message_files
-
add_service_files
-
add_action_files
然后,必須在這些宏之后調用調用生成的宏:
generate_messages()8.1 重要的先決條件/限制
?這些宏必須位于catkin_package()宏之前,才能正確生成。
find_package(catkin REQUIRED COMPONENTS ...)add_message_files(...)add_service_files(...)add_action_files(...)generate_messages(...)catkin_package(...)...您的catkin_package()宏必須具有CATKIN_DEPENDS依賴于消息_運行時的依賴項。?
catkin_package( find_package(catkin REQUIRED COMPONENTS message_generation) ...CATKIN_DEPENDS message_runtime ......)?必須單獨使用find_package()生成包消息,或將其作為catkin的一個組件:
find_package(catkin REQUIRED COMPONENTS message_generation)您的package.xml文件必須包含對消息\u生成的生成依賴項和對消息\u運行時的運行時依賴項。如果依賴項是通過傳遞方式從其他包中拉入的,則不需要這樣做。
如果您有一個目標(甚至是可傳遞的)依賴于需要構建消息/服務/操作的其他目標,則需要添加對目標catkin\u導出的\u目標的顯式依賴,以便它們以正確的順序構建。這種情況幾乎總是適用的,除非你的軟件包真的沒有使用ROS的任何部分。不幸的是,此依賴項無法自動傳播。(some_target是由add_executable()設置的目標的名稱):
add_dependencies(some_target ${catkin_EXPORTED_TARGETS})如果您有一個構建消息和/或服務的包以及使用這些消息和/或服務的可執行文件,則需要在自動生成的消息目標上創建一個顯式依賴項,以便以正確的順序構建它們。(some_target是由add_executable()設置的目標的名稱):
add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS})如果您的包同時滿足上述兩個條件,則需要添加兩個依賴項,即:
add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})8.2 實例
如果您的包在名為“MyMessage1.msg”和“MyMessage2.msg”的目錄中有兩條消息,并且這些消息依賴于std_msgs和sensor_msgs,則名為“MyService.srv”的目錄中名為“srv”的服務定義了使用這些消息和服務的可執行消息程序,而可執行文件不使用本地消息程序,它使用ROS的某些部分,但不使用此包中定義的消息/服務,那么您需要在CMakeLists.txt中提供以下內容:
# Get the information about this package's buildtime dependenciesfind_package(catkin REQUIREDCOMPONENTS message_generation std_msgs sensor_msgs)# Declare the message files to be builtadd_message_files(FILESMyMessage1.msgMyMessage2.msg)# Declare the service files to be builtadd_service_files(FILESMyService.srv)# Actually generate the language-specific message and service filesgenerate_messages(DEPENDENCIES std_msgs sensor_msgs)# Declare that this catkin package's runtime dependenciescatkin_package(CATKIN_DEPENDS message_runtime std_msgs sensor_msgs)# define executable using MyMessage1 etc.add_executable(message_program src/main.cpp)add_dependencies(message_program ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})# define executable not using any messages/services provided by this packageadd_executable(does_not_use_local_messages_program src/main.cpp)add_dependencies(does_not_use_local_messages_program ${catkin_EXPORTED_TARGETS})此外,如果您希望構建actionlib操作,并且在“action”目錄中有一個名為“MyAction.action”的操作規范文件,則必須將actionlib\u MSG添加到使用catkin打包的組件列表中,并在調用之前添加以下調用以生成\u消息(…):
add_action_files(FILESMyAction.action )此外,包必須對actionlib_msgs具有構建依賴關系。
第九章 啟用Python模塊支持
如果您的ROS包提供了一些Python模塊,那么應該創建setup.py文件并調用
catkin_python_setup()在調用generate_messages()和catkin_package()之前。
第十章 單元測試
有一個特定于catkin的宏,用于處理基于gtest的單元測試,稱為catkin_add_gtest()。
if(CATKIN_ENABLE_TESTING)catkin_add_gtest(myUnitTest test/utest.cpp) endif()第十一章 可選步驟:指定可安裝目標
構建后,將目標放置到catkin工作區的開發空間中。但是,我們通常希望將目標安裝到系統(有關安裝路徑的信息可在REP 122中找到),以便其他人或本地文件夾可以使用它們來測試系統級安裝。換句話說,如果您希望能夠對代碼進行“makeinstall”,則需要指定目標的最終位置。
這是使用CMake install()函數完成的,該函數將以下參數作為參數:
-
TARGETS - which targets to install
-
ARCHIVE?DESTINATION - Static libraries and DLL (Windows) .lib stubs
-
LIBRARY?DESTINATION - Non-DLL shared libraries and modules
-
RUNTIME?DESTINATION - Executable targets and DLL (Windows) style shared libraries
以共享庫為例:
install(TARGETS ${PROJECT_NAME}ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} )以下是可執行文件的另一個示例:
install(TARGETS ${PROJECT_NAME}_nodeRUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )除了這些標準目標之外,還必須將一些文件安裝到特殊文件夾中。即,包含Python綁定的庫必須安裝到不同的文件夾中,才能在Python中導入:
install(TARGETS python_module_libraryARCHIVE DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION}LIBRARY DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION} )11.1 安裝Python可執行腳本
對于Python代碼,安裝規則看起來不同,因為沒有使用add_library()和add_executable()函數,以便CMake確定哪些文件是目標以及它們是什么類型的目標。相反,請在CMakeLists.txt文件中使用以下命令:
catkin_install_python(PROGRAMS scripts/myscriptDESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})有關安裝python腳本和模塊的詳細信息,以及文件夾布局的最佳實踐,可以在catkin手冊中找到。
如果只安裝Python腳本而不提供任何模塊,則不需要創建上述setup.py文件,也不需要調用catkin_Python_setup()。
11.2 安裝頭文件
頭文件還必須安裝到“include”文件夾中,這通常是通過安裝整個文件夾的文件來完成的(可以選擇按文件名模式過濾,不包括SVN子文件夾)。可以使用如下所示的安裝規則完成此操作:
install(DIRECTORY include/${PROJECT_NAME}/DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}PATTERN ".svn" EXCLUDE ) 或者,如果include下的子文件夾與包名稱不匹配:install(DIRECTORY include/DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION}PATTERN ".svn" EXCLUDE )11.3 安裝roslaunch文件或其他資源
其他資源(如launchfiles)可以安裝到${CATKIN\u PACKAGE\u SHARE\u DESTINATION}:
install(DIRECTORY launch/DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launchPATTERN ".svn" EXCLUDE)find_package(Boost REQUIRED COMPONENTS system)
?
include_directories(
? include
? ${catkin_INCLUDE_DIRS}
? ${Boost_INCLUDE_DIRS}
)
?
target_link_libraries(demo ${catkin_LIBRARIES} ${Boost_LIBRARIES})
?
關于CMake文檔:
[CMake] adding a link directory
總結
以上是生活随笔為你收集整理的ROS知识: vanilla(香草) CMakeLists.txt 的语法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ROS知识:关于如何命名的约定
- 下一篇: 安装ubuntu20.4+gtx1050