1. CMakeLists.txt란?
CMakeLists.txt는 ROS 2 패키지를 빌드할 때 사용하는 설정 파일입니다.
쉽게 말하면 다음 역할을 합니다.
이 패키지를 어떻게 빌드할지,
어떤 ROS 2 패키지를 사용할지,
어떤 실행 파일을 만들지,
어디에 설치할지 알려주는 파일
ROS 2 Humble에서는 보통 colcon build 명령으로 워크스페이스를 빌드합니다.
cd ~/ros2_study
colcon build
이때 C++ 패키지나 인터페이스 패키지의 CMakeLists.txt를 읽어서 빌드 규칙을 처리합니다.
2. Python 패키지는 보통 CMakeLists.txt를 사용하지 않는다
ROS 2에서 Python 패키지는 보통 ament_python 빌드 타입을 사용합니다.
예를 들어 my_first_package가 Python 패키지라면 일반적으로 다음 파일들을 중심으로 동작합니다.
my_first_package/
├── package.xml
├── setup.py
├── setup.cfg
├── resource/
│ └── my_first_package
└── my_first_package/
└── __init__.py
Python 패키지는 보통 CMakeLists.txt가 핵심 파일이 아닙니다.
Python 패키지에서 중요한 파일은 다음입니다.
| setup.py | Python 노드 실행 등록 |
| setup.cfg | 실행 파일 설치 경로 설정 |
| package.xml | 패키지 정보와 의존성 선언 |
따라서 my_first_package 같은 Python 패키지에서는 일반적으로 CMakeLists.txt를 수정하지 않습니다.
Python 노드를 실행 가능하게 만드는 설정은 보통 setup.py에서 합니다.
예를 들어 Python 노드를 등록할 때는 다음처럼 작성합니다.
entry_points={
'console_scripts': [
'my_python_node = my_first_package.my_python_node:main',
],
},
그러면 다음 명령으로 실행할 수 있습니다.
ros2 run my_first_package my_python_node
정리하면 다음과 같습니다.
Python 패키지 = setup.py 중심
C++ 패키지 = CMakeLists.txt 중심
인터페이스 패키지 = CMakeLists.txt 중심
3. C++ 패키지 my_cpp_package의 CMakeLists.txt
my_cpp_package는 C++ 패키지입니다.
C++ 패키지는 보통 ament_cmake를 사용합니다.
그래서 CMakeLists.txt가 매우 중요합니다.
기본 구조는 다음과 같습니다.
cmake_minimum_required(VERSION 3.8)
project(my_cpp_package)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
add_executable(my_cpp_node src/my_cpp_node.cpp)
ament_target_dependencies(my_cpp_node
rclcpp
)
install(TARGETS
my_cpp_node
DESTINATION lib/${PROJECT_NAME}
)
ament_package()
4. C++ 패키지 : CMakeLists.txt 분석
1) cmake_minimum_required
cmake_minimum_required(VERSION 3.8)
이 패키지를 빌드하기 위해 필요한 최소 CMake 버전을 지정합니다.
ROS 2 Humble에서는 기본 템플릿에서 보통 3.8을 사용합니다.
2) project
project(my_cpp_package)
현재 CMake 프로젝트 이름을 지정합니다.
이 이름은 보통 package.xml의 패키지 이름과 같아야 합니다.
package.xml에 다음처럼 되어 있다면,
<name>my_cpp_package</name>
CMakeLists.txt도 다음처럼 맞추는 것이 좋습니다.
project(my_cpp_package)
패키지 이름이 서로 다르면 빌드나 설치 경로에서 헷갈릴 수 있습니다.
3) 컴파일 경고 옵션
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
C++ 컴파일러가 GCC 또는 Clang일 때 경고 옵션을 추가합니다.
| -Wall | 기본 경고 활성화 |
| -Wextra | 추가 경고 활성화 |
| -Wpedantic | C++ 표준에 엄격한 경고 활성화 |
실습 단계에서는 경고가 귀찮아 보일 수 있지만, 실제 개발에서는 경고를 무시하면 나중에 버그로 돌아옵니다.
4) find_package
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package()는 사용할 패키지를 찾는 명령입니다.
find_package(ament_cmake REQUIRED)
이 줄은 ROS 2의 CMake 빌드 시스템을 사용하겠다는 의미입니다.
find_package(rclcpp REQUIRED)
이 줄은 C++에서 ROS 2 노드를 만들기 위해 rclcpp를 사용하겠다는 의미입니다.
C++ 코드에서 다음 헤더를 사용한다면,
#include "rclcpp/rclcpp.hpp"
CMakeLists.txt에는 반드시 다음이 있어야 합니다.
find_package(rclcpp REQUIRED)
5) add_executable
add_executable(my_cpp_node src/my_cpp_node.cpp)
이 줄은 C++ 소스 파일을 빌드해서 실행 파일을 만드는 명령입니다.
형식은 다음과 같습니다.
add_executable(실행파일이름 소스파일경로)
예를 들어 다음처럼 작성하면,
add_executable(my_cpp_node src/my_cpp_node.cpp)
src/my_cpp_node.cpp 파일을 빌드해서 my_cpp_node라는 실행 파일을 만듭니다.
이 실행 파일은 나중에 다음 명령으로 실행합니다.
ros2 run my_cpp_package my_cpp_node
단, ros2 run으로 실행하려면 아래의 install() 설정도 필요합니다.
6) ament_target_dependencies
ament_target_dependencies(my_cpp_node
rclcpp
)
이 줄은 my_cpp_node 실행 파일이 rclcpp 패키지에 의존한다고 알려줍니다.
즉, 다음 관계입니다.
my_cpp_node 실행 파일
└── rclcpp 필요
만약 C++ 노드에서 std_msgs도 사용한다면 다음처럼 추가해야 합니다.
find_package(std_msgs REQUIRED)
ament_target_dependencies(my_cpp_node
rclcpp
std_msgs
)
규칙은 단순합니다.
C++ 코드에서 어떤 ROS 2 패키지를 include하면
CMakeLists.txt에도 find_package와 ament_target_dependencies를 추가한다.
7) install
install(TARGETS
my_cpp_node
DESTINATION lib/${PROJECT_NAME}
)
이 줄은 빌드된 실행 파일을 ROS 2가 찾을 수 있는 위치에 설치합니다.
이 설정이 없으면 빌드는 성공해도 다음 명령이 실패할 수 있습니다.
ros2 run my_cpp_package my_cpp_node
C++ 실행 파일은 보통 다음 위치에 설치합니다.
DESTINATION lib/${PROJECT_NAME}
실제 설치 위치는 대략 다음과 같습니다.
~/ros2_study/install/my_cpp_package/lib/my_cpp_package/my_cpp_node
8) ament_package
ament_package()
ament_package()는 현재 패키지를 ROS 2 패키지로 등록하는 명령입니다.
보통 CMakeLists.txt의 가장 마지막에 작성합니다.
쉽게 말하면 다음 의미입니다.
이 패키지는 ROS 2 패키지입니다.
빌드 시스템에 등록해 주세요.
5. 인터페이스 패키지 my_first_package_msgs의 CMakeLists.txt
my_first_package_msgs는 인터페이스 패키지입니다.
인터페이스 패키지는 보통 다음 파일을 만듭니다.
my_first_package_msgs/
├── msg/
│ └── MyMsg.msg
├── srv/
│ └── MySrv.srv
├── action/
│ └── MyAction.action
├── CMakeLists.txt
└── package.xml
인터페이스 패키지는 C++ 실행 파일을 만드는 패키지가 아닙니다.
대신 .msg, .srv, .action 파일을 기반으로 Python과 C++에서 사용할 수 있는 코드를 자동 생성합니다.
1) 기본 CMakeLists.txt 예시
cmake_minimum_required(VERSION 3.8)
project(my_first_package_msgs)
find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/MyMsg.msg"
"srv/MySrv.srv"
)
ament_export_dependencies(rosidl_default_runtime)
ament_package()
2) rosidl_default_generators
find_package(rosidl_default_generators REQUIRED)
이 줄은 메시지, 서비스, 액션 코드를 생성하기 위한 패키지를 찾습니다.
인터페이스 패키지에서는 거의 필수입니다.
3) rosidl_generate_interfaces
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/MyMsg.msg"
"srv/MySrv.srv"
)
이 부분이 인터페이스 패키지의 핵심입니다.
msg/MyMsg.msg 파일과 srv/MySrv.srv 파일을 읽어서 Python과 C++에서 사용할 수 있는 코드를 자동 생성합니다.
예를 들어 MyMsg.msg가 있다면 C++에서는 다음처럼 사용할 수 있습니다.
#include "my_first_package_msgs/msg/my_msg.hpp"
Python에서는 다음처럼 사용할 수 있습니다.
from my_first_package_msgs.msg import MyMsg
즉, my_first_package_msgs 패키지는 Python 패키지와 C++ 패키지 사이에서 공통 메시지 타입을 제공하는 역할을 합니다.
4) ament_export_dependencies
ament_export_dependencies(rosidl_default_runtime)
이 줄은 다른 패키지에서 my_first_package_msgs의 메시지를 사용할 수 있도록 런타임 의존성을 내보내는 설정입니다.
인터페이스 패키지에서는 보통 다음 줄을 넣습니다.
ament_export_dependencies(rosidl_default_runtime)
6. C++ 패키지에서 인터페이스 패키지 사용하기
my_cpp_packagesms에서 my_first_package_msgs의 메시지를 사용하려면 CMakeLists.txt에 의존성을 추가해야 합니다.
예시는 다음과 같습니다.
cmake_minimum_required(VERSION 3.8)
project(my_cpp_package)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(my_first_package_msgs REQUIRED)
add_executable(my_cpp_node src/my_cpp_node.cpp)
ament_target_dependencies(my_cpp_node
rclcpp
my_first_package_msgs
)
install(TARGETS
my_cpp_node
DESTINATION lib/${PROJECT_NAME}
)
ament_package()
핵심은 두 줄입니다.
find_package(my_first_package_msgs REQUIRED)
ament_target_dependencies(my_cpp_node
rclcpp
my_first_package_msgs
)
이 설정이 있어야 C++ 코드에서 다음처럼 메시지를 include할 수 있습니다.
#include "my_first_package_msgs/msg/my_msg.hpp"
7. Python 패키지에서 인터페이스 패키지 사용하기
Python 패키지인 my_first_package는 보통 CMakeLists.txt가 아니라 package.xml과 setup.py를 중심으로 설정합니다.
Python 코드에서는 다음처럼 메시지를 import합니다.
from my_first_package_msgs.msg import MyMsg
이때 my_first_package의 CMakeLists.txt를 수정하는 것이 아니라, 보통 package.xml에 의존성을 추가합니다.
<depend>my_first_package_msgs</depend>
Python 패키지에서는 메시지 사용을 위해 CMakeLists.txt를 건드리는 방식이 아닙니다.
정리하면 다음과 같습니다.
| C++ 패키지에서 메시지 사용 | CMakeLists.txt, package.xml |
| Python 패키지에서 메시지 사용 | 주로 package.xml, Python 코드 |
| 메시지 자체를 생성 | 인터페이스 패키지의 CMakeLists.txt |
8. ROS 2 Humble 기준 빌드 순서
워크스페이스는 ros2_study입니다.
cd ~/ros2_study
colcon build
source install/setup.bash
특정 패키지만 빌드하려면 다음처럼 할 수 있습니다.
colcon build --packages-select my_first_package_msgs
colcon build --packages-select my_cpp_packagesms
하지만 인터페이스 패키지를 사용하는 경우에는 보통 전체 빌드를 권장합니다.
cd ~/ros2_study
colcon build
source install/setup.bash
빌드 순서는 개념적으로 다음과 같습니다.
1. my_first_package_msgs
└── msg, srv 코드 생성
2. my_cpp_package
└── 생성된 메시지를 사용해서 C++ 노드 빌드
3. my_first_package
└── Python 노드에서 생성된 메시지 import
9. 최종 정리
ROS 2 Humble에서 CMakeLists.txt의 역할은 패키지 종류에 따라 다릅니다.
| my_cpp_package | 매우 중요 | C++ 노드 빌드, 의존성 연결, 실행 파일 설치 |
| my_first_package | 낮음 | Python 패키지는 보통 setup.py 중심 |
| my_first_package_msgs | 매우 중요 | msg, srv, action 코드 자동 생성 |
핵심만 기억하면 됩니다.
C++ 패키지에서는 CMakeLists.txt가 빌드의 중심이다.
Python 패키지에서는 setup.py가 실행 등록의 중심이다.
인터페이스 패키지에서는 CMakeLists.txt가 메시지 생성의 중심이다.
my_cpp_package에서 중요한 명령은 다음입니다.
find_package()
add_executable()
ament_target_dependencies()
install()
ament_package()
my_first_package_msgs에서 중요한 명령은 다음입니다.
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/MyMsg.msg"
)
ament_export_dependencies(rosidl_default_runtime)
실무 기준으로 보면, CMakeLists.txt는 그냥 형식 파일이 아닙니다.
C++ 노드가 빌드되지 않거나, 메시지를 include하지 못하거나, ros2 run에서 실행 파일을 찾지 못하는 문제는 대부분 CMakeLists.txt 설정 누락에서 나옵니다.
'강좌 > ROS2' 카테고리의 다른 글
| C++ Service Client 작성 실습 : 모바일 로봇 긴급정지 요청 보내기 (0) | 2026.05.24 |
|---|---|
| ROS 2 C++ Action Server / Client 실습 #1 (0) | 2026.05.24 |
| ROS 2 Python 패키지의 setup.py 이해하기 (0) | 2026.05.24 |
| ROS 2 package.xml 이해하기 : Python 패키지와 C++ 패키지 기준 (0) | 2026.05.24 |
| C++ ROS 2 패키지 생성하기 (0) | 2026.05.24 |