9.2.1 `zenoh-c` 개발 환경 구축

9.2.1 zenoh-c 개발 환경 구축

C/C++ 생태계에서의 서드파티 라이브러리 연동 체계는 Node.js 생태계의 패키지 매니저 패러다임(npm)과 달리, 컴파일러(GCC/Clang) 및 링커(Linker)의 동작 원리를 기반으로 한 수동 의존성 주입이 요구된다. 헤더 파일(.h)의 참조 경로를 명시하고, 정적/동적 라이브러리(.a, .so) 링킹(Linking) 옵션을 주입하는 명시적인 빌드 스크립트 작성은 로버스트(Robust)한 시스템 구축의 선결 조건이다.

본 절에서는 자동화된 크로스 플랫폼 빌드 시스템의 표준인 CMake를 기반으로 zenoh-c 패키지를 타겟 로보틱스 제어 애플리케이션의 바이너리 및 런타임 환경에 물리적으로 이식(Transplantation)하기 위한 빌드 파이프라인(Build Pipeline) 전술을 기술한다.

1. CMake 및 다양한 빌드 시스템과의 연동

현대 C/C++ 시스템 프로그래밍 구역에서 소스 파일 간의 의존성(Dependency)을 단순 Makefile로만 관리하는 것은 대규모 분산 구조의 유지 보수성을 급감시킨다. 크로스 플랫폼 빌드 시스템의 표준인 CMake 환경 하에서 zenoh-c 패키지를 연동하는 정규 로직을 수립한다.

1.0.1 CMake 기반 Zenoh 결속 전술

zenoh-c의 컴파일된 릴리즈 파일(예: zenoh-c-0.10.x-linux-x86_64.zip)을 확보하여 프로젝트 작업 디렉터리 내 하위 참조 경로(libs/zenoh)에 배치하였다고 가정한다.

폴더 구조 명세

my_robot_project/
├── CMakeLists.txt
├── src/
│   └── main.c
└── libs/
    └── zenoh/
        ├── include/   (zenoh.h 위치)
        └── lib/       (libzenohc.so 혹은 libzenohc.a 위치)

CMakeLists.txt 작성 스키마

cmake_minimum_required(VERSION 3.10)
project(MyRobotComm C CXX)

set(CMAKE_C_STANDARD 99) # Zenoh-C 아키텍처는 C99 규격 이상을 요구함

# 1. 헤더 파일(include) 탐색 경로(Include Directories) 명시
include_directories(${CMAKE_SOURCE_DIR}/libs/zenoh/include)

# 2. 링커 경로(Link Directories) 지정
link_directories(${CMAKE_SOURCE_DIR}/libs/zenoh/lib)

# 3. 소스코드 컴파일 타겟 바이너리 선언
add_executable(robot_node src/main.c)

# 4. Zenoh 라이브러리(zenohc) 링킹
# 리눅스 커널 환경에서는 다중 스레드(pthread) 및 수학 라이브러리(m) 심볼이 요구될 수 있음
target_link_libraries(robot_node zenohc pthread m)

상기 CMake 명세는 make 툴체인이든, 병렬 빌드 시스템인 Ninja 툴체인이든 동일한 컴파일러 플래그 타겟(GCC/Clang)으로 파싱(Parsing)되며, 엔드포인트 단말기 실행 파일인 main.c에 선언된 #include <zenoh.h> 구문과 라이브러리의 물리적 심볼(Symbol) 맵을 런타임에 완벽히 바인딩(Binding)한다.

2. 소스코드 컴파일 및 정적/동적 라이브러리 링킹 기법

개발 호스트 머신(x86 PC 환경)에서 정상 동작이 검증된 C 바이너리 파일이, 실제 프로덕션 환경(Docker 컨테이너 혹은 에지 단말)으로 딥플로이(Deploy)된 시점에서 ./robot_node: error while loading shared libraries: libzenohc.so: cannot open shared object file와 같은 런타임 누락 예외를 표출할 수 있다. 이는 **동적 링킹(Dynamic Linking)**과 **정적 링킹(Static Linking)**의 구조적 차이에서 기인한다.

2.0.1 동적 라이브러리 링킹 (libzenohc.so / .dylib)

  • 빌드 지시어 타겟: target_link_libraries(robot_node zenohc)
  • 장점: 빌드 산출물인 실행 파일(.elf)의 사이즈 레이아웃이 매우 작게(수십 KB 단위) 유지된다. 시스템 내 다른 프로세스와 바이너리 영역을 공유하여 메모리 활용이 효율적이다.
  • 단점: 타겟 운영체제의 환경 변수 탐색 경로(/usr/lib 권역 혹은 LD_LIBRARY_PATH 지정 영역)에 반드시 libzenohc.so 라이브러리 파일이 컴파일 타임에 일치한 버전으로 배포 및 상주해 있어야만 프로세서 실행이 인가된다.

