21.2.2. px4_add_module() 매크로의 내부 동작 메커니즘
앞선 Kconfig 단계가 ’이 모듈을 빌드할 자격이 있는가?’를 심사하는 서류 전형이었다면, 지금부터 다룰 CMake 시스템은 통과된 서류를 바탕으로 실제 C++ 소스 코드를 기계어(바이너리)로 번역하고 하나로 엮어내는(Linking) 공장 조립 라인이다.
이 거대한 PX4 조립 라인에서 여러분의 커스텀 앱 코드를 컨베이어 벨트에 안전하게 올려놓는 유일하고도 절대적인 주문(Spell)이 바로 px4_add_module() 매크로이다.
1. 일반적인 CMake와의 차이점
만약 일반적인 리눅스 환경에서 데스크톱용 C++ 프로그램을 만들었다면, 보통 CMakeLists.txt 파일 안에는 add_executable()이나 add_library() 같은 기본 CMake 명령어들이 등장했을 것이다. 하지만 PX4 소스 트리 내부에 위치한 여러분의 모듈 디렉터리(src/modules/custom_app/CMakeLists.txt) 안에서는 저런 원시적인 명령어를 절대 찾아볼 수 없다.
오직 **px4_add_module()**이라는, PX4 메인테이너들이 한 땀 한 땀 마개조하여 래핑(Wrapping)해 둔 강력한 자체 매크로 함수만이 사용된다.
2. px4_add_module()이 감추고 있는 막강한 백그라운드 작업들
여러분이 작성한 단 몇 줄의 px4_add_module(...) 코드가 컴파일러에게 파싱(Parsing)될 때, 보이지 않는 곳에서는 다음과 같은 수많은 중노동이 자동으로 처리된다.
- 플랫폼 분기(Platform Branching):
이 모듈이 Pixhawk(NuttX) 용으로 빌드되고 있는지, 아니면 시뮬레이터(SITL - Linux/macOS) 용으로 빌드되고 있는지 감지하여, 각 플랫폼에 맞는 크로스 컴파일러(Cross-compiler) 옵션과 타겟(Target) 바이너리 포맷을 스위칭해 준다. - 링커 테이블 장부 기록:
빌드된 객체 파일(.obj)을 단순히 흩어놓지 않고, 이를 모아 하나의 거대한 PX4 정적 라이브러리 아카이브(libcustom_app.a)로 묶어낸 뒤, 펌웨어 최상위 링커 테이블(Firmware Linker Table)에 이 모듈의 이름표를 강제로 박아 넣는다. (이 과정이 없으면 NSH 콘솔에서custom_app이라고 쳐도 “Command not found” 에러가 뜬다.) - 내부 의존성 사슬 자동 연결:
사용자가 일일이 인클루드 패스(include_directories)를 잡아주지 않아도, PX4의 코어 라이브러리 패스(Math, uORB, Param 시스템 등)를 이 모듈이 자동으로 참조할 수 있도록 보이지 않는 끈을 연결해 준다.
3. 전형적인 사용 예시
가장 표준적인 커스텀 앱의 CMakeLists.txt 내용은 다음과 같이 생겼다.
px4_add_module(
MODULE modules__custom_app
MAIN custom_app
STACK_MAIN 2000
PRIORITY SCHED_PRIORITY_DEFAULT
SRCS
custom_app.cpp
CustomApp.cpp
DEPENDS
uORB_msgs
)
겉보기에는 단순해 보이지만, 블록 안에 나열된 컴파일러 지시자(옵션 속성)들 하나하나가 모듈의 런타임 성능과 OS 스케줄링 운명을 결정짓는 치명적인 파라미터들이다.
- 이름을 왜 저렇게 언더스코어(
__)를 섞어 지어야 하는지, STACK_MAIN숫자는 어떻게 결정해야 기체가 추락하지 않는지,DEPENDS에 왜uORB_msgs를 적지 않으면 빌드 에러가 터지는지.
이 암호문과도 같은 속성 파라미터 블록들을 다음 단원들(21.2.2.1 하위 단원)에서 한 줄 한 줄 현미경으로 뜯어보고 컴파일러의 관점에서 그 의미를 해석해 볼 것이다.