본문 바로가기
ROS

[ROS2] 다른 패키지에서 라이브러리 가져다 쓰기 | CMakeLists.txt, package.xml skeleton 정리

by yongee97 2026. 4. 12.

문제상황

ROS2로 패키지를 나누다 보면,

  • 한 패키지에서 C++ 라이브러리를 빌드하고
  • 다른 패키지에서 그 라이브러리를 find_package()로 가져다 써야 하는 경우가 자주 있다.

그런데 막상 해보면 항상 비슷한 부분에서 헷갈린다.

  • package.xml에 뭘 써야 하는지
  • CMakeLists.txt에서 find_package()는 누구를 해야 하는지
  • target_include_directories()와 install()의 역할 차이
  • ament_export_targets()는 왜 필요한지
  • 받는 쪽에서는 어떤 이름으로 링크해야 하는지

이번 글에서는 이 내용을 최소 skeleton 기준으로만 정리해본다.

  • 불필요한 옵션은 빼고 꼭 필요한 구조만 남겼다.
  • provider 패키지와 consumer 패키지가 각각 뭘 해야 하는지만 정리한다.

 

목표

이번 글에서서는 아래 두 개의 패키지를 만든다.

  • lib_pkg
    • C++ 라이브러리를 빌드해서 외부 패키지에 제공하는 패키지
  • app_pkg
    • lib_pkg를 가져와서 링크하고 ROS2 node를 실행하는 패키지

전체 구조

ros2_ws/
└── src/
    ├── lib_pkg/
    │   ├── CMakeLists.txt
    │   ├── package.xml
    │   ├── include/
    │   │   └── lib_pkg/
    │   │       └── lib_a.hpp
    │   └── src/
    │       └── lib_a.cpp
    └── app_pkg/
        ├── CMakeLists.txt
        ├── package.xml
        └── src/
            └── main.cpp

 

1. provider 패키지: lib_pkg

lib_pkg는 라이브러리를 제공하는 패키지로, 지금은 ROS2 node를 실행하지 않는다.

즉, ROS2 패키지이긴 하지만 rclcpp가 꼭 필요한 건 아니며, 여기서는 단순히 C++ 라이브러리 하나를 만들고 export한다.

 

1.1 package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>lib_pkg</name>
  <version>0.0.0</version>
  <description>Minimal ROS 2 C++ library package</description>
  <maintainer email="you@example.com">you</maintainer>
  <license>MIT</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

 

1.2 CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
project(lib_pkg)

find_package(ament_cmake REQUIRED)

# Build library target
add_library(lib_a STATIC
  src/lib_a.cpp
)

# Public include paths for this target:
# - BUILD_INTERFACE: used while building in this workspace
# - INSTALL_INTERFACE: used by downstream packages after installation
target_include_directories(lib_a PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>
)

# Install public headers
install(
  DIRECTORY include/
  DESTINATION include
)

# Install library target and export it for downstream packages
install(
  TARGETS lib_a
  EXPORT export_${PROJECT_NAME}
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
)

# Make exported targets available to find_package() consumers
ament_export_targets(export_${PROJECT_NAME} HAS_LIBRARY_TARGET)

ament_package()

 

 

add_library(lib_a ...)

  • lib_a라는 C++ 라이브러리 타깃을 생성한다.

target_include_directories(...)

라이브러리와 관련된 include 경로를 정의한다.

  • BUILD_INTERFACE
    • 현재 워크스페이스에서 빌드할 때 사용할 include 경로
  • INSTALL_INTERFACE
    • 설치 후, 다른 패키지가 이 타깃을 사용할 때 필요한 include 경로

install(

 DIRECTORY include/

 DESTINATION include

)

이건 패키지 내에 존재하는 헤더 파일을 실제 설치 경로로 복사하는 부분이다.

  • DIRECTORY include/
    • include 폴더가 아니라 그 안의 내용만 복사됨
  • DESTINATION include
    • 실제 설치 위치는 보통 <install-prefix>/include가 된다.

