ROS初級教程 cmake cmakelist.txt 的編寫教程
有很多 的時候我們使用別人的程序包。然後添加東西的時候缺少什麽東西,會使程序編譯不過去,甚至無法運行,接下來介紹一下cmakelist.txt 的每一行的作用。為了以後添加和修改方便。
2.整體結構和訂購
您的CMakeLists.txt文件必須遵循此格式,否則您的包將無法正確構建。 配置中的順序計數。
所需CMake版本(cmake_minimum_required)
軟件包名稱(project())
查找構建所需的其他CMake / Catkin軟件包(find_package())
啟用Python模塊支持(catkin_python_setup())
消息/服務/動作生成器(add_message_files(),add_service_files(),add_action_files())
調用消息/服務/動作生成(generate_messages())
指定package build info export(catkin_package())
要建立的庫/可執行文件(add_library()/ add_executable()/ target_link_libraries())
測試建立(catkin_add_gtest())
安裝規則(install())
3.CMake版本
每個catkin CMakeLists.txt文件必須以需要的CMake版本開始。 Catkin需要2.8.3或更高版本。
cmake_minimum_required(VERSION 2.8.3)
4.軟件包名稱
下一個項目是由CMake項目功能指定的包的名稱。 讓我們說我們正在制作一個名為robot_brain的軟件包。
project(robot_brain)
請註意,在CMake中,您可以隨時在CMake腳本中隨時使用變量$ {PROJECT_NAME}來引用項目名稱。
5.查找相關的CMake包
我們需要使用CMake find_package函數指定需要找到哪些其他CMake包來構建我們的項目。 總是至少有一個依賴於catkin:
find_package(catkin REQUIRED)
如果您的項目依賴於其他濕式包裝,它們將自動變成catkin的組件(以CMake為單位)。 而不是在這些軟件包上使用find_package,如果您將它們指定為組件,它將使生活更輕松。 例如,如果您使用package nodelet。
find_package(catkin REQUIRED COMPONENTS nodelet)
註意:您應該只需要find_package組件來構建標誌。 您不應添加運行時依賴關系。
find_package(catkin REQUIRED) find_package(nodelet REQUIRED)
但是,你會看到這是一個不方便的事情。
5.1find_package()做什麽?
如果CMake通過find_package找到一個包,則會導致創建幾個提供有關找到的包的信息的CMake環境變量。 這些環境變量可以在CMake腳本中稍後使用。 環境變量描述了包導出的頭文件的位置,源文件的位置,包所依賴的庫以及這些庫的路徑。 名稱總是符合<PACKAGE NAME> _ <PROPERTY>的慣例:
<NAME> _FOUND - 如果找到庫,則設置為true,否則為false
<NAME> _INCLUDE_DIRS或<NAME> _INCLUDES - 包導出的包含路徑
<NAME> _LIBRARIES或<NAME> _LIBS - 由包導出的庫
<NAME> _DEFINITIONS - ?
5.2為什麽Catkin包被指定為組件?
Catkin包不是catkin的真正組成部分。相反,CMake的組件功能被用於catkin的設計,從而為您節省打字時間。
對於catkin包,如果find_package它們作為catkin的組件,這是有利的,因為使用catkin_前綴創建了一組環境變量。例如,讓我們說您在代碼中使用package nodelet。查找包的推薦方法是:
find_package(catkin REQUIRED COMPONENTS nodelet)
這意味著由nodelet導出的include路徑,庫等也附加到catkin_變量。例如,catkin_INCLUDE_DIRS不僅包含catkin的include路徑,還包含了nodelet,這將在以後派上用場。
我們可以自己選擇find_package nodelet:
find_package(nodelet)
這意味著nodelet路徑,庫等不會被添加到catkin_變量中。
這將導致nodelet_INCLUDE_DIRS,nodelet_LIBRARIES等。也使用相同的變量創建
find_package(catkin REQUIRED COMPONENTS nodelet)
5.3促進
如果使用C ++和Boost,您需要在Boost上調用find_package(),並指定用作組件的Boost的哪些方面。 例如,如果你想使用Boost線程,你會說:
find_package(Boost REQUIRED COMPONENTS thread)
6.0catkin_package()
catkin_package()是一個catkin提供的CMake宏。這是為構建系統指定catkin特定信息所必需的,後者又用於生成pkg-config和CMake文件。
在使用add_library()或add_executable()聲明任何目標之前,必須調用此函數。該函數有5個可選參數:
INCLUDE_DIRS - 包的導出包含路徑(即cflags)
圖書館 - 從項目導出的圖書館
CATKIN_DEPENDS - 該項目依賴的其他catkin項目
DEPENDS - 該項目所依賴的非catkin CMake項目。為了更好的理解,請看這個解釋。
CFG_EXTRAS - 其他配置選項
完整的宏文檔可以在這裏找到。
舉個例子:
catkin_package( INCLUDE_DIRS include LIBRARIES ${PROJECT_NAME} CATKIN_DEPENDS roscpp nodelet DEPENDS eigen opencv)
這表示包文件夾中的文件夾“include”是導出標題的地方。 CMake環境變量$ {PROJECT_NAME}評估到之前傳給project()函數的任何東西,在這種情況下它將是“robot_brain”。 “roscpp”+“nodelet”是需要存在來構建/運行此程序包的軟件包,“eigen”+“opencv”是需要存在的用於構建/運行此程序包的系統依賴項。
7.0指定構建目標
構建目標可以有多種形式,但通常它們代表兩種可能之一:
可執行目標 - 我們可以運行的程序
庫目標 - 可在構建和/或運行時由可執行目標使用的庫
7.1目標命名
非常重要的是註意,catkin中的構建目標的名稱必須是唯一的,而不管它們被構建/安裝到哪個文件夾。 這是CMake的要求。 但是,目標的唯一名稱只能在CMake內部進行。 可以使用set_target_properties()函數將目標重命名為其他目標:
例:
set_target_properties(rviz_image_view PROPERTIES OUTPUT_NAME image_view PREFIX "")
這將在構建和安裝輸出中將目標rviz_image_view的名稱更改為image_view。
7.2自定義輸出目錄
雖然可執行文件和庫的默認輸出目錄通常設置為合理的值,但在某些情況下必須進行自定義。即 一個包含Python綁定的庫必須放在不同的文件夾中才能在Python中導入:
例:
set_target_properties(python_module_library
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION})
7.3包括路徑和庫路徑
在指定目標之前,您需要指定可以為所述目標找到資源的位置,特別是頭文件和庫:
包括路徑 - 在哪裏可以找到代碼(最常見於C / C ++)的頭文件
庫路徑 - 哪些庫位於該可執行目標建立對象?
include_directories(<dir1>,<dir2>,...,<dirN>)
link_directories(<dir1>,<dir2>,...,<dirN>)
7.3.1include_directories()
include_directories的參數應該是find_package調用和需要包含的任何其他目錄生成的* _INCLUDE_DIRS變量。 如果您使用catkin和Boost,您的include_directories()調用應該如下所示:
include_directories(include ${Boost_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS})
第一個參數“include”表示包中的include /目錄也是路徑的一部分。
7.3.2link_directories()
CMake link_directories()函數可用於添加額外的庫路徑,但是不推薦這樣做。 所有catkin和CMake軟件包在find_packaged時都會自動添加鏈接信息。 只需鏈接到target_link_libraries()中的庫
例:
link_directories(~/my_libs)
請參閱這個cmake線程以查看關於在link_directories()上使用target_link_libraries()的詳細示例。
7.4可執行目標
要指定必須構建的可執行目標,我們必須使用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 / another_file.cpp。
7.5 圖書館目標
add_library()CMake函數用於指定要構建的庫。 默認情況下,catkin構建共享庫。
add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS})
7.6target_link_libraries
使用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()自動拉入。
8.0消息,服務和行動目標
消息(.msg),服務(.srv)和動作(.action)文件在ROS包構建和使用之前需要一個特殊的預處理器構建步驟。 這些宏的要點是生成編程語言特定的文件,以便可以利用其選擇的編程語言中的消息,服務和動作。 構建系統將使用所有可用的生成器(例如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()宏必須對message_runtime具有CATKIN_DEPENDS依賴關系。
catkin_package(
...
CATKIN_DEPENDS message_runtime ...
...)
您必須對包message_generation使用find_package(),單獨或作為catkin的組件:
find_package(catkin REQUIRED COMPONENTS message_generation)
您的package.xml文件必須包含對message_generation的構建依賴關系以及message_runtime上的運行時依賴關系。 如果依賴關系從其他軟件包中過渡拉出來,則不需要這樣做。
如果您有一個目標(即使是過渡性的)依賴於需要構建消息/服務/操作的其他一些目標,則需要向目標catkin_EXPORTED_TARGETS添加明確的依賴關系,以便它們以正確的順序構建。 這種情況幾乎總是適用,除非您的包真的不使用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”的名為“msg”的目錄中有兩條消息,這些消息依賴於std_msgs和sensor_msgs,名為“srv”的名為“MyService.srv”的目錄中的服務, 定義使用這些消息和服務的可執行的message_program,並且使用ROS的某些部分的可執行的do_not_use_local_messages_program,而不是此包中定義的消息/服務,那麽在CMakeLists.txt中需要以下內容:
# Get the information about this package‘s buildtime dependencies find_package(catkin REQUIRED COMPONENTS message_generation std_msgs sensor_msgs) # Declare the message files to be built add_message_files(FILES MyMessage1.msg MyMessage2.msg ) # Declare the service files to be built add_service_files(FILES MyService.srv ) # Actually generate the language-specific message and service files generate_messages(DEPENDENCIES std_msgs sensor_msgs) # Declare that this catkin package‘s runtime dependencies catkin_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 package add_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_msgs添加到使用catkin進行find_package的組件列表中,然後添加以下調用 對generate_messages(...)的調用:
add_action_files(FILES
MyAction.action
)
此外,該包必須具有對actionlib_msgs的構建依賴。
9.0啟用Python模塊支持
如果您的ROS包提供了一些Python模塊,您應該創建一個setup.py文件並調用
catkin_python_setup()
之前調用generate_messages()和catkin_package()。
10.0 單位測試
有一個catkin-specific宏用於處理名為catkin_add_gtest()的基於gtest的單元測試。
catkin_add_gtest(myUnitTest test / utest.cpp)
11.0可選步驟:指定可安裝的目標
構建時間之後,目標被放置在catkin工作區的開發空間中。但是,通常我們希望將目標安裝到系統中(有關安裝路徑的信息可以在REP 122中找到),以便其他人或本地文件夾可以使用它們來測試系統級安裝。換句話說,如果你想要做一個“make install”的代碼,你需要指定目標應該在哪裏。
這是使用CMake install()函數作為參數完成的:
目標 - 目標是安裝
ARCHIVE DESTINATION - 靜態庫和DLL(Windows).lib存根
LIBRARY DESTINATION - 非DLL共享庫和模塊
RUNTIME DESTINATION - 可執行目標和DLL(Windows)樣式共享庫
舉一個例子:
install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
除了這些標準目標,一些文件必須安裝到特殊文件夾。即一個包含Python綁定的庫必須安裝到不同的文件夾中才能在Python中導入:
install(TARGETS python_module_library
ARCHIVE 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/myscript DESTINATION ${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 )
或者如果包含的子文件夾與包名稱不匹配:
install(DIRECTORY include/ DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION} PATTERN ".svn" EXCLUDE )
11.3安裝roslaunch文件或其他資源
其他資源(如啟動文件)可以安裝到$ {CATKIN_PACKAGE_SHARE_DESTINATION
install(DIRECTORY launch/ DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch PATTERN ".svn" EXCLUDE)
ROS初級教程 cmake cmakelist.txt 的編寫教程