# CMakeList.txt 介紹 ## <font color="orange">CMake 是什麼</font> > CMake(Cross platform Make)一種自動化的軟體系統建置工具,可以整合一些邊一時的各種步驟,透過CMakeList.txt 檔案自動生成一堆編譯所需的檔案。 ## <font color="orange">C++中的 CMake 流程</font> ::::spoiler **以下面這個專案架構為例,說明如何使用 cmake 建置專案** ::::info :::warning Example ├── CMakeLists.txt ├── lib │ ├── CMakeLists.txt │ ├── f1.cpp │ ├── f1.h │ ├── f2.cpp │ └── f2.h └── main.cpp ::: 1. 建立 CMakeLists.txt 檔案 2. `$ cmake`:走訪整個專案資料夾(也會讀取子資料夾中的 CMakeLists.txt)產生原生建置系統的設定檔 3. `$ make`:編譯 (如果是 linux 原始的環境,使用的編譯器是 make) 4. 然後就可以執行了 :::: ## <font color="orange">基本的 CMakeList.txt 結構</font> - **Project command**:包括處理檔案相關,如增加原始檔,專案的執行樹和安裝時的架構。 - **Scripting command**:處理 flow control 等等相關的語法,如 if-else, for-loop, while-break, continue 等 ::: spoiler **常用的語法** - 設定最低 CMake 版本要求:`cmake_minimum_required(VERSION 3.10)` - 設定專案名稱:`project(MyProject)` - 添加內部 library:`add_library(Game name.cpp)` - 將主要要執行的檔案添加至專案中:`add_executable(my_executable main.cpp helper.cpp)` - 設定編譯選項:`target_compile_options(my_executable PRIVATE -Wall -Wextra)` - 連結外部 library: - `find_package(PkgConfig REQUIRED)` - `target_link_libraries(my_executable PRIVATE ${LIBRARY_LIBRARIES})` - 安裝目標檔案和 header file: - `install(TARGETS` - `install(FILES` ::: ## <font color="orange">ROS1 與 CMake</font> - 如前面所述,使用 CMake 建置的專案都會包含一個或多個 CMakeLists.txt 檔案去描述如何編譯程式碼以及將其安裝到哪裡。 - 在 ROS1 中,將 CMake 與 catkin 編譯器合併使用時,我們所要編寫的 CMakeLists.txt 檔案就會多了一些條件限制並且延伸出一些特定語法,官網稱之為 vanilla CMakeLists.txt (加了一些香料 :leaves: ) ## <font color="orange">ROS1 中的編譯器</font> >catkin 是 ROS 官方的一個編譯建置系統,是原本的 ROS 的編譯建置系統rosbuild 的發展。`$ catkin_make` 指令是將 `cmake` 與 `make` 的編譯方式做了一個封裝的指令工具,規範了工作路徑與生成檔路徑。 ## <font color="orange">ROS1 的 CMakeList.txt 結構</font> - `cmake_minimum_required(VERSION 3.0.2)`:CMake 的版本 - `project({package_name})`:Package 名稱 - `add_compile_options(-std=c++17)`:C++ 的版本 - `find_package(catkin REQUIRED COMPONENTS`:需要使用到的外部 package - 如果 CMake 透過 find_package() 查找到 package,它就會建立 CMake 環境變數儲存 package 相關資訊,方便後續腳本使用。 - `add_message_files()` & `add_service_files()` & `add_action_files()`:建立Message/Service/Action的檔案 - `generate_messages()`:編譯上述 message/service/action 時需要用到的原始 message 型態 - `catkin_package()`:編譯上述 package 時需要用到的模組資訊 - catkin_package 和 find_package 很像,catkin_package 是 catkin 延伸出來的語法,一樣會被建立在環境變數中,主要有 5 個選項可以使用: 1. `INCLUDE_DIRS`: - include 資料夾 - 直接在後面加上 include 4. `LIBRARIES`:函式庫 5. `CATKIN_DEPENDS`:其他 catkin package - 可以把 find_package 有抓進來的東西都寫一遍 6. `DEPENDS`:其他非 catkin 編譯的 package 7. `CFG_EXTRAS`:額外的設定檔 - `add_library({library_name} src/{library_file_name}.cpp)`:編譯非 node 的所有其他 c++ 程式檔案 - `add_executable({node_name} src/{node_file_name}.cpp)`:編譯 node - `target_link_libraries({node_name} {library_name})`:node 會用到的其他 c++ 程式檔案 - `add_dependencies({node_name} {target_name}.{file extension})`: - `catkin_make` 的時候就會優先去 build dependance 內的 {target_name} 這個檔案,如果 node 有用到自定義 message,可以加這一行優先編譯自定義 message - `install(TARGETS `:install node 檔案和 library 檔案 - `install(DIRECTORY `:install include 資料夾(header file) - `install(FILES `:install 其他的檔案(launch file, bag file, config file etc.) :::spoiler **template** ```=txt cmake_minimum_required(VERSION 3.0.2) project(bt_app) add_compile_options(-std=c++17) find_package(catkin REQUIRED COMPONENTS std_msgs behaviortree_cpp geometry_msgs nav_msgs roscpp rospy actionlib actionlib_msgs ) ## System dependencies are found with CMake's conventions find_package(Boost REQUIRED COMPONENTS system) ################################################ ## Declare ROS messages, services and actions ## ################################################ # Generate messages in the 'msg' folder add_message_files( FILES Message1.msg Message2.msg ) # Generate services in the 'srv' folder add_service_files( FILES Service1.srv Service2.srv ) # Generate actions in the 'action' folder add_action_files( FILES test.action ) # Generate added messages and services with any dependencies listed here generate_messages( DEPENDENCIES geometry_msgs std_msgs actionlib_msgs ) ################################################ ## Declare ROS dynamic reconfigure parameters ## ################################################ # Generate dynamic reconfigure parameters in the 'cfg' folder generate_dynamic_reconfigure_options( cfg/DynReconf1.cfg cfg/DynReconf2.cfg ) ################################### ## catkin specific configuration ## ################################### catkin_package( # INCLUDE_DIRS include # LIBRARIES bt_app CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs actionlib_msgs # DEPENDS system_lib ) ########### ## Build ## ########### include_directories( include ${catkin_INCLUDE_DIRS} ) # Declare Action Node sources file(GLOB BT_ACTION_NODE_SOURCES "src/bt_action_node/*.cpp") # Declare Decorator Node sources file(GLOB BT_DECORATOR_NODE_SOURCES "src/bt_decorator_node/*.cpp") # Declare Utils Node sources file(GLOB BT_UTILS_NODE_SOURCES "src/bt_utils_node/*.cpp") add_library(BTKERNEL src/bt_kernel_lib.cpp) target_link_libraries(BTKERNEL ${catkin_LIBRARIES} ${ARMADILLO_LIBRARIES}) add_dependencies(BTKERNEL ${catkin_EXPORTED_TARGETS}) add_library(BT_ACTION_NODE ${BT_ACTION_NODE_SOURCES}) target_link_libraries(BT_ACTION_NODE ${catkin_LIBRARIES} ${ARMADILLO_LIBRARIES}) add_dependencies(BT_ACTION_NODE ${catkin_EXPORTED_TARGETS}) add_library(BT_DECORATOR_NODE ${BT_DECORATOR_NODE_SOURCES}) target_link_libraries(BT_DECORATOR_NODE ${catkin_LIBRARIES} ${ARMADILLO_LIBRARIES}) add_dependencies(BT_DECORATOR_NODE ${catkin_EXPORTED_TARGETS}) add_library(BT_UTILS_NODE_NODE ${BT_UTILS_NODE_SOURCES}) target_link_libraries(BT_UTILS_NODE_NODE ${catkin_LIBRARIES} ${ARMADILLO_LIBRARIES}) add_dependencies(BT_UTILS_NODE_NODE ${catkin_EXPORTED_TARGETS}) add_executable(test_action_client src/node/simple_action_client.cpp) target_link_libraries(test_action_client ${catkin_LIBRARIES} ) add_executable(test_action_server src/node/simple_action.cpp) target_link_libraries(test_action_server ${catkin_LIBRARIES} ) add_executable(bt src/node/bt.cpp) target_link_libraries(bt ${catkin_LIBRARIES} BT_ACTION_NODE BT_DECORATOR_NODE BT_UTILS_NODE_NODE BTKERNEL ) add_executable(kernel_test src/node/kernel_test.cpp) target_link_libraries(kernel_test ${catkin_LIBRARIES} BTKERNEL ) ############# ## Install ## ############# install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} ) install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE ) # Mark other files for installation (e.g. launch and bag files, etc.) install(FILES # myfile1 # myfile2 DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) ``` ::: # package.xml 介紹 ## <font color="orange">package.xml 是什麼?</font> > 儲存 package 的基本訊息,包含版本、維護者、授權形式以及這個 package 會用到的其他 package 的說明 ## <font color="orange">基本指令解釋</font> - `buildtool_depend`:建立這個 package 時要使用的 tool(有點像編譯器的感覺),如果是採用 catkin_make 則就叫做 catkin - `build_depend`:建立 package 過程會使用到的其他 package,期間會把裡面的一些資訊拆開存起來 - `build_export_depend`:跟前面的 `build_depend` 很像,但是如果現在這個 package 會被 work space 底下的其他 package 使用的話,就要使用這個指令 :::spoiler 生動的說明 例如說現在寫了一個很好用的導航程式包,然後我想要用在我的小烏龜作業,所以小烏龜作業的 CMakeList.txt 就要 find_package 這個導航程式包,那這時導航程式包裡的 package.xml 就會使用到 `build_export_depend` 指令 ::: - `exec_depend`:執行的時候要用的其他 package,但因為這些 package 想要用基本上都需要經過構建,所以就會和前面的幾乎重複。 - `test_depend`:一樣是執行時要用的其他 package,但應用的時機不同