Atlas Robotics
ROS2 PackageTrung bình

CMakeLists.txt trong package ROS2 — đọc hiểu từng dòng

Atlasbot · 17/8/2026 · 11 phút đọc

CMakeLists.txt trong package ROS2 — đọc hiểu từng dòng
Cấu trúc chuẩn của một CMakeLists.txt trong package ament_cmake

Mở CMakeLists.txt của một package ament_cmake bất kỳ lần đầu thường thấy rối vì nhiều dòng lệnh lạ. Thực tế phần lớn package chỉ lặp lại 5-6 khối lệnh theo đúng thứ tự cố định — nắm được khuôn này là đọc hiểu (và sửa) được hầu hết CMakeLists.txt trong hệ sinh thái ROS2.

Khái niệm chính

cmake_minimum_required(VERSION 3.8)
project(my_cpp_pkg)

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(hello_node src/hello_node.cpp)
ament_target_dependencies(hello_node rclcpp std_msgs)

install(TARGETS hello_node
  DESTINATION lib/${PROJECT_NAME})

ament_package()
  • cmake_minimum_required / project() — khai tên project, bắt buộc với mọi file CMake chuẩn, không riêng ROS2
  • find_package(... REQUIRED) — tìm và nạp từng dependency đã khai ở package.xml; thiếu dòng này cho dependency nào thì build sẽ báo lỗi "package not found" ngay cả khi package đó đã cài trên máy
  • add_executable() — khai một file .cpp sẽ được biên dịch thành binary, đặt tên executable (tên dùng với ros2 run)
  • ament_target_dependencies() — tự động link đúng thư viện + include path cho executable vừa khai, dựa theo các find_package() ở trên — thay thế cho target_link_libraries()/target_include_directories() thuần CMake mà bạn phải tự viết nếu không dùng ament_cmake
  • install() — khai nơi copy file kết quả vào thư mục install/ của workspace, để ros2 run/ros2 launch tìm thấy được
  • ament_package() — luôn là dòng cuối cùng, đăng ký package vào hệ thống ament (sinh các file cần thiết để package khác find_package() được nó)

Tóm lại: Thứ tự cố định là find_package (khai cần gì) → add_executable (khai biên dịch gì) → ament_target_dependencies (khai link gì) → install (khai đặt ở đâu) → ament_package (chốt lại). Sai thứ tự — ví dụ install() một executable chưa được add_executable() — sẽ báo lỗi CMake ngay khi build.

Nguyên lý hoạt động

Một package có nhiều node chỉ cần lặp lại cặp add_executable + ament_target_dependencies + liệt kê thêm trong install(TARGETS ...):

add_executable(node_a src/node_a.cpp)
ament_target_dependencies(node_a rclcpp)

add_executable(node_b src/node_b.cpp)
ament_target_dependencies(node_b rclcpp std_msgs)

install(TARGETS node_a node_b
  DESTINATION lib/${PROJECT_NAME})

Nếu có code dùng chung giữa nhiều node (ví dụ một class helper), tách thành thư viện riêng bằng add_library() rồi cho từng executable link vào, tránh biên dịch trùng lặp cùng một đoạn code nhiều lần:

add_library(my_helper_lib src/helper.cpp)
ament_target_dependencies(my_helper_lib rclcpp)

add_executable(node_a src/node_a.cpp)
target_link_libraries(node_a my_helper_lib)

Kiến thức kỹ thuật

Thông số

Một số macro ament_cmake khác ít gặp hơn nhưng quan trọng khi package của bạn được package khác dùng lại:

MacroDùng khi nào
cmake_minimum_required(VERSION 3.8)Phiên bản CMake tối thiểu ROS2 hiện hành yêu cầu
ament_export_targets()Cho phép package khác find_package() và dùng thư viện của bạn
ament_export_dependencies()Tự động kéo theo dependency của bạn khi package khác dùng thư viện của bạn
ament_export_include_directories()Cho package khác biết header của bạn nằm ở đâu

Ứng dụng thực tế

Khi một package chứa thư viện dùng chung cho nhiều package khác trong hệ thống robot (VD: 1 package robot_utils chứa các hàm hình học/toán học dùng lại ở cả node điều khiển lẫn node xử lý cảm biến), cần thêm bộ ament_export_* để "xuất khẩu" đúng cách — thiếu bước này, package khác dù find_package(robot_utils REQUIRED) thành công vẫn không link được vào thư viện bên trong, vì ament không biết phải export những gì. Đây là khác biệt giữa 1 package "chỉ tự dùng nội bộ" và 1 package "được thiết kế để tái sử dụng" trong toàn hệ thống.

Với package lớn có nhiều file .cpp, thay vì liệt kê từng file trong add_executable(), thường dùng biến CMake để gom danh sách file nguồn gọn hơn:

file(GLOB SOURCES "src/*.cpp")
add_executable(main_node ${SOURCES})

Cách này tiện khi package đang phát triển nhanh (thêm file .cpp mới thường xuyên), nhưng cần lưu ý file(GLOB ...) chỉ quét danh sách file tại thời điểm chạy cmake, không tự phát hiện file mới thêm vào giữa các lần build — nếu thêm file .cpp mới mà build không nhận, cần chạy lại cmake từ đầu (rm -rf build && colcon build) thay vì chỉ colcon build thông thường.

Ví dụ thực tế

$ colcon build --packages-select my_cpp_pkg
Output khi thiếu find_package(std_msgs REQUIRED) dù code có #include <std_msgs/...>:

CMake Error at CMakeLists.txt:9 (ament_target_dependencies):
  Could not find a package configuration file provided by "std_msgs"

-- Configuring incomplete, errors occurred!

Thông báo lỗi chỉ thẳng đúng dòng và đúng package thiếu — đọc kỹ dòng CMake Error at CMakeLists.txt:X luôn cho biết chính xác vị trí cần sửa, thay vì phải đoán mò trong toàn bộ file.

Lỗi thường gặp

Triệu chứngNguyên nhân
Could not find a package configuration file for "X"Thiếu find_package(X REQUIRED), hoặc package X chưa cài/chưa source đúng workspace
undefined reference to ... khi linkThiếu tên thư viện trong ament_target_dependencies() dù đã find_package()
ros2 run báo không thấy executable dù build "thành công"Thiếu executable đó trong install(TARGETS ...)
Package khác không link được thư viện của bạn dù find_package() thành côngThiếu ament_export_targets()/ament_export_dependencies()

Kết luận

CMakeLists.txt trong ament_cmake tuân theo 1 khuôn cố định — hiểu đúng thứ tự find_package → add_executable/add_library → ament_target_dependencies → install → ament_package là đọc/sửa được hầu hết package C++ trong hệ sinh thái ROS2, kể cả những package chưa từng thấy trước đó. Bài tiếp theo trong chuyên mục nói về package.xml — file khai dependency song hành với CMakeLists.txt, quyết định thứ tự build của cả workspace.

CMakeLists.txt trong package ROS2 — đọc hiểu từng dòng — Atlasbot