28.2.2.2. CMakeLists.txt 파일 분석 및 조건부 컴파일(Conditional Compilation) 옵션
하드웨어 스펙이 스마트폰 급으로 남아도는 최신 Companion Computer(ex: Raspberry Pi) 타겟 환경과 달리, 정통 PX4의 주 무대인 Pixhawk V1 (STM32F427, 256KB RAM / 2MB Flash) 칩셋 환경은 소프트웨어 공학적으로 숨 막힐 듯이 가혹한 롬(ROM) 공간의 한계를 지닌다.
이를 극복하기 위해 src/modules/flight_mode_manager/CMakeLists.txt 빌드 스크립트는 단순한 소스 컴파일 묶음 명세서 기능을 넘어, 타겟 하드웨어 보드의 남은 플래시 메모리 용량에 맞춰 비행 모드 기능들을 수술용 메스처럼 정교하게 도려내고 덧붙이는 조건부 컴파일(Conditional Compilation) 아키텍처의 신경망 역할을 수행한다.
1. px4_add_module() 매크로의 FMM 코어 바인딩
CMakeLists.txt 파일을 열어보면 가장 상단에서 PX4 빌드 생태계의 알파이자 오메가인 px4_add_module 전역 헬퍼 매크로가 호출되어 flight_mode_manager 라는 굵직한 C++ 모듈 덩어리를 선언한다.
px4_add_module(
MODULE modules__flight_mode_manager
MAIN flight_mode_manager
STACK_MAIN 1200
COMPILE_FLAGS
-Wno-cast-align # 특정 컴파일러 경고 무시
SRCS
FlightModeManager.cpp
...
)
이 매크로 블록은 단순 컴파일 목록이 아니다. OS 커널이 런타임에 FMM 데몬 스레드에게 할당해 줄 **구체적인 스택(Stack) 메모리 윈도우 크기(STACK_MAIN 1200 Bytes)**를 CMake 레벨에서 박제해 버리는 무서운 튜닝 포인트다.
만약 향후 누군가 커스텀 비행 모드에서 깊고 거대한 지역 변수 행렬 매트릭스를 함수 내부에 float array[500] 식으로 무심코 선언한다면, 단돈 1.2KB로 타이트하게 컴파일러에 의해 세팅된 이 콜 스택 커널 윈도우 한계를 찢고 나오며, 데몬이 부팅되자마자 스택 오버플로우(Stack Overflow) 패닉으로 보드 전체가 새빨간 불빛과 함께 얼어붙는 하드 크래시를 유발하게 된다.
2. CMake 매크로를 이용한 C++ 정적 팩토리의 코드 자동 생성(Auto-Generation)
FMM 디렉터리 빌드 스크립트가 지닌 가장 찬란하고 흑마법적인 마술은 바로 수십 개의 FlightTask... 서브 자식 모듈 폴더들을 하나하나 찾아서 엮어주는 메타 프로그래밍 파이프라인에 있다.
set(flight_tasks_all
AutoLine
AutoMapper
Failsafe
ManualPosition
...
)
CMake 파일 내부에는 위와 같이 타겟 컴파일을 앞두고 빌드 명단 리스트(flight_tasks_all)가 스트링(String) 배열 형태로 정의되어 있다.
빌드가 시작되면, CMake는 단순히 이 폴더 안의 CPP 파일들을 오브젝트 파일로 컴파일하는 것에서 그치지 않고, 파이썬 기반의 진주 같은 스크립트인 generate_flight_tasks.py 툴체인을 셸(Shell) 백그라운드에서 은밀하게 서브 프로세스로 실행시켜버린다.
이 파이썬 스크립트는 flight_tasks_all 리스트에 적힌 텍스트 이름들을 파싱하여, 다음과 같은 C++ 실제 소스 코드 조각(FlightTasks_generated.cpp 및 .hpp)을 빌드 폴더 디렉터리에 아무도 모르게 기계적으로 타이핑해 임시 생성(Generate)해 낸다.
// 자동 생성된 C++ 팩토리 코드의 예시적 형태
#include <tasks/AutoLine/FlightTaskAutoLine.hpp>
#include <tasks/ManualPosition/FlightTaskManualPosition.hpp>
FlightTask* FlightModeManager::instantiateTask(uint8_t task_id) {
switch(task_id) {
case TASK_AUTO_LINE: return new FlightTaskAutoLine();
case TASK_MANUAL_POSITION: return new FlightTaskManualPosition();
...
default: return nullptr;
}
}
이러한 빌드 타임(Build-time) AST 리플렉션(Reflection) 모방 기법 덕분에, C++ 코드 개발자는 코어 엔진 소스를 더럽히며 하드코딩된 switch-case 구문을 일일이 수정하는 원시적인 노가다 악몽에서 평생 해방된다. 단순히 CMake 파일 텍스트 리스트에 폴더 이름(MyAwesomeTask) 한 줄만 추가하면, 기계가 알아서 C++ 객체 생성 로직을 꿰매어 링킹(Linking) 해주는 현대적인 플러그인 빌드 아키텍처가 눈앞에 펼쳐진다.
3. BOARD_FLASH_SIZE 기반의 잔혹한 생태계 최적화 가지치기 (Kconfig 연동)
Pixhawk FMU-v2 같은 1MB 급의 영세한 플래시 메모리를 가진 구형 보드를 타겟으로 .px4 펌웨어 바이너리 압축 파일을 구울 때는, 위에서 나열한 20여 개의 모든 자동 및 특수 비행 모드 기능들을 하나도 빠짐없이 빌드해 넣으려면 플래시 용량이 터져버리는 에러(Flash section overflow)에 직면한다.
이를 피하기 위해 CMake 빌드 시스템은 최상단의 보드별 환경 설정 파일(ex: boards/px4/fmu-v2/default.cmake 또는 최신 PX4의 Kconfig 인터페이스)에서 넘겨준 전역 플래그 변수인 메모리 사이즈 마진 스코프를 은밀하고 잔인하게 검열한다.
if(NOT BOARD_FLASH_SIZE LESS 2000)
# ROM 용량이 넉넉한 모던(2MB 이상) FC 보드일 경우에만 사치스럽게 추가되는 태스크들
list(APPEND flight_tasks_all
AutoFollowMe
Orbit
VtolTransition
...
)
endif()
위의 빌드 스크립트 로직처럼, 플래시 용량이 작은 구형 보드 타겟으로 컴파일을 명령하면 CMake는 피도 눈물도 없이 AutoFollowMe(나를 따라다니는 영상 촬영용 모드)나 복잡한 Orbit(원형 비행) 커스텀 수학 자식 객체들을 flight_tasks_all 빌드 포함 리스트에서 아예 잔인하게 가위로 잘라 탈락시켜 버린다.
결과적으로, 구형 하드웨어용 펌웨어를 빌드할 때는 C++ generate_flight_tasks.py 파이썬 생성 로직에서도 해당 모드들의 new 객체 팩토리 코드가 소스 단계에서부터 증발(Evaporate)해버리게 된다. 이는 Ardupilot 시절의 #ifdef 매크로 지옥 난도질 대잔치와는 비교도 안 될 정도로 우아하고 투명하며 유지 보수하기 쉬운 모듈식 펌웨어 다이어트 바이너리 빌드 파이프라인 아키텍처라고 할 수 있다.