# 빈번한 빌드 오류와 패키지 충돌 처리

ROS2 Humble 환경에서 프로젝트를 빌드할 때 종종 예기치 못한 오류나 패키지 간 충돌로 인해 개발 속도가 느려지는 경우가 많다. 이러한 문제는 주로 의존성 패키지 누락, 서로 다른 버전의 라이브러리가 뒤섞인 환경, 잘못 설정된 빌드 옵션 등이 원인인 경우가 대부분이다. 빌드 오류와 패키지 충돌을 이해하고 사전에 방지할 수 있다면, 개발 과정에서 상당한 시간을 절약할 수 있다. 본 장에서는 이러한 빌드 오류와 충돌을 해결하기 위한 구체적인 방법과 사례를 다룬다.

#### 빌드 시스템(colcon) 개요와 주요 지점

ROS2에서 공식적으로 권장되는 빌드 시스템은 `colcon`이다. `catkin_make`나 `catkin_tools`를 사용하던 ROS1 시대와는 달리, ROS2는 `colcon build` 명령을 통해 패키지를 병렬로 빌드하고, 의존성을 자동으로 관리한다. 하지만 다음과 같은 상황들이 발생하면 각종 충돌 오류나 빌드 실패로 이어질 수 있다.

* 빌드 순서 혹은 환경 변수 설정 누락
* 패키지 버전 불일치에 따른 의존성 깨짐
* 호환되지 않는 C++ 표준(예: C++14, C++17) 혹은 파이썬 버전 혼재
* 임시로 생성된 캐시 파일(.cache, .install 등)의 잘못된 상태 유지

**colcon 빌드에서 필수적으로 확인해야 할 사항**

1. `colcon build`를 실행하기 전, `source /opt/ros/humble/setup.bash` 혹은 해당 워크스페이스 내 `install/setup.bash` 같은 환경 설정을 정확히 불러왔는지 확인한다.
2. `colcon list` 명령을 통해 ROS2 워크스페이스 내 패키지가 올바르게 인식되고 있는지 점검한다.
3. `colcon graph` 또는 `colcon info --packages-select <패키지명>`으로 패키지 간 의존성 관계를 시각화하거나 텍스트로 확인한다.

#### 빈번하게 발생하는 빌드 오류 사례

**1. 의존성 패키지 누락**

ROS2 패키지가 요구하는 의존 패키지가 설치되지 않았거나, 버전이 맞지 않아서 발생한다. 예를 들어 $rclcpp$ 패키지 버전이 낮거나, 특정 메시지 타입을 제공하는 패키지가 설치되지 않았다면 다음과 같은 오류 메시지를 볼 수 있다.

```
CMake Error at CMakeLists.txt:XX (find_package):
  Could not find a package configuration file provided by "rclcpp" ...
```

**해결 방법**

다음 명령으로 필요한 패키지를 설치한다.

```bash
sudo apt-get update
sudo apt-get install ros-humble-rclcpp
```

만약 메시지 타입 패키지가 누락된 것이라면, 예를 들어 `std_msgs` 가 없다면 다음과 같이 설치한다.

```bash
sudo apt-get install ros-humble-std-msgs
```

package.xml 이나 CMakeLists.txt 에서 해당 의존성을 빠뜨리지 않았는지 다시 확인하고, 아래와 같이 CMakeLists.txt 를 수정한다.

```cmake
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
...
add_executable(my_node src/my_node.cpp)
ament_target_dependencies(my_node rclcpp std_msgs)
```

**2. C++ 또는 파이썬 버전 충돌**

C++ 표준 버전을 의도적으로 $14$로 설정했는데, 빌드 환경에서 $17$ 이상을 필요로 하는 라이브러리를 함께 사용하면 심각한 컴파일 오류가 발생할 수 있다. 파이썬 역시 ROS2에서 사용하는 기본 버전(예: Python 3.8 이상)이 아닌 구버전이 환경에 설정되어 있을 경우 스크립트 호출 시 오류가 잦다.

**해결 방법**

CMakeLists.txt 내부에서 C++ 표준을 명시적으로 설정한다.

```cmake
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
```

시스템에 설치된 파이썬 버전을 확인한다.

```bash
python3 --version
```

ROS2 Humble이 사용하는 파이썬 버전이 3.8 이상인지 확인하고, 필요하다면 적절한 버전을 설치하고 가상환경(virtualenv) 등을 설정한다.

#### 패키지 간 충돌과 의존성 불일치 문제

**1. 중복 설치된 패키지**