install(TARGETS ...)

이건 빌드된 라이브러리 타깃을 설치하는 부분이다.

 

ament_export_targets(...)

이게 있어야 downstream 패키지에서 find_package(lib_pkg REQUIRED) 후
export된 타깃을 링크해서 사용할 수 있다.

 

1.3 헤더 / 소스 파일

// include/lib_pkg/lib_a.hpp
#pragma once

#include <string>

namespace lib_pkg
{

std::string make_greeting(const std::string & name);

}  // namespace lib_pkg
// src/lib_a.cpp
#include "lib_pkg/lib_a.hpp"

namespace lib_pkg
{

std::string make_greeting(const std::string & name)
{
  return "Hello, " + name;
}

}  // namespace lib_pkg

 

2. consumer 패키지: app_pkg

app_pkg는 lib_pkg를 사용하는 패키지다.

  • ROS2 node를 실행해야 하므로 rclcpp가 필요하고
  • lib_pkg의 라이브러리를 쓰므로 lib_pkg에도 의존한다.

2.1 package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>app_pkg</name>
  <version>0.0.0</version>
  <description>ROS 2 node package using lib_pkg</description>
  <maintainer email="you@example.com">you</maintainer>
  <license>MIT</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>lib_pkg</depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>
  • <depend>rclcpp</depend>
  • <depend>lib_pkg</depend>

이 패키지는 node 기능과 외부 라이브러리 둘 다 필요하다.

 

2.2 CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
project(app_pkg)

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(lib_pkg REQUIRED)

add_executable(app_node
  src/main.cpp
)

# Link ROS 2 and exported library target from lib_pkg
target_link_libraries(app_node PRIVATE
  rclcpp::rclcpp
  lib_pkg::lib_a
)

# Install executable so ros2 run can find it
install(TARGETS app_node
  DESTINATION lib/${PROJECT_NAME}
)

ament_package()

 

 

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(lib_pkg REQUIRED)

 
  • ament_cmake : 이 패키지 자체 빌드를 위해 필요
  • rclcpp : ROS2 node 실행을 위해 필요
  • lib_pkg : 앞서 작성한 외부 라이브러리
 

add_executable(app_node
 src/main.cpp
)

 

실행파일을 생성한다. 여기서 app_node는 최종 node 실행파일 이름이다.

 

target_link_libraries(app_node PRIVATE
 rclcpp::rclcpp
 lib_pkg::lib_a
)

 

실행파일에 라이브러리를 링크한다.

  • rclcpp::rclcpp : ROS2 C++ node 기능
  • lib_pkg::lib_a : lib_pkg가 export한 라이브러리 타깃

find_package(lib_pkg REQUIRED)는 패키지를 찾는 단계이고,
실제로 라이브러리를 쓰는 건 target_link_libraries()에서 한다.

 

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

 

실행파일을 설치한다. 이렇게 해야 ros2 run app_pkg app_node로 실행할 수 있다.

 

2.3 main.cpp

#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "lib_pkg/lib_a.hpp"

class AppNode : public rclcpp::Node
{
public:
  AppNode()
  : Node("app_node")
  {
    RCLCPP_INFO(this->get_logger(), "%s", lib_pkg::make_greeting("ROS2").c_str());
  }
};

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<AppNode>();
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}

 

이 예제에서는:

  • lib_pkg/lib_a.hpp를 include하고
  • node 생성 시 로그 한 줄을 출력하여 lib_pkg 패키지의 함수가 app_pkg의 노드 안에서 정상적으로 호출되는지를 확인한다.

 

3. 실행 결과

다음 명령어를 통해 app_pkg에서 빌드한 ROS2 노드를 실행한다.

ros2 run app_pkg app_node

 

실행 결과 다음과 같이 lib_pkg 에서 정의한 함수가 정상적으로 동작한다.