21.2.1. PX4 Kconfig 트리(Tree) 구조 내 커스텀 모듈 주입
과거 PX4 펌웨어 빌드 시스템은 오로지 CMake에 의존하여 모든 것을 결정했다. 컴파일할 모듈의 목록은 boards/ 폴더 안의 텍스트 파일에 죽 나열되어 있었고, 이 파일들을 텍스트 에디터로 수정하다가 오타라도 하나 나면 빌드 전체가 엉망이 되곤 했다.
이러한 하드코딩(Hard-coding)의 폐해를 바로잡고 리눅스 커널 수준의 우아한 모듈 구성 관리를 도입하기 위해, PX4는 v1.11 릴리스를 기점으로 Kconfig 시스템을 전면 도입했다. Kconfig는 여러분의 커스텀 모듈이 펌웨어에 포함될 수 있는지, 포함되려면 어떤 전제 조건이 필요한지를 논리적으로 평가하는 ‘수문장(Gatekeeper)’ 역할을 한다.
1. Kconfig 시스템의 트리(Tree) 계층 구조
PX4 소스 코드를 다운로드받아 루트 디렉터리에서 make px4_fmu-vX_default boardconfig 명령어를 터미널에 입력하면, 푸른색 바탕의 깔끔한 텍스트 UI 메뉴가 팝업된다. 이 메뉴(GUI) 자체가 사실 소스 트리 전체에 흩어져 있는 수백 개의 Kconfig 파일들이 부모-자식 관계로 엮여 만들어진 거대한 ’트리 구조(Tree Structure)’이다.
PX4 최상단 루트에 위치한 Kconfig 파일은 src/drivers/Kconfig, src/modules/Kconfig, src/lib/Kconfig 등 하위 폴더에 존재하는 다른 Kconfig 파일들을 source 지시어를 통해 재귀적으로 빨아들인다(Include). 여러분이 src/modules/custom_app이라는 새 폴더를 만들고 그곳에 C++ 코드를 작성했다면, 이 코드가 컴파일러의 눈에 띄기 위한 첫 번째 단추는 바로 이 거대한 트리 어딘가에 **내 모듈 전용의 Kconfig 노드(Node)**를 접붙이는 일이다.
2. 모듈 주입의 메커니즘
여러분의 커스텀 모듈을 이 Kconfig 트리에 안전하게 주입하려면 다음의 두 가지 절차가 필요하다.
- 로컬
Kconfig파일 생성:
src/modules/custom_app/디렉터리 한구석에 덩그러니Kconfig라는 이름의 텍스트 파일을 하나 생성한다. 이 파일 안에는 내 모듈의 이름, 설명, 그리고 활성화(True/False) 스위치를 정의하는 문법이 들어간다. (상세 문법은 21.2.1.1 단원 참조) - 부모 트리에 링크 걸기:
로컬 파일만 달랑 만들어 둔다고 해결되지 않는다. 부모 디렉터리인src/modules/Kconfig(또는 여러분이 모듈을 위치시킨 상위 폴더의 Kconfig) 파일을 열고, 그 파일의 마지막 줄 즈음에source "src/modules/custom_app/Kconfig"라는 한 줄을 명시적으로 끼워 넣어주어야 한다.
이 두 가지 과정이 무사히 끝나면, PX4 빌드 도구를 실행할 때 Kconfig 파서(Parser)가 최상단 루트부터 가지를 치고 내려오다가 여러분이 적어 둔 source 지시어를 만나 custom_app의 존재를 비로소 인식하게 된다.
2.1 Kconfig 트리의 두 가지 목적
새롭게 편입된 로컬 Kconfig 파일은 단지 빌드 메뉴에 모듈 이름을 띄우는 장식용이 아니다. 빌드가 시작될 때 시스템은 Kconfig 설정 값들을 스윕하여 다음과 같은 두 가지 마법을 부린다.
- CMake 연결: 사용자가 Kconfig 메뉴에서 모듈을 체크박스(
[*])로 켜면, Kconfig 도구가 최종적으로<build_dir>/CMakeCache.txt파일에CONFIG_MODULES_CUSTOM_APP=y라는 CMake 변수를 주입하여 실제 C++ 컴파일 링킹 과정의 스위치를 올려준다. - C/C++ 매크로 생성: 동시에
build/<target>/NuttX/nuttx/config.h같은 C 헤더 파일에도#define CONFIG_MODULES_CUSTOM_APP 1매크로를 자동 생성해 준다. 만약 다른 모듈의 C++ 소스 코드에서 특정 구문을 이 커스텀 모듈이 켜졌을 때만 컴파일하고 싶다면#ifdef CONFIG_MODULES_CUSTOM_APP구문을 사용하여 조건부 컴파일(Conditional Compilation)을 수행할 수 있게 해준다.
그렇다면 구체적으로 이 로컬 Kconfig 파일 내부에 어떤 코드를 쳐넣어야 나만의 멋진 체크박스 메뉴를 만들고 시스템 버그를 유발하지 않는 논리적 의존성을 짤 수 있을까? 다음 21.2.1.1 단원에서는 이 Kconfig 언어의 구문론적 설계(Syntactical Design)를 파헤친다.