ROS2 환경에서 동일한 이름의 패키지를 서로 다른 버전으로 설치하는 경우, 우선순위에 따라 한 쪽 패키지만 인식되거나 의도치 않은 버전의 패키지가 빌드에 사용될 수 있다. 예컨대 `$ament_cmake` 패키지가 기존 워크스페이스와 새 워크스페이스 둘 다에 설치되어 충돌을 일으키면 빌드 에러가 날 수 있다.

**해결 방법**

ROS2 시스템 패키지 설치 디렉터리(`/opt/ros/humble/`)와 개인 워크스페이스(`~/ros2_ws/`) 내 install 디렉터리에 중복된 패키지가 있는지 확인한다.

중복 충돌이 의심된다면, 새 워크스페이스에서 다음과 같이 `colcon`을 실행해본다.

```bash
colcon build --merge-install --packages-select <충돌 의심 패키지> --cmake-clean-cache
```

필요하다면, 시스템 전역 설치 버전을 제거하거나 워크스페이스 패키지 중 필요한 것만 분리하는 방안을 검토한다.

**2. 의존성이 꼬여 있는 경우**

어떤 패키지가 다른 패키지를 필요로 하고, 그 패키지가 다시 다른 패키지를 필요로 하는 식으로 복잡하게 얽혀 있을 때, 버전 불일치가 발생하면 빌드 오류가 발생한다. 예를 들어, A 패키지는 B 패키지 버전 1.0 이상을 요구하지만, B 패키지는 C 패키지와의 호환 문제로 인해 0.9 버전만 유지해야 하는 상황일 수 있다.

**해결 방법**

* `colcon graph` 혹은 `rqt_graph` 등의 기능을 통해 의존성 관계를 시각적으로 확인한다.
* 의존성이 충돌하는 지점을 파악한 뒤, 한쪽 패키지의 버전을 상향 혹은 하향 조정하여 일치시킨다.
* 해당 패키지의 Git 저장소에서 호환 버전을 확인하거나, ROS2 버전을 명시적으로 변경해 적용한다.

#### colcon clean과 캐시 삭제를 통한 문제 해결

빌드 오류나 패키지 충돌이 해결되지 않을 때, 가장 먼저 시도해볼 수 있는 방법 중 하나는 이전 빌드 캐시와 설치 파일을 깨끗이 정리한 뒤 다시 빌드하는 것이다. ROS2 Humble 환경에서 `colcon`을 사용할 때, 빌드 디렉터리(`build/`), 설치 디렉터리(`install/`), 로그 디렉터리(`log/`) 등은 패키지 간에 잘못된 참조가 생기면 문제가 발생하기 쉽다.

**1. 빌드 디렉터리와 설치 디렉터리 삭제**

워크스페이스 루트에서 다음과 같이 디렉터리를 제거한다.

```bash
rm -rf build/ install/ log/
```

필요하다면 다음과 같이 `--merge-install` 옵션이나

```
--cmake-clean-cache
```

옵션을 활용하여 빌드를 다시 시도한다.

```bash
colcon build --merge-install --cmake-clean-cache
```

**2. 특정 패키지만 청소 후 빌드**

여러 개의 패키지가 섞여 있어서 원인을 특정하기 어렵다면, 문제가 의심되는 패키지 하나만 선택해서 빌드해볼 수 있다.

```bash
colcon build --packages-select <문제 패키지> --cmake-clean-cache
```

이 명령으로 빌드가 정상 완료되면, 다른 패키지들과의 상호 작용 문제가 아니라 단독 패키지 내부 이슈일 가능성이 높다.

**3. colcon-clean 확장 도구**

별도의 확장 툴로 `colcon-clean`을 사용할 수 있다.

* 다음과 같이 설치한다.

  ```bash
  sudo apt-get install python3-colcon-clean
  ```
* 모든 빌드, 설치, 로그 디렉터리를 일괄 삭제하려면 다음과 같이 실행한다.

  ```bash
  colcon clean
  ```
* 특정 패키지만 청소하려면 다음과 같이 옵션을 활용한다.

  ```bash
  colcon clean --packages-select <패키지명>
  ```

#### 환경 변수 충돌과 잘못된 설정

ROS2 Humble에서 자주 사용되는 환경 변수로는 `CMAKE_PREFIX_PATH`, `LD_LIBRARY_PATH`, `PYTHONPATH` 등이 있다. 각종 라이브러리와 실행 파일, 파이썬 모듈이 어디서 로드되는지 결정하는 중요한 변수들이다. 이를 제대로 설정하지 않으면 빌드 중 의도하지 않은 경로의 라이브러리를 참조하거나, ROS2가 아닌 ROS1 패키지가 로드되어 혼선을 빚기도 한다.

**1. `CMAKE_PREFIX_PATH` 문제**