2.0.2 정적 라이브러리 링킹 (libzenohc.a)

  • 빌드 지시어 타겟:
    # 정적 아카이브 타겟을 명시하여 타겟 비즈니스 로직과 바이너리 차원에서 결합
    target_link_libraries(robot_node ${CMAKE_SOURCE_DIR}/libs/zenoh/lib/libzenohc.a)
    # (주의: 정적 링킹 방식은 POSIX 하위 종속성에 대한 명시적 링커 지정이 결여될 시 오류를 유발함. 
    # 예: Ubuntu 환경에서는 -lpthread, -ldl, -lm 옵션을 후위에 병기해야 함)
    
- **장점:** 컴파일과 링킹이 완료된 `robot_node` 단일 실행 파일 내부에 외부 종속 아티팩트가 모두 포함되어, 타겟 리눅스 환경에 배포 시 추가적인 환경 설정 없이 독자적인 구동(Stand-alone Execution)을 보장한다.
- **단점:** 실행 파일의 바이너리 용량이 현격히 증가(10MB 이상)하게 된다.

**[아키텍처 설계 지침]**
차량 내 제어 유닛(ECU)과 같은 고립성(Isolation)이 요구되는 단말 플랫폼 환경 파이프라인 배포 시, "공유 라이브러리 누락으로 인한 런타임 크래시 셧다운(Runtime Crash Shutdown)" 리스크를 원천 배제해야 한다. 이러한 제약 조건에서는 불가피하게 바이너리 용량의 오버헤드를 수용하더라도, **정적 링킹(Static Linking)** 기법을 채택하여 모놀리식(Monolithic) 실행 파일을 생성하는 방안이 권고된다.

## 3.  임베디드 리눅스 및 RTOS를 위한 교차 컴파일(Cross-compilation) 설정


개발 목적으로 활용되는 범용 워크스테이션 환경은 십중팔구 Intel 프로세서 구조(x86_64 아키텍처)에 종속된다. 반면, `zenoh-c` 통신 단말 시스템이 실체화되어야 하는 필드 운용 시스템은 Raspberry Pi(ARM64 아키텍처)나 NVIDIA Jetson 기기(AArch64 아키텍처) 등 철저히 독립된 프로세서 구조를 취한다. 호스트 환경의 기본 툴체인(`gcc`)으로 컴파일된 바이너리는 대상(Target) 기계명령어셋(Instruction Set)과의 불일치로 인하여 실행 체계가 붕괴된다. 목적 환경 구조에 맞는 바이너리를 호스트 시스템 선상에서 원격으로 렌더링 및 트랜슬레이션(Translation)하는 기술, 즉 **교차 컴파일(Cross-compile)** 파이프라인의 수립이 핵심 과제로 대두된다.

#### 3.0.1  ARM64 타겟 크로스 컴파일 파이프라인


**전제 조건:** AArch64 빌드 대상의 경우, 링크할 목적 패키지도 `zenoh-c-linux-aarch64` 버전의 공유/정적 라이브러리로 사전 준비되어야만 링커 충돌 예외를 피할 수 있다.

**리눅스 교차 툴체인(Cross-Toolchain) 설치 (Ubuntu 패키지 관리자 환경)**
```bash
# ARM64(AArch64) 대상 바이너리 코드를 방출하는 교차 컴파일러 설치
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

CMake 툴체인 지정 파일 명세 (arm64-toolchain.cmake)
CMake 프로세서가 호스트 운영체제의 로컬 gcc 대신 AArch64 목적 gcc 인터페이스를 사용하도록 타겟 프로파일링(Target Profiling)을 수행하는 명세 파일이다.

# 목적 운영체제와 머신 아키텍처를 시스템 속성으로 강제 주입
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

# 목적 운영체제를 위한 목적 교차 컴파일러 포인터 설정
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

# 호스트와 타겟 간의 루트 디렉터리 경로 혼선 충돌을 방어하는 옵션
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

빌드 트리거 선언
터미널 환경에서 CMake 툴체인 지시어 옵션을 삽입 인가하여 컴파일 파이프라인을 타격한다.

mkdir build_arm && cd build_arm
# 정의된 목적 툴체인 구성 명세 파일을 인자(Argument)로 교체 및 전달
cmake -DCMAKE_TOOLCHAIN_FILE=../arm64-toolchain.cmake ..
make

상기 파이프라인을 도출한 robot_node 목적물은 개발 워크스테이션 환경에서는 프로세스 단위로 인스트럭션을 판독할 수 없는 상태에 놓인다. SSH 파일 전송 프로토콜(scp) 등을 매개로 실제 런타임 타겟 기기(에지 노드)로 복사되어 런칭 루틴에 회부되는 시점에 비로소 에지 컴퓨팅(Edge Computing) 통신망의 정상 구동 사이클이 체결된다.

graph TD
    A[x86_64 Host PC] -->|1. Write C Code| B(Source Code)
    B -->|2. Use aarch64-gcc| C{Cross-compiler}
    D[ARM64 zenoh-c Library] --> C
    C -->|3. Output ARM64 Binary| E[robot_node_arm]
    E -.->|4. SCP Transfer| F[ARM64 Edge Device]
    F -->|5. Execution| G(Zenoh Network)