ROS中的CMakeLists.txt

    ROS的編程過程中,如果CMakeLists.txt如果寫不好,編譯就很難成功。如果看不懂CMakeLists.txt那麼很多錯誤你也不知道時什麼回事。所以深入瞭解它是很右必要的。現在我們就來看看它。

    我們使用cmake進行程序編譯的時候,會根據CMakeLists.txt這個文件進行一步一步的處理,然後形成一個MakeFile文件,系統再通過這個文件的設置進行程序的編譯。

    我們可以先尋找一些cmake方面的東西進行一定的瞭解。ROS中的CMakeLists.txt也是基於普通的cmake的。ROS中的CMakeLists.txt主要包括下面幾個部分:

  1. Required CMake Version(cmake_minimum_required)

  2. Package Name(project())

  3. Find other CMake/Catkinpackages needed for build (find_package())

  4. Message/Service/ActionGenerators(add_message_files(), add_service_files(), add_action_files())

  5. Invokemessage/service/action generation(generate_messages())

  6. Specify package buildinfo export (catkin_package())

  7. Libraries/Executablesto build(add_library()/add_executable()/target_link_libraries())

  8. Tests to build(catkin_add_gtest())

  9. Install rules(install())

下面就進行一一的解釋。

1,

 cmake_minimum_required(VERSION 2.8.3)

      catkinCMakeLists.txt都要以此開始,catkin編譯需要2.8.3版本以上的cmake

2,

project(beginner_tutorials)

      通過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:這個包輸出的庫文件。

需要的所有包我們都可用這種方式包含進來,比如我們還需要roscpprospystd_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 ROS 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(catkin REQUIRED COMPONENTS ...)
 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(catkin REQUIRED 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之前使用。


6,指定編譯的target

      編譯產生的target有多種形式,通常有兩種:程序可以運行的可執行文件以及在可執行文件編譯和運行時要用到的庫。

1)target的命名:

target的命名很重要,在catkin中target的名字必須是唯一的,和你之前構建產生的和安裝的都不能相同。這只是cmake內部的需要。可以利用set_target_properties()函數將以個target進行重命名。例如:

set_target_properties(rviz_image_view
                      PROPERTIES OUTPUT_NAME image_view
                      PREFIX "")
這樣就可舊愛那個target   rviz_image_view 改爲image_view。

2)設置輸出路徑:

ROS中的輸出路徑時默認的,但是也可通過下面進行修改:

set_target_properties(python_module_library
  PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION})
3)頭文件路徑和庫文件路徑:

在我們指定target之前,我們需要指明對target而言,在哪裏找源文件,特別是在哪裏找頭文件,在哪裏找庫文件。

Include Paths:指明編譯代碼時在哪裏尋找頭文件;

Library Paths:指明可執行文件需要的庫文件在哪裏。

函數:

include_directories:他的參數是通過find_package產生的*_INCLUDE_DIRS變量和其他所有額外的頭文件路徑。例如:

include_directories(include ${Boost_INCLUDE_DIRS} ${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(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS})
6)鏈接庫:

使用target_link_libraries函數來指定可執行文件鏈接的庫。這個要用在add_executable()後面。形如:

target_link_libraries(<executableTargetName>, <lib1>, <lib2>, ... <libN>)
比如:

add_executable(foo src/foo.cpp)
add_library(moo src/moo.cpp)
target_link_libraries(foo moo)
這就是將可執行文件foo鏈接到庫文件libmoo.so。

發佈了24 篇原創文章 · 獲贊 38 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章