ROS2 패키지가 설치되어 있는 위치를 CMake가 찾지 못하면, 빌드가 불가능해진다. 예를 들어 `/opt/ros/humble/` 경로가 빠졌다면 `rclcpp` 등 주요 패키지를 전혀 찾지 못한다.

```bash
echo $CMAKE_PREFIX_PATH
# 출력 결과에 /opt/ros/humble/가 포함되어 있는지 확인
```

만약 누락되어 있다면 다음과 같이 수동으로 추가한 후 다시 빌드할 수 있다.

```bash
export CMAKE_PREFIX_PATH=/opt/ros/humble:$CMAKE_PREFIX_PATH
```

**2. `LD_LIBRARY_PATH` 문제**

C++로 작성된 노드를 실행할 때, 해당 노드가 동적으로 링크하는 라이브러리를 찾지 못하면 실행 중에 `Library not found` 또는 `symbol lookup error` 등이 발생한다.

* `$LD_LIBRARY_PATH`에 ROS2 라이브러리 디렉터리(`/opt/ros/humble/lib`)가 포함되어 있는지 점검한다.
* 필요하다면 다음과 같이 추가 설정한다.

  ```bash
  export LD_LIBRARY_PATH=/opt/ros/humble/lib:$LD_LIBRARY_PATH
  ```

**3. `PYTHONPATH` 문제**

파이썬 노드나 스크립트를 실행할 때, ROS2 파이썬 모듈을 찾지 못하면 `ModuleNotFoundError`가 발생한다.

* 다음 명령으로 환경 변수를 확인한다.

  ```bash
  echo $PYTHONPATH
  ```
* 설정이 누락되었다면 아래와 같이 추가한다.

  ```bash
  export PYTHONPATH=/opt/ros/humble/lib/python3.8/site-packages:$PYTHONPATH
  ```

  (파이썬 버전은 시스템 환경에 따라 다를 수 있다.)

***

#### 컴파일 옵션 불일치와 링크 에러

빌드 툴체인과 컴파일 옵션이 제각각인 상태로 ROS2 패키지를 빌드하면, 심각한 링크 에러가 발생할 수 있다. 예를 들어, 특정 라이브러리를 `$Debug` 모드로 빌드했는데, 프로젝트 전체는 `$Release` 모드로 링크하는 경우가 대표적이다.

**1. CMake build type 설정**

ROS2 Humble는 기본적으로 `$RelWithDebInfo`(Release + Debug 심볼) 모드를 사용하지만, 상황에 따라 `$Debug`, `$Release`, `$MinSizeRel` 등으로 변경할 수 있다.

프로젝트 전역 모드가 혼재된 상태라면, CMakeLists.txt 에서 명시적으로 통일시킨다.

```cmake
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
```

`colcon build` 실행 시 다음과 같이 모드를 지정할 수도 있다.

```bash
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Debug
```

**2. 링커 라이브러리 경로와 링크 순서**

CMake 설정에서 라이브러리 경로나 링크 순서가 틀어지면 컴파일 중에는 문제 없어 보이지만, 실행 시점이나 후속 빌드에서 문제가 발생한다.

* `target_link_libraries()`를 할 때, 반드시 필요한 라이브러리를 올바른 순서로 링크해야 한다.
* ROS2에서 제공되는 매크로 `ament_target_dependencies()`를 활용하면 의존성 있는 라이브러리를 자동으로 링크해주므로, 최대한 이를 활용한다.

#### 의존 패키지의 소스 변경으로 인한 재빌드 지연

ROS2를 활용해 다수의 패키지를 개발하다 보면, 어느 한쪽 패키지에서 header 파일을 수정했을 때 다른 패키지들이 전부 재빌드되는 문제가 종종 발생한다. 빌드 시간이 길어지면 개발 효율이 떨어지므로, 효율적인 관리가 필요하다.

**1. 자주 바뀌는 헤더 파일과 구현 분리**

* C++ 템플릿 클래스나 멤버 함수를 헤더 파일에 과도하게 정의하면, 작은 수정만 발생해도 의존 패키지들이 연쇄적으로 재빌드된다.
* 구현은 최대한 `.cpp` 소스에 분리하여 빌드 범위를 줄이는 것이 중요하다.

**2. 메시지 타입 변경 최소화**

* ROS2 메시지 타입을 자주 수정하면, 해당 메시지를 사용하는 모든 노드가 재빌드된다.
* 메시지 설계를 신중히 하고, 가능하면 공통 메시지를 미리 확정하여 변경 횟수를 최소화한다.

#### mermaid를 이용한 빌드 흐름 예시

