Buildroot 새 패키지 작성 — autotools·cmake·python 통합
#한 줄 요약
“빌드 시스템이 정해져 있으면 Buildroot 패키지는 한 페이지면 끝난다.” — autotools, cmake, python은 전용 infrastructure가 모든 세부를 처리해 줍니다.
Ch 5에서 generic-package로 무엇이든 빌드할 수 있는 골격을 봤습니다. 그러나 현실의 오픈소스 패키지는 99%가 autotools, cmake, python setuptools/pip 셋 중 하나입니다. 이걸 매번 CONFIGURE_CMDS·BUILD_CMDS·INSTALL_TARGET_CMDS로 적는 건 시간 낭비입니다.
이 장은 그래서 세 가지 infrastructure를 차례로 실제 예시와 함께 다룹니다. 각각의 최소 .mk가 어떻게 생겼는지, license와 hash는 어떻게 표기하는지, 의존성 선언은 어떻게 하는지, 그리고 디버깅 흐름은 어떻게 다른지.
#세 infrastructure 비교
| Infrastructure | 대상 | $(eval ...) |
|---|---|---|
autotools-package | ./configure && make && make install을 따르는 패키지 | $(eval $(autotools-package)) |
cmake-package | CMakeLists.txt 기반 패키지 | $(eval $(cmake-package)) |
python-package | setuptools/poetry/flit 기반 Python 패키지 | $(eval $(python-package)) |
세 infrastructure 모두 cross-compile 환경 변수 (CC, CXX, CFLAGS, sysroot)를 자동으로 주입합니다. 우리가 직접 적는 건 URL, 버전, 의존성, 라이선스만으로 충분합니다.
#사례 1: autotools-package — htop 추가하기
htop은 ncurses에 의존하는 대화형 프로세스 viewer입니다. autotools 기반이라 교과서적인 사례입니다. (실제 htop은 Buildroot 본체에 이미 있지만, 외부 트리에 내 fork를 두는 흐름을 가정합니다.)
#디렉터리
br2-acme/package/htop-acme/├── Config.in├── htop-acme.mk└── htop-acme.hash#Config.in
config BR2_PACKAGE_HTOP_ACME bool "htop-acme" depends on BR2_USE_WCHAR # ncurses-wchar 필요 depends on BR2_TOOLCHAIN_HAS_THREADS select BR2_PACKAGE_NCURSES select BR2_PACKAGE_NCURSES_WCHAR help ACME-customized htop, interactive process viewer. https://github.com/acme-corp/htop
comment "htop-acme needs a toolchain w/ wchar, threads" depends on !BR2_USE_WCHAR || !BR2_TOOLCHAIN_HAS_THREADSdepends on은 조건입니다. 충족되지 않으면 메뉴에 표시되지 않거나 comment로 안내됩니다. select는 암묵적 활성화입니다. htop을 켜면 ncurses도 자동으로 켜집니다.
#htop-acme.mk
################################################################################## htop-acme#################################################################################
HTOP_ACME_VERSION = 3.3.0HTOP_ACME_SOURCE = htop-$(HTOP_ACME_VERSION).tar.xzHTOP_ACME_SITE = https://github.com/htop-dev/htop/releases/download/$(HTOP_ACME_VERSION)HTOP_ACME_LICENSE = GPL-2.0+HTOP_ACME_LICENSE_FILES = COPYING
HTOP_ACME_DEPENDENCIES = ncurses
HTOP_ACME_CONF_OPTS = \ --disable-unicode=no \ --enable-affinity \ --disable-hwloc
ifeq ($(BR2_PACKAGE_LIBCAP),y)HTOP_ACME_CONF_OPTS += --enable-capabilitiesHTOP_ACME_DEPENDENCIES += libcapelseHTOP_ACME_CONF_OPTS += --disable-capabilitiesendif
$(eval $(autotools-package))autotools-package 매크로는 다음을 자동으로 처리합니다.
./configure --host=$(GNU_TARGET_NAME) --prefix=/usr ...CC=$(TARGET_CC) CFLAGS="$(TARGET_CFLAGS)"make -C $(@D)make -C $(@D) DESTDIR=$(TARGET_DIR) install
추가 옵션은 _CONF_OPTS에 적습니다. 의존성에 따라 옵션을 조건부로 바꾸려면 ifeq를 씁니다.
#htop-acme.hash
# Locally computedsha256 ad12345fc... htop-3.3.0.tar.xzsha256 cf2b... COPYINGCOPYING 파일까지 해시를 적는 이유는 라이선스 파일이 바뀌면 알아야 하기 때문입니다. 라이선스 변경은 재배포 영향이 있어 무시할 수 없습니다.
해시는 sha256sum 결과를 그대로 적습니다.
$ sha256sum htop-3.3.0.tar.xz COPYINGad12345fc... htop-3.3.0.tar.xzcf2b... COPYING#Config.in 등록
외부 트리 최상위 Config.in에 추가합니다.
source "$BR2_EXTERNAL_ACME_PATH/package/htop-acme/Config.in"make menuconfig에서 활성화한 뒤:
$ make htop-acme-source # tarball 다운로드 + hash 검증$ make htop-acme # configure + build + install$ make htop-acme-show-info # 메타데이터 출력빌드가 성공하면 output/target/usr/bin/htop이 생깁니다.
#사례 2: cmake-package — libfoo 같은 라이브러리
CMake 기반 패키지를 추가하는 흐름입니다. 예시로 가상의 acme-sensorlib를 듭니다.
#Config.in
config BR2_PACKAGE_ACME_SENSORLIB bool "acme-sensorlib" depends on BR2_INSTALL_LIBSTDCPP # C++ 사용 select BR2_PACKAGE_NLOHMANN_JSON help ACME sensor abstraction library. Supports I2C and SPI sensors with a common API.
comment "acme-sensorlib needs a toolchain w/ C++" depends on !BR2_INSTALL_LIBSTDCPP#acme-sensorlib.mk
################################################################################## acme-sensorlib#################################################################################
ACME_SENSORLIB_VERSION = 2.4.1ACME_SENSORLIB_SITE = $(call github,acme-corp,sensorlib,v$(ACME_SENSORLIB_VERSION))ACME_SENSORLIB_LICENSE = Apache-2.0ACME_SENSORLIB_LICENSE_FILES = LICENSEACME_SENSORLIB_INSTALL_STAGING = YES
ACME_SENSORLIB_DEPENDENCIES = nlohmann-json
ACME_SENSORLIB_CONF_OPTS = \ -DBUILD_TESTING=OFF \ -DBUILD_EXAMPLES=OFF \ -DACME_SENSOR_I2C=ON \ -DACME_SENSOR_SPI=ON
ifeq ($(BR2_PACKAGE_ACME_SENSORLIB_SHARED),y)ACME_SENSORLIB_CONF_OPTS += -DBUILD_SHARED_LIBS=ONelseACME_SENSORLIB_CONF_OPTS += -DBUILD_SHARED_LIBS=OFFendif
$(eval $(cmake-package))핵심 차이입니다.
cmake-package는cmake -DCMAKE_TOOLCHAIN_FILE=...을 자동으로 호출합니다. cross-compile toolchain 파일을 Buildroot가 생성해 줍니다.- 사용자는
_CONF_OPTS에 CMake 변수만 적습니다 (-D...). _INSTALL_STAGING = YES로 두면STAGING_DIR에도 install합니다. 라이브러리는 다른 패키지가 빌드 시점에 헤더·.so를 참조해야 하므로 거의 항상 staging이 필요합니다.
#Hash와 GitHub source
github 헬퍼는 https://github.com/<user>/<repo>/archive/<ref>.tar.gz를 자동으로 만들어 줍니다.
ACME_SENSORLIB_SITE = $(call github,acme-corp,sensorlib,v$(ACME_SENSORLIB_VERSION))위와 같이 쓰면 Buildroot가 tarball 파일명을 안정적으로 acme-sensorlib-2.4.1.tar.gz로 만듭니다. GitHub의 raw archive 파일명은 git ref가 들어가 해시 일치가 깨질 수 있어 헬퍼를 거치는 것이 안전합니다.
hash 파일:
# Locally computed (post download)sha256 e3b0... acme-sensorlib-2.4.1.tar.gzsha256 c712... LICENSE#Shared vs static option
Config.in에 옵션을 추가해 boolean으로 노출할 수 있습니다.
config BR2_PACKAGE_ACME_SENSORLIB_SHARED bool "build as shared library" depends on BR2_PACKAGE_ACME_SENSORLIB default y.mk의 ifeq가 이를 받습니다. 이 패턴은 Config.in 옵션이 .mk의 CMake 인자로 변환되는 표준 흐름입니다.
#사례 3: python-package — pyserial 같은 패키지
Python 패키지는 별도 infrastructure를 씁니다. setup.py, pyproject.toml, poetry 모두 자동 감지합니다.
#Config.in
config BR2_PACKAGE_PYTHON_ACME_TOOLS bool "python-acme-tools" depends on BR2_PACKAGE_PYTHON3 select BR2_PACKAGE_PYTHON_PYSERIAL help ACME device management CLI for Python 3. https://pypi.org/project/acme-toolsdepends on BR2_PACKAGE_PYTHON3은 반드시 적습니다. Python 인터프리터가 없으면 의미가 없습니다.
#python-acme-tools.mk
################################################################################## python-acme-tools#################################################################################
PYTHON_ACME_TOOLS_VERSION = 0.5.2PYTHON_ACME_TOOLS_SOURCE = acme_tools-$(PYTHON_ACME_TOOLS_VERSION).tar.gzPYTHON_ACME_TOOLS_SITE = https://files.pythonhosted.org/packages/source/a/acme_toolsPYTHON_ACME_TOOLS_LICENSE = MITPYTHON_ACME_TOOLS_LICENSE_FILES = LICENSE.txtPYTHON_ACME_TOOLS_SETUP_TYPE = setuptoolsPYTHON_ACME_TOOLS_DEPENDENCIES = python-pyserial
$(eval $(python-package))핵심은 PYTHON_ACME_TOOLS_SETUP_TYPE입니다. 가능한 값:
| 값 | 의미 |
|---|---|
distutils | 옛 setup.py |
setuptools | 가장 흔함 |
pep517 | pyproject.toml 기반 (poetry, flit, hatch 등) |
flit | flit 특화 |
#PyPI에서 source 찾기
PyPI 패키지의 source tarball은 다음 패턴입니다.
https://files.pythonhosted.org/packages/source/<첫글자>/<패키지명>/<파일명>예: acme_tools-0.5.2.tar.gz → https://files.pythonhosted.org/packages/source/a/acme_tools/acme_tools-0.5.2.tar.gz.
Buildroot 본체에 이미 있는 Python 패키지(package/python-pyserial/)를 참고하면 패턴이 명확합니다.
#Host vs target Python
Python 패키지는 host에만 설치해야 할 때(빌드 도구)와 target에만, 둘 다 세 가지 모드가 있습니다. 기본은 target입니다.
# target only (default)$(eval $(python-package))
# host only — 빌드 도구$(eval $(host-python-package))
# host + target$(eval $(python-package))$(eval $(host-python-package))setuptools도 host 빌드가 필요하니, host-python-acme-tools를 동시에 정의하는 사례가 종종 있습니다.
#의존성 선언 정확하게
세 infrastructure 모두 <NAME>_DEPENDENCIES 변수를 같은 방식으로 사용합니다.
HTOP_ACME_DEPENDENCIES = ncurses libcap여기서 반드시 알아야 할 것은 세 종류의 의존성입니다.
| 종류 | 변수 | 의미 |
|---|---|---|
| Build-time | <NAME>_DEPENDENCIES | 이 패키지를 빌드하기 전에 빌드돼 있어야 함 |
| Runtime (Kconfig) | select BR2_PACKAGE_<DEP> | rootfs에 포함되어야 함 |
| Toolchain | depends on BR2_TOOLCHAIN_HAS_THREADS 등 | 컴파일러·libc의 기능 요구 |
세 가지를 혼동하면 menuconfig에서는 켜졌는데 빌드는 실패하는 상태가 나옵니다. 권장 규칙:
- 라이브러리 의존(
-lncurses)이면_DEPENDENCIES에 반드시 적습니다. - runtime에 실행되는 패키지(예: 스크립트가
bash를 호출)면Config.in에서select로 활성화합니다. - C++·threads·wchar 등 toolchain 기능은
Config.in의depends on으로 표현합니다.
#Patch 적용
upstream tarball에 수정이 필요하면 패키지 디렉터리에 *.patch 파일을 둡니다.
br2-acme/package/htop-acme/├── Config.in├── htop-acme.mk├── htop-acme.hash├── 0001-fix-musl-build.patch└── 0002-add-acme-column.patch이름은 번호 prefix + 짧은 설명이 관례입니다. Buildroot가 알파벳 순으로 자동 적용합니다.
$ make htop-acme-rebuild>>> htop-acme 3.3.0 Patchingapplying patch file 0001-fix-musl-build.patchpatching file Makefile.inapplying patch file 0002-add-acme-column.patchpatching file CRT.cseries 파일(quilt 형식)도 지원합니다. 패치 순서를 명시적으로 통제하려면 series 파일을 두고 거기 한 줄씩 적습니다.
#디버깅 흐름 — *-rebuild의 활용
새 패키지를 작성하는 동안 반복 수정이 잦습니다. 다음 타겟이 핵심입니다.
| 타겟 | 효과 |
|---|---|
<name>-source | tarball만 다운로드 + hash 검증 |
<name>-extract | + 압축 해제 + patch 적용 |
<name>-configure | + configure/cmake 실행 |
<name>-build | + 실제 컴파일 |
<name>-install | + target/staging install |
<name> | 위 전체 |
<name>-rebuild | extract 이후를 처음부터 다시 |
<name>-reconfigure | configure 이후를 다시 |
<name>-dirclean | build 디렉터리 완전 삭제 |
<name>-show-info | 메타데이터 JSON 출력 |
<name>-show-depends | 직접 의존성만 출력 |
전형적 디버깅 흐름입니다.
$ make htop-acme # 첫 시도, 실패... error: undefined reference to `cap_get_proc'
# .mk 수정: HTOP_ACME_DEPENDENCIES += libcap 추가$ make htop-acme-rebuild # 의존성 해결 후 다시... still fails
# configure 옵션 확인$ ls output/build/htop-acme-3.3.0/config.log$ less output/build/htop-acme-3.3.0/config.log
# .mk 다시 수정$ make htop-acme-reconfigure # configure만 다시-rebuild는 extract부터 다시 합니다. patch가 늘었거나 시리즈 변경이 있을 때 씁니다. -reconfigure는 configure부터 다시. 옵션만 바꿀 때 충분합니다.
#License 표기
<NAME>_LICENSE와 <NAME>_LICENSE_FILES는 형식이 정해져 있습니다. SPDX identifier를 씁니다.
ACME_SENSORLIB_LICENSE = Apache-2.0ACME_SENSORLIB_LICENSE_FILES = LICENSE복합 라이선스도 SPDX 표현으로 적습니다.
HTOP_ACME_LICENSE = GPL-2.0+SOMETHING_LICENSE = MIT or GPL-2.0+ANOTHER_LICENSE = (GPL-2.0+ and LGPL-2.1+)이 정보는 make legal-info가 프로젝트 전체의 라이선스 보고서를 만들 때 사용됩니다. 임베디드 제품의 오픈소스 컴플라이언스에 필수입니다.
$ make legal-info$ ls output/legal-info/host-manifest.csv manifest.csv README sources/manifest.csv에 모든 패키지의 버전·라이선스·source URL·tarball 파일명이 정리됩니다. 그대로 컴플라이언스 문서로 쓸 수 있습니다.
#Troubleshooting
#”Wrong hash” 에러
해시가 안 맞으면 빌드가 멈춥니다.
>>> htop-acme 3.3.0 Downloading...ERROR: htop-3.3.0.tar.xz has wrong sha256 hashexpected: ad12345...got: ef67890...원인은 tarball이 변경됐거나 (GitHub auto-generated archive는 git 변경에 따라 해시가 바뀝니다), 내가 hash 파일을 잘못 적었거나. 후자라면 dl/에 받힌 파일에서 해시를 다시 계산합니다.
$ sha256sum dl/htop-acme/htop-3.3.0.tar.xz#”No package ‘ncurses’ found” pkg-config 에러
_DEPENDENCIES에 ncurses를 안 적은 경우입니다. 또는 ncurses가 host에만 빌드되고 staging에 install 안 된 경우. ncurses는 staging에 install되므로 의존성만 추가하면 보통 해결됩니다.
#Python 패키지가 import는 되는데 실행이 안 된다
_DEPENDENCIES에 런타임 의존성이 빠진 경우입니다. pyserial을 import하지만 select만 하고 _DEPENDENCIES에 적지 않으면 menuconfig에선 켜져도 install order가 꼬일 수 있습니다. 둘 다 적는 게 안전합니다.
#CMake가 host의 라이브러리를 잡는다
cross-compile toolchain 파일이 잘 적용되지 않은 경우입니다. cmake-package가 자동으로 처리하지만, CMakeLists.txt가 find_package로 불완전하게 검색하면 host 헤더를 잡을 수 있습니다. -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY를 _CONF_OPTS에 추가하면 강제됩니다.
#autoreconf가 필요하다고 한다
upstream patch가 configure.ac를 건드리면 autoreconf가 필요합니다.
HTOP_ACME_AUTORECONF = YES_AUTORECONF = YES를 추가하면 Buildroot가 빌드 전에 autoreconf -fi를 자동으로 호출합니다.
#정리
autotools-package,cmake-package,python-package는 cross-compile 환경 변수를 자동 주입합니다.- 사용자는 URL, 버전, 의존성, 라이선스, hash만 적으면 됩니다.
_DEPENDENCIES(build-time),select(runtime presence),depends on(toolchain capability) — 세 의존성을 구분해 표현합니다.- 라이브러리 패키지는
_INSTALL_STAGING = YES로 staging에도 install합니다. - License는 SPDX identifier.
make legal-info가 컴플라이언스 보고서를 생성합니다. - Patch는
*.patch파일을 패키지 디렉터리에 두면 자동 적용됩니다. - 디버깅은
-rebuild,-reconfigure,-dirclean을 적절히 골라 씁니다. - Python 패키지는
_SETUP_TYPE을 정확히 적어야 합니다(setuptools,pep517등).
#다음 장 예고
다음 편은 Ch 10: 실전 — BeagleBone Black 시스템 처음부터 끝까지.
#관련 항목
Buildroot Practical · 9 of 20
- 1Buildroot가 푸는 문제 — Yocto와의 핵심 차이 분석
- 2Buildroot 디렉터리 구조 분해 — board·configs·dl·output
- 3Buildroot Kconfig 설정 — menuconfig와 defconfig 작성
- 4Buildroot 첫 빌드 — QEMU에서 동작하는 시스템 만들기
- 5Buildroot 패키지 시스템 분석 — .mk와 Config.in 동작 추적
- 6Buildroot 외부 트리 — BR2_EXTERNAL 구성과 활용
- 7Buildroot 보드 Customize — overlay·post-build·post-image 흐름
- 8Buildroot 출력 파일시스템 — initramfs·squashfs·ext4·cpio 선택
- 9Buildroot 새 패키지 작성 — autotools·cmake·python 통합
- 10Buildroot 실전 — BeagleBone Black 시스템 처음부터 끝까지
- 11Buildroot Toolchain 선택 — Internal vs External 비교
- 12Buildroot 커널 Customize — defconfig fragment와 DTS 통합
- 13Buildroot U-Boot 통합 — 빌드·env·fw_env 흐름
- 14Buildroot 빌드 캐싱 분석 — dl·ccache·per-package
- 15Buildroot post-build·post-image 심화 — rootfs 최종 수정 흐름
- 16Buildroot OTA 이미지 업데이트 — RAUC·swupdate 통합
- 17Buildroot SDK 생성·배포 — make sdk와 application 워크플로
- 18Buildroot Security·CVE 추적 — pkg-stats와 Reproducible Builds
- 19Buildroot CI/CD 구축 — Container Build와 Cache 공유
- 20Buildroot → Yocto 마이그레이션 — 언제·어떻게 옮길까
관련 글
Buildroot 패키지 시스템 분석 — .mk와 Config.in 동작 추적
Buildroot 패키지 작성 규약 — Config.in 옵션 노출과 .mk 빌드 레시피.
Buildroot → Yocto 마이그레이션 — 언제·어떻게 옮길까
Buildroot가 한계에 도달하는 신호와 Yocto/OE로 점진 이전하는 패턴, meta-buildroot 같은 hybrid 옵션.
Buildroot CI/CD 구축 — Container Build와 Cache 공유
GitLab/GitHub Actions에서 Buildroot 트리를 컨테이너로 빌드하고 dl·ccache를 팀이 공유하는 패턴.