본문으로 바로가기

ROS 2 에서 CMakeLists.txt 이해하기

category 강좌/ROS2 2026. 5. 24. 03:29

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의 역할은 패키지 종류에 따라 다릅니다.

 

                           패키지                               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 설정 누락에서 나옵니다.

728x90
728x90