아래는 `colcon build`의 빌드 흐름이 패키지 간 의존성 관계에 따라 어떤 식으로 이루어지는지 간략히 표현한 예시이다:

{% @mermaid/diagram content="graph LR
A\[패키지 A] --> B\[패키지 B]
B\[패키지 B] --> C\[패키지 C]
A\[패키지 A] --> D\[패키지 D]
C\[패키지 C] --> D\[패키지 D]
D\[패키지 D] --> E\[최종 실행 파일]" %}

* A 패키지를 먼저 빌드해야 B, D 패키지가 정상 빌드될 수 있고, B와 C가 모두 빌드된 이후 D가 빌드됨을 보여준다.
* 최종 실행 파일(E)은 모든 하위 패키지의 빌드가 완료되어야 링크가 가능하다.

#### 디버그 모드에서의 문제 파악

빌드 오류나 런타임 에러의 원인을 찾기 위해서는 디버그 모드(예: `$Debug`, `$RelWithDebInfo`)로 빌드한 뒤, GDB(또는 LLDB 등) 같은 디버거로 실행 과정을 추적하는 방식이 효과적이다. ROS2 노드는 여러 프로세스로 분할되어 작동하기 때문에, 노드 단위로 디버거를 붙여서 어떤 지점에서 에러가 발생하는지 관찰한다.

```bash
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Debug
```

이후 특정 노드를 디버거로 실행할 때는 다음과 같은 단계를 거친다.

실행하고자 하는 노드를 찾는다.

```bash
ros2 run <패키지명> <실행파일> --help
```

GDB를 통해 해당 실행 파일을 실행한다.

```bash
gdb --args ros2 run <패키지명> <실행파일> <추가 인자>
```

1. `run` 명령을 통해 프로그램을 실행하고, 필요하면 `break`, `step`, `next` 등의 명령으로 에러 발생 지점을 추적한다.

**공유 라이브러리(.so) 디버깅**

C++ 기반 ROS2 패키지의 경우, 공유 라이브러리(.so 파일)를 다른 노드가 동적으로 로드해 사용하는 형태가 많다. 이 경우에도 $LD\_LIBRARY\_PATH$가 올바르게 설정되어 있어야 GDB에서 심볼을 정확히 해석해낼 수 있다.

문제가 발생하는 노드 내부에서 어떤 라이브러리가 사용되는지

```
ldd
```

명령으로 확인해볼 수도 있다.

```bash
ldd /경로/실행파일
```

#### 빌드 로그 분석

`colcon build` 실행 시 생성되는 로그는 `log/` 디렉터리에 저장된다. 빌드 오류가 발생하면 로그를 면밀히 살펴, 어느 단계에서 에러가 났는지를 파악해야 한다.

1. 로그 디렉터리 구조 확인 빌드를 실행하면 패키지별로 로그 파일이 생성되며, 대체로 `log/latest_build/<패키지명>` 형태의 디렉터리에 `stdout.log`, `stderr.log` 등이 들어 있다.
2. CMake 단계 vs. 컴파일 단계 분류
   * CMake configure 단계에서 발생하는 오류는 `CMakeError.log`나 `CMakeOutput.log` 등을 보면 된다.
   * 컴파일 및 링크 단계에서 발생하는 오류는 `stderr.log`에 명시적으로 기록된다.
3. 의존 패키지 경고(`WARNING`) 확인
   * 간혹 오류로 이어지지 않은 경고 메시지가 후속 빌드에서 실제 오류를 유발할 수 있다.
   * 예: "Some includes cannot be found" 같은 경고를 그대로 두면, 후속 빌드에서 링크 에러나 심볼 누락 문제가 발생할 수 있다.

#### 빌드 문제를 재현하기 위한 최소 예제(Isolation)

여러 패키지가 얽힌 상황에서 문제가 발생하면, 원인을 명확히 재현하기 어려울 수 있다. 이럴 때는 “최소 예제”(Minimal Working Example)를 만들어 빌드 오류가 발생하는 상황을 단순화해서 확인한다.

새 워크스페이스 생성

```bash
mkdir -p ~/isolated_ws/src
cd ~/isolated_ws
```

문제가 발생하는 코드를 최소화하여 복사

* 빌드가 실패하는 핵심 패키지와 의존 패키지 일부만 `src/` 아래에 복사한다.

colcon build 실행

```bash
colcon build
```

이때 동일한 오류가 재현된다면, 그 코드 내에서 문제를 해결해볼 수 있다.

이 과정을 통해 복잡한 전체 프로젝트를 전부 빌드하지 않고도, 에러를 재현할 수 있는 소규모 환경에서 집중적으로 디버깅할 수 있다.
