35.2.1.1. 크로스 플랫폼(Cross-platform) 빌드 도구(CMake)의 추상 구문 트리(AST) 분석 및 닌자(Ninja) 빌드 시스템 가속화

35.2.1.1. 크로스 플랫폼(Cross-platform) 빌드 도구(CMake)의 추상 구문 트리(AST) 분석 및 닌자(Ninja) 빌드 시스템 가속화

드론 관제 소프트웨어 생태계는 데스크톱 리눅스(Ubuntu)부터 자원 제약적 임베디드 보드(Raspberry Pi, Pixhawk)와 윈도우(Windows), 맥OS(macOS)까지 파편화된 다중 이기종 플랫폼(Heterogeneous Platforms)의 지원을 요구한다. 본 절에서는 이러한 거대한 파편화를 관통하여 MAVSDK 코어와 PX4 펌웨어를 일관되게 빌드해 내는 최신 CMake 시스템의 내부 컴파일러 원리인 추상 구문 트리(AST)를 분석하고, 기존 Make를 대치하여 도입된 Ninja 빌드 시스템의 속도 가속화 기법을 고찰한다.

1. 크로스 플랫폼 빌드를 위한 CMake 추상 구문 트리(AST) 분석

CMake 그 자체는 C++ 코드를 직접 컴파일하는 도구가 아니라, 타겟 플랫폼의 컴파일러(GCC, Clang, MSVC)에 맞춰 빌드 스크립트(Makefile이나 Ninja 파일)를 생성해 주는 ’메타 빌드 시스템(Meta-Build System)’이다.

개발자가 작성한 CMakeLists.txt에는 호스트 운영 체제의 경로 탐색이나 라이브러리 링크 속성들이 고도의 추상화된 스크립트 언어로 기술되어 있다.

  1. 파싱 및 AST 생성: CMake 엔진은 CMakeLists.txt 라인들을 스캐닝(Scanning)하여 자신만의 추상 구문 트리(Abstract Syntax Tree, AST)를 메모리 상에 구축한다. 이 AST 노드들에는 타겟(Target), 라이브러리 의존성(Dependencies), 컴파일 플래그(Compile Flags) 정보가 담긴다.
  2. 생성기(Generator) 계층: 완성된 AST를 바탕으로 CMake 내부의 생성기 계층이 동작한다. 이 때 타겟 환경이 리눅스라면 Makefile이나 build.ninja 구문으로, 윈도우라면 Visual Studio의 *.sln 프로젝트 구문으로 트리 구조를 번역해 버린다. 이를 통해 개발자는 윈도우용과 리눅스용 빌드 스크립트를 중복해서 작성할 필요가 사라지는 이점을 누린다.

2. 레거시 메이크(Make) 시스템의 한계와 병목

전통적으로 유닉스(Unix) 진영에서 사용해 온 GNU Make는 수천 개의 파일로 이루어진 거대한 MAVSDK C++ 코어 레포지토리를 빌드할 때 다음과 같은 아키텍처적 한계를 노출했다.

  • 동적 의존성 평가 지연: Make는 컴파일을 진행하는 런타임에 소스 파일(Dependency)이 수정되었는지를 재귀적(Recursive)으로 계속해서 판별한다. 시스템의 덩치가 커질수록, 실제로 수정된 파일이 1개뿐인데도 빌드 업데이트를 위해 파일의 타임스탬프 스캐닝을 하는 데만 수 초 이상의 이른바 “Null Build Time” 지연이 발생한다.
  • 병렬성(Parallelism) 부족: Make에도 -j 옵션을 통한 병렬 빌드 기능이 있으나, 하위 디렉토리(Sub-directory)가 깊어지는 구조에서는 의존성 순서가 보장되지 않아 병목 구간에서 CPU 코어 수(Core Count)를 온전히 끌어 쓰지 못하고 대기(Idle) 현상이 발생한다.

3. 닌자(Ninja)의 그래프 평탄화(Graph Flattening)와 동시성 가속화

이러한 Make의 약점을 극복하기 위해 크롬(Chrome) 브라우저를 빌드하던 개발자들이 창안한 도구가 바로 닌자(Ninja)이다. 그리고 PX4와 MAVSDK 프로젝트 역시 최근 빌드 가속화의 일환으로 기본 생성기(Default Generator)를 Ninja로 채택하였다.

  1. 정적 그래프(Static Graph) 평탄화: Ninja는 빌드 중간에 의존성을 능동적으로 연산하지 않는다. 사전에 CMake가 생성해 둔 거대한 정적 의존성 그래프(Static Dependency Graph) 명령어를 1차원 배열처럼 평탄화시킨 build.ninja 파일을 오로지 기계적으로만 읽어 들인다. 따라서 “무엇을 빌드할지 판단하는 시간(Null Build)“이 거의 0에 수렴한다.
  2. 극한의 병렬 스케줄링: Ninja의 스케줄러는 단순히 파일의 타임스탬프만 보고 의존성 트리의 최하단부터 사용 가능한 모든 논리 CPU 스레드를 극한(100% Load)까지 동원하여 분산 병렬 컴파일을 수행한다.
  3. 컴파일 오버헤드 \vert 3 \times \vert 이상의 단축: 실제로 C++ 템플릿 메타프로그래밍(TMP)이 난무하는 MAVSDK 코어 및 생성형 Protobuf 소스를 타겟 임베디드 보드 내에서 네이티브로 직접 컴파일할 때, Ninja는 기존 Make 대비 체감상 3배 이상 빠르고 쾌적한 빌드 완료율을 보장한다.

4. 결론

실시간 자율 비행 알고리즘을 현장(Field)에서 곧바로 수정하고 에지 컴퓨터 시스템에 투입(Deployment)해야 하는 긴박한 로보틱스 개발 환경에서 빌드 속도는 곧 개발 사이클(Iteration Cycle)의 생산성과 직결된다. CMake의 다중 이기종 추상화 체계(AST)와 Ninja의 기계적인 초고속 병렬 단일 스레딩 처리 메커니즘을 융합함으로써, MAVSDK 개발자들은 C++ 언어 고유의 컴파일 타임(Compile Time) 지옥을 탈출하여 신속한 프로토타이핑(Rapid Prototyping)과 실기체 적용 간격 극소화라는 혁신적인 이점을 확보하였다.