1. 程式人生 > >ROS初級教程 cmake cmakelist.txt 的編寫教程

ROS初級教程 cmake cmakelist.txt 的編寫教程

函數 geo ets other cas 描述 targe util rom

有很多 的時候我們使用別人的程序包。然後添加東西的時候缺少什麽東西,會使程序編譯不過去,甚至無法運行,接下來介紹一下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 packages 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 packages 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 的編寫教程