# Dependency(의존성) 충돌 해결 방안

#### 패키지 의존관계 점검

ROS2 Humble 환경에서 발생하는 대표적인 문제 중 하나는 패키지 간 의존성 충돌이다. 패키지의 $package.xml$ 또는 `setup.py`에 명시된 의존 라이브러리 버전이 서로 호환되지 않으면 빌드 과정에서 에러가 발생하거나 런타임 환경에서 정상 동작이 불가능해진다. 의존관계를 점검하기 위해서는 다음과 같은 과정을 거치는 것이 일반적이다.

1. **의존성 확인**
   * `$colcon list --paths-only --base-paths src` 등을 통해 현재 작업공간(workspace)에 포함된 모든 패키지를 나열한다.
   * 각 패키지의 $package.xml$ 혹은 `setup.py` 등을 직접 열어 의존 항목을 확인한다.
2. **버전 호환성 확인**
   * 패키지가 요구하는 라이브러리나 ROS2 기능의 특정 버전을 확인한다.
   * 예를 들어, `rclcpp`가 `>=4.0.0` 버전을 요구하고, 다른 패키지는 `3.x.x` 버전을 요구한다면 충돌이 발생할 수 있다.
3. **중복 의존성 검사**
   * 여러 패키지가 같은 라이브러리를 사용하지만 버전이 서로 다른 경우가 많다.
   * 이런 상황에서는 package manager(예: apt) 레벨에서 의존성을 재검토해야 한다.

#### C++ 라이브러리 버전 충돌 사례

C++ 기반 패키지들은 대체로 CMake를 활용해 빌드가 이루어지므로, CMakeLists.txt 안에 종속된 라이브러리 버전이 제대로 표기되어 있어야 한다. 만약 다음과 같은 형태로 필요 라이브러리가 제대로 연결되지 않으면 에러가 발생한다.

```cmake
find_package(geometry_msgs REQUIRED)
find_package(tf2_ros 0.18.0 EXACT REQUIRED)
...
```

* **EXACT 옵션**: 특정 버전을 정확히 요구한다. 다른 버전이 깔려 있어도 빌드 오류가 날 수 있다.
* **REQUIRED 옵션**: 해당 패키지를 반드시 발견해야만 빌드가 진행된다.

C++ 라이브러리가 제공하는 API가 버전에 따라 다르게 구현되어 있으면, 빌드 타임뿐 아니라 런타임에서도 symbol lookup error와 같은 문제가 발생할 수 있다. 이때 다음과 같은 단계로 문제를 진단할 수 있다.

**공유 라이브러리 심볼 확인**

* `ldd <실행파일>` 명령어로 어떤 라이브러리가 어떤 경로에서 로드되는지 확인한다.
* 여러 경로에서 동일 라이브러리가 중복 로드되는 경우 충돌을 야기할 수 있다.

**패키지 매니저 동기화**

* Ubuntu나 Debian 계열에서는 다음 명령어로 의존 라이브러리를 최신 상태로 갱신한다.

```bash
sudo apt-get update
sudo apt-get upgrade
```

* ROS2 Humble에서 제공하는 공식 저장소(repo) 버전과 시스템 전역에 설치된 다른 repo 버전이 충돌할 수 있으므로, ROS2용 repo를 우선순위 높게 설정하거나 필요한 경우 PPA를 조정한다.

#### Python 라이브러리 버전 충돌 사례

ROS2 패키지 중 Python 기반 노드를 사용하는 경우, 시스템 전역 파이썬 환경과 가상환경(virtualenv) 또는 Conda 환경 사이에서 충돌이 발생하기도 한다. 가령 `numpy` 혹은 `torch` 같은 라이브러리가 특정 버전 이상을 필요로 하는데, 시스템 전역에 설치된 버전이 낮다면 런타임 시 ImportError가 발생하기 쉽다. 이와 같은 문제를 해결하기 위한 주요 방법은 다음과 같다.

**Python 환경 분리**:

* 작업공간마다 별도의 가상환경 또는 Conda 환경을 사용하여 의존성 충돌을 회피한다. 예시:

  ```bash
  python3 -m venv ~/ros2_humble_env
  source ~/ros2_humble_env/bin/activate
  ```
* 의존 라이브러리가 서로 다른 버전을 요구하는 경우, 하나의 환경에서 전부 충족시키기 어렵다면 여러 개의 가상환경을 만들어 관리한다.

**pip 패키지 버전 잠금(lock)**:

* `requirements.txt` 또는 `poetry.lock` 등을 활용해 패키지 버전을 명시적으로 고정한다.
* ROS2 빌드 시에도 `$colcon build` 전에 필요한 패키지를 `pip install -r requirements.txt` 형태로 동기화해둔다.

**중복 설치 확인**

* `pip show numpy` 등으로 실제 설치 경로를 확인하여, 의도치 않게 전역 환경과 가상환경에 동일 패키지가 서로 다른 버전으로 공존하고 있는지 확인한다.

#### 워크스페이스 관리 전략

ROS2 프로젝트를 여러 개 동시에 진행하거나, 다양한 버전의 종속성을 필요로 하는 경우에는 워크스페이스를 다단계로 구성하는 것이 중요하다. 예를 들어, `underlay_ws`, `overlay_ws` 식으로 여러 개의 작업공간을 정의하고, 상위 작업공간에 대한 종속성을 하위 작업공간이 상속하여 사용하도록 설계한다. 아래는 mermaid를 사용하여 단순화한 예시다.

{% @mermaid/diagram content="graph LR;
A\[Underlay Workspace] --> B\[Overlay Workspace];" %}

* **Underlay Workspace**: ROS2 Humble의 기본 구성 및 공통으로 사용하는 패키지들을 위치시킨다.
* **Overlay Workspace**: 프로젝트별 혹은 버전별 고유 패키지를 배치하여 별도로 빌드한다.
* 패키지 충돌이 발생하면 상위 작업공간과 하위 작업공간 사이의 버전을 재조정하거나, 의존성을 상위(Underlay)에서 제거하고 하위(Overlay)에서 재설치하는 방법도 고려한다.

#### 의존성 충돌 방지를 위한 팁과 주의사항

**ROS2 설치 경로 및 환경 변수 점검**

**ROS\_DISTRO 환경 변수**:

* ROS2 Humble이 설치된 환경에서는 `$echo$ROS_DISTRO` 명령어를 통해 현재 사용 중인 ROS 버전을 확인한다.
* 잘못된 버전(예: ros2-foxy 환경 설정 스크립트가 활성화)으로 인해 빌드 시 엉뚱한 버전의 라이브러리를 참조할 수 있으므로 주의한다.

**ROS\_PACKAGE\_PATH**:

* `$echo$ROS_PACKAGE_PATH`로 현재 ROS 패키지 검색 경로를 확인한다.
* 프로젝트에 사용하지 않는 경로가 들어 있다면 빌드가 혼선을 일으켜 충돌의 원인이 될 수 있다.
* 필요에 따라 `unset ROS_PACKAGE_PATH` 또는 `. /opt/ros/humble/setup.bash` 등으로 재설정한다.

**apt 혹은 다른 패키지 매니저와의 충돌**

**System-level 패키지와 ROS2 repo 버전 충돌**:

* 예를 들어, Ubuntu 22.04에서 기본적으로 설치되는 특정 라이브러리가 ROS2 Humble에서 요구하는 라이브러리 버전보다 낮거나 높을 수 있다.
* 이 경우 PPA를 추가하거나, ROS Official Repo를 최우선으로 설정하여 필요한 버전으로 업그레이드한다.

**colcon build 시 자동으로 잡히지 않는 의존성**:

* 일부 패키지는 $package.xml$에 기술되지 않은 의존성을 필요로 할 수 있다.
* `$sudo apt-get install libsomepackage-dev`와 같이 시스템 라이브러리를 직접 깔아야 하는지 미리 파악한다.

**Docker 환경을 활용한 버전 충돌 회피**

* 다양한 OS 및 ROS2 버전에서 개발 테스트를 진행해야 할 경우, Docker 이미지를 활용하여 충돌을 최소화할 수 있다.
* 예시:

```bash
docker pull ros:humble
docker run -it --name ros2_humble ros:humble /bin/bash
```

* 컨테이너 내부에서 빌드된 워크스페이스는 호스트 환경과 독립적이므로, 패키지 충돌 문제를 효율적으로 디버깅할 수 있다.

**소스 빌드(Source Build)와 설치형(apt) 혼용 시 주의**

* ROS2 Humble의 일부 패키지를 별도로 소스 빌드하여 사용하고, 나머지는 `apt`를 통해 설치된 환경을 사용할 경우, 설치 경로가 중복될 수 있다.
* `$colcon build` 후 생성되는 `install/` 디렉토리와 `/opt/ros/humble/` 디렉토리 중 어느 쪽의 라이브러리가 우선순위를 가질지 명확히 확인해야 한다.
* `$source install/setup.bash` 명령어를 통해 소스 빌드된 패키지를 사용 중이라면, 동일 이름의 패키지가 `/opt/ros/humble/` 디렉토리에 있는지 체크하고 불필요하다면 제거하거나 우선순위를 재조정한다.

#### rosdep 활용하기

의존성 관리는 소스 빌드 전후로 꾸준히 체크해야 하는데, ROS2 환경에서는 `rosdep`을 이용해 자동화할 수 있다.

설치 확인:

* 일반적으로 ROS2 설치 시 `rosdep`이 같이 설치되지만, 환경에 따라 누락될 수 있으므로 다음 명령어로 확인한다.

```bash
rosdep --version
```

의존성 설치:

* 작업공간의 `src/` 경로에 존재하는 모든 패키지의 시스템 레벨 의존성을 자동 설치하려면 다음과 같이 수행한다.

```bash
rosdep update
rosdep install --from-paths src --ignore-src -y
```

* 이때, package.xml에 제대로 기술되어 있지 않은 의존성은 자동 설치 목록에 누락된다.

#### 빌드 설정(CMake) 상세 점검

find\_package 설정 확인:

* `$find_package(some_library REQUIRED)`에서 `some_library` 패키지가 중복 설치되어 있거나 버전이 안 맞으면 문제가 발생한다.
* `$cmake --trace-expand` 옵션으로 CMake가 어떤 경로에서 패키지를 찾는지 추적해볼 수 있다.

```bash
cmake .. --trace-expand
```

CMake Policy 설정:

* CMake 버전 차이로 인해 policies가 다르게 적용될 경우, 경로가 뒤바뀌거나 링크 순서가 바뀔 수 있다.
* 패키지 내 `cmake_minimum_required(VERSION 3.x.x)` 구문에서 해당 버전에 알맞은 policy가 제대로 적용되는지 확인한다.

#### Advanced 디버깅 기법

의존성 충돌 문제는 단순 빌드 오류로만 나타나지 않고, 런타임 시점에 예기치 않은 에러를 일으킬 수도 있다. 아래는 자주 사용되는 디버깅 기법이다.

**Symbol Lookup Error 추적**:

* 실행 파일 또는 노드 실행 시 `$symbol lookup error: ... undefined symbol: ...$` 형태의 메시지가 뜨면, 특정 동적 라이브러리(so 파일)의 버전이 맞지 않아 심볼을 찾지 못했을 가능성이 크다.
* `$LD_LIBRARY_PATH` 환경 변수를 확인해 보고, 필요한 라이브러리의 실제 설치 경로와 버전을 비교한다.

**gdb를 통한 라이브러리 로딩 검사**:

* `$gdb --args ./my_ros2_node`로 디버거 환경에서 프로세스를 실행해볼 수 있다.
* 프로그램 시작 전(`start` 또는 `run` 명령 전)에 `$set environment LD_DEBUG=libs` 등을 주어서, 어떤 순서로 라이브러리가 로딩되는지 확인 가능하다.

**strace/ldd 사용**:

* `$ldd ./my_ros2_node`로 빌드된 바이너리가 참조하는 모든 동적 라이브러리를 목록화한다.
* `$strace -e open,openat ./my_ros2_node`로 라이브러리 파일 오픈 경로를 추적해, 중복 설치된 라이브러리와 충돌이 있는지 파악한다.

#### 라이브러리 다중 버전 공존 전략

**LD\_LIBRARY\_PATH 분리**:

* 서로 다른 버전의 라이브러리를 공존시켜야 한다면, 노드를 실행하기 전에 LD\_LIBRARY\_PATH를 명시적으로 분리해준다.

```bash
export LD_LIBRARY_PATH=/home/user/libs/version1:$LD_LIBRARY_PATH
ros2 run my_package my_node
```

* 이후 다른 노드를 실행할 때는 `/home/user/libs/version2` 디렉토리를 우선하도록 바꾸는 식으로 관리한다.

**Docker 이미지를 중첩해서 사용**:

* 특정 라이브러리 버전이 상이한 노드를 동시에 실행해야 할 경우, Docker 컨테이너를 여러 개 띄우고 각 컨테이너 내에서 필요한 라이브러리를 세팅할 수도 있다.
* 컨테이너 간 통신은 ROS2의 DDS(데이터 분배 서비스) 기능을 통해 네트워크로 연결하면 된다.

#### CI(Continuous Integration) 파이프라인에서의 의존성 검증

ROS2 프로젝트를 대규모로 운영하거나 여러 팀에서 협업하는 경우, 의존성 충돌이 발생하지 않도록 사전에 자동 점검을 도입하는 것이 효과적이다. 대표적인 방법은 다음과 같다.

**빌드 및 테스트 자동화**:

* GitHub Actions, GitLab CI 등 CI 환경에서 Docker 이미지를 기반으로 `$colcon build`와 `$colcon test`를 수행한다.
* 워크스페이스마다 필요한 시스템 의존성을 `$rosdep install --from-paths src --ignore-src -y`로 자동 설치하도록 설정한다.
* Python 의존성(예: `numpy`, `torch` 등)은 `$pip install -r requirements.txt` 등을 통해 설치 버전을 고정(lock)한다.

**빌드 매트릭스(Build Matrix)**:

* ROS2 버전별(Humble, Iron 등) 또는 OS별(Ubuntu 22.04, Debian 11 등)로 병렬 빌드를 실행해, 다양한 환경에서 동일 소스가 정상 빌드되는지 검증한다.
* 의존성 호환성이 의심되는 경우 특정 조합에서만 문제를 일으키는지 빠르게 확인 가능하다.

**테스트 커버리지 확장**:

* 단순히 빌드가 성공하는 것만으로는 런타임 의존성 충돌을 잡아내기 어렵다.
* `$colcon test --event-handlers console_direct+` 등을 통해 단위 테스트, 통합 테스트를 충분히 돌려야 런타임 충돌 사례까지 빠르게 잡아낼 수 있다.

#### 의존성 변화 추적(Dependency Tracking)

프로젝트 진행 중, 의존성 패키지의 버전이 상향(업데이트)되면 기존 코드와 호환성이 깨질 수 있다. 이를 예방하기 위해서는 버전 변경 사항을 추적하는 장치가 필요하다.

1. **package.xml 변경 이력 관리**
   * Git이나 SVN 같은 버전 관리 시스템을 통해 $package.xml$ 파일이 어떻게 바뀌었는지, 해당 시점에 빌드는 정상적이었는지 기록을 남긴다.
   * 필요 시 특정 태그(tag) 또는 커밋으로 돌아가서 빌드 환경을 재현해볼 수 있다.
2. **종속 패키지 릴리즈 노트 확인**
   * 외부 라이브러리나 ROS2 코어 패키지가 업데이트될 때, 릴리즈 노트를 확인하여 breaking change(하위 호환 불가 변경)가 있는지 미리 파악한다.
   * `rclcpp`, `nav2`, `gazebo_ros_pkgs` 등 주요 패키지의 GitHub 릴리즈 페이지나 ROS2 공식 문서를 주기적으로 모니터링한다.
3. **버전 핀(pin) 및 업데이트 주기 설정**
   * Python 패키지나 시스템 라이브러리에 대해서는, 프로젝트 내부적으로 “분기별 1회” 등 업데이트 주기를 정하여, 변경 폭을 한 번에 관리한다.
   * 예측 불가능한 시점에 의존성이 깨지는 문제를 방지하고, 테스트의 안정성을 높일 수 있다.

#### 운영 환경과 개발 환경의 동기화

로컬(개발 환경)에서는 빌드와 런타임이 정상인데, 실제 로봇이나 서버(운영 환경)에서 동작시 충돌이 발생하는 경우가 종종 있다. 이를 방지하기 위한 방법은 다음과 같다.

1. **Infrastructure as Code**
   * Dockerfile, Ansible, Terraform 등 자동화 도구를 사용해 운영 환경을 프로비저닝한다.
   * 로컬 환경과 최대한 유사한 환경(리눅스 버전, ROS2 버전, apt 패키지 버전 등)으로 구성해, 환경 차이로 인한 의존성 충돌을 최소화한다.
2. **환경 변수 정리**
   * `$RMW_IMPLEMENTATION`, `$ROS_DOMAIN_ID`, `$LD_LIBRARY_PATH` 등 ROS2 관련 환경 변수를 운영 환경에서도 동일하게 적용한다.
   * 노드 실행 스크립트에 환경 변수 설정을 명시해, 수동 설정 차이로 발생하는 오류를 방지한다.
3. **하드웨어 종속 라이브러리 점검**
   * GPU(예: CUDA 버전)나 센서 드라이버 의존성이 있는 경우, 개발 머신과 실제 로봇의 하드웨어 드라이버 버전이 달라서 충돌이 일어날 수 있다.
   * 이럴 때는 Docker 컨테이너 내부에 GPU나 센서 드라이버를 동일 버전으로 설치하여, 운영 환경을 에뮬레이션한다.
