catkin_package DEPENDS, CATKIN_DEPENDS 탐구 (I)

Published:

이 포스트를 읽기에 앞서, find_package 를 잘 모르고 있다면 이 포스트를 먼저 읽어보길 권한다.

CMakeList를 작성하다보면 catkin_packageDEPENDS , CATKIN_DEPENDS가 너무나 헷갈린다. 어쩔 땐 find_package() 에 있는 패키지를 추가해야하고, 어느 패키지는 추가하지 않아도 빌드가 되기 때문이다.

이를 이해하기 위해 catkin_package() 가 왜 쓰이는지 먼저 살펴보자

catkin_package()

It installs the package.xml file, and it generates code for find_package and pkg-config so that other packages can get information about this package. For this purpose the information about include directories, libraries, further dependencies and CMake variables are used.

project(example_package)

...

catkin_package(CATKIN_DEPENDS std_msgs
               DEPENDS Boost
               INCLUDE_DIRS include
               LIBRARIES your_library)

Your catkin_package() needs to export all your library build targets so other catkin packages can use them. Suppose your_library depends on the ROS std_msgs package and on the system Boost thread library:

<depend>std_msgs</depend>
<build_export_depend>boost</build_export_depend>

Ref: catkin_package, Building and installing C++ libraries and headers

번역하면, example_package의 정보를 export하기 위한 용도로 catkin_package가 사용 된다고 한다.

예를 들면 catkin_package(DEPENDS Boost)example_package를 빌드하기 위해서 Boost 가 필요함을 다른 패키지에 알려주는 것이다 . 이 점이 find_package 와 목적이 다르다.

  • find_package() : 현재 example_package를 빌드할 때 필요한 패키지들을 찾아온다.
  • catkin_package(DEPENDS ... CATKIN_DEPENDS ...) : example_package 의 의존성이 있는 패키지들의 목록을 export 하기 위함이다. 즉 다른 패키지가 알 수 있게 하기 위함이다.

따라서, 처음 질문인 “find_package()에 포함된 패키지중 어느 패키지가 catkin_packageDEPENDS , CATKIN_DEPENDS에 추가 되어야 하는가?” 에 대한 답변은

다른 패키지에게, 의존성을 알려주어야하는 패키지들이 추가 되어야 한다고 답변을 할 수 있다.

예제를 통해 좀 더 정확히 이해해보자

예제

catkin workspace를 아래와 같이 bar, foo, fred 의 3가지 패키지를 가지도록 구성하였다.

(base) kyuhwanyeon@kyuhwanyeon-MS-7B17:~/personnel/cmake_tutorial$ tree -d
.
└── src
    ├── bar
    │   ├── include
    │   └── src
    ├── foo
    │   ├── include
    │   └── src
    └── fred
        ├── include
        └── src

여기서 의존 관계를

fred –> bar –> foo가 되도록 CMakeList를 작성해보자.

또한 fred –> bar –> foo 순서로 빌드가 될 수 있도록 package.xml 을 작성 해놓자. (이 포스트 참조)

이해를 돕기 위해 먼저 catkin_package의 DEPENDSCATKIN_DEPENDS 를 비워두고 빌드해보겠다.

[fred CMakeList.txt]

cmake_minimum_required(VERSION 3.0.2)
project(fred)

catkin_package(
 INCLUDE_DIRS include
 LIBRARIES fred
)

include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

add_library(${PROJECT_NAME}
  src/fred.cpp
)

fred library 를 만들도록 작성하였다. foo, boo 로 부터의 dependency 가 없음을 유의하자.

[bar CMakeList.txt]

cmake_minimum_required(VERSION 3.0.2)
project(bar)

find_package(catkin REQUIRED COMPONENTS
  fred
)

catkin_package(
 INCLUDE_DIRS include
 LIBRARIES bar
)

include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

add_library(${PROJECT_NAME}
  src/bar.cpp
)

target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})


bar library를 만들도록 작성하였다. find_package를 통해 fred 가 필요함을 명시하였고, fred 의 라이브러리 결과물이 catkin_LIBRARIES 에 포함이 되어있을테니까, 이를 사용할 수 있도록 link를 걸어주었다.

[foo CMakeList.txt]

cmake_minimum_required(VERSION 3.0.2)
project(foo)


find_package(catkin REQUIRED COMPONENTS
  bar
)

catkin_package(
)

include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

add_executable(${PROJECT_NAME} src/foo.cpp)

target_link_libraries(${PROJECT_NAME}
  ${catkin_LIBRARIES}
)

foo executable을 만들었다. bar library 를 사용하는 package이므로, find_package 를 통해 bar 를 찾도록 하였다. 또한 foo 패키지를 사용하는 다른 패키지는 없으니까 export 할 필요가 없으니 catkin_package를 비워 두었다.

이제 catkin_make 를 통해 빌드를 해보면 아래와 같은 에러가 나온다.

[ 83%] Building CXX object foo/CMakeFiles/foo.dir/src/foo.cpp.o
In file included from /home/kyuhwanyeon/personnel/cmake_tutorial/src/foo/include/foo.hpp:1:0,
                 from /home/kyuhwanyeon/personnel/cmake_tutorial/src/foo/src/foo.cpp:1:
/home/kyuhwanyeon/personnel/cmake_tutorial/src/bar/include/bar.hpp:1:10: fatal error: fred.hpp: No such file or directory
 #include "fred.hpp"
          ^~~~~~~~~~

foo package의 foo.cpp를 빌드를 하는 과정에서 bar.hpp를 불러오는데 여기서, fred.hpp를 찾을 수 없다고 나오는 것이다!

이유는 명확하다

foobar를 불러왔는데, export된 bar의 정보에는 fred의 dependency가 기입 되어 있지 않아서, foo를 빌드할 때는 이를 모른채로 빌드를 하기 때문에 위와 같은 에러가 나온 것이다.

그럼 해결 방법 또한 명확하다.

bar의 CMakeList.txt 에 CATKIN_DEPENDS fred 를 추가하는 것이다. 이를 통해, 다른 bar 를 이용하는 다른 패키지들은 “ barfred에 의존성이 있구나” 를 알 수가 있다.

따라서 bar의 CMakeList를 아래와 같이 수정해보자

cmake_minimum_required(VERSION 3.0.2)
project(bar)

find_package(catkin REQUIRED COMPONENTS
  fred
)

catkin_package(
 INCLUDE_DIRS include
 LIBRARIES bar
 CATKIN_DEPENDS fred
)

include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

add_library(${PROJECT_NAME}
  src/bar.cpp
)

target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})


CATKIN_DEPENDS fred 만 추가 된것이 다르다.

catkin_make 를 진행하면 정상 빌드가 된다 :)

[ 33%] Built target fred
[ 66%] Built target bar
[100%] Built target foo

Summary

  • catkin_package(DEPENDS ... CATKIN_DEPENDS ...) 는 현재 패키지의 의존성이 있는 패키지들의 목록을 export 하기 위해 사용된다. 즉 다른 패키지가 이러한 의존성 관계를 알 수 있게 하기 위함이다.