이 글은 Ubuntu 환경에서 Clang/LLVM 툴체인을 이용해 Linux 커널을 실제로 빌드하는 방법을 단계별로 정리한다.
Clang/LLVM 툴체인 설치는 아래 글을 먼저 확인한다.
Ubuntu 커널 빌드에 대한 건 아래 글을 참고한다.
전체 빌드 흐름 한눈에 보기

커널 소스
|
.config 생성 (defconfig / menuconfig)
|
make LLVM=1
|
clang -> LLVM IR -> ld.lld
|
vmlinux / Image / modules
핵심은 LLVM=1 하나로 컴파일러, 링커, binutils 계열을 모두 LLVM 쪽으로 전환한다는 점이다.
커널 소스 준비
소스 받기
준비된 커널 소스가 없다면 아래처럼 받는다.
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
실무에서는 다음 중 하나를 써도 무방하다.
- LTS 커널
- 배포판 커널 소스
- SoC 벤더 커널 트리
빌드 방법 자체는 동일하다.
Out-of-tree 빌드 디렉터리 구성
커널 빌드는 산출물이 많기 때문에 O= 옵션을 쓰는 것이 정석이다.
mkdir -p out
이후 모든 make 명령에 O=out을 붙인다.
x86_64 (native) Clang/LLVM 커널 빌드
기본 config 생성
make O=out defconfig
이 단계에서 .config가 생성된다. 필자의 경우는 기존에 빌드해 둔 소스가 있어서 mrproper 후 진행했다.
$ make mrproper
$ make O=out defconfig
Clang/LLVM 빌드 실행
make O=out LLVM=1 -j$(nproc)
이 한 줄이 의미하는 바는 다음과 같다.
| 항목 | 의미 |
|---|---|
LLVM=1 | clang + ld.lld + llvm-binutils 사용 |
-j$(nproc) | 병렬 빌드 |
중간에 LTO, CFI 등 config 선택이 나오면 여기서는 Enter로 넘어간다.
컴파일하다 보면 GCC로 빌드할 때와 달리 아래처럼 error가 발생하는 경우가 있다. Clang이 기존 GCC에서는 warning으로 넘어가던 것들을 더 엄격한 기준으로 error 처리하기 때문이다.
../net/netfilter/nf_conntrack_netlink.c:677:41: error: variable 'len' is uninitialized when used here [-Werror,-Wuninitialized]
677 | + nla_total_size(sizeof(char) * len); /* CTA_SECCTX_NAME */
| ^~~
../net/netfilter/nf_conntrack_netlink.c:670:9: note: initialize the variable 'len' to silence this warning
670 | int len, ret;
| ^
| = 0
1 error generated.
make[5]: *** [../scripts/Makefile.build:243: net/netfilter/nf_conntrack_netlink.o] Error 1
make[4]: *** [../scripts/Makefile.build:481: net/netfilter] Error 2
make[4]: *** Waiting for unfinished jobs....
...
이 에러는 len이 초기화 없이 사용된 경우로, 컴파일러가 len = 0으로 초기화할 것을 제안하고 있다. 이런 식으로 발생하는 error를 하나씩 확인하고 수정해서 컴파일이 끝까지 완료되도록 한다.
arm64 크로스 컴파일 (Clang/LLVM)
arm64에서는 ARCH 지정이 필수다.
arm64 defconfig 설정
make O=out ARCH=arm64 defconfig
Clang + GNU cross 혼합 빌드 (가장 흔한 패턴)
make O=out ARCH=arm64 LLVM=1 \
CROSS_COMPILE=aarch64-linux-gnu- \
-j$(nproc)
이 조합의 의미는 다음과 같다.
- 컴파일러/링커: Clang + LLD
- 일부 도구/asm fallback: GNU binutils
실무에서 가장 안정적인 조합이다.
Integrated Assembler 문제 발생 시
특정 .S 파일에서 에러가 나면 통합 어셈블러를 끈다.
make O=out ARCH=arm64 LLVM=1 LLVM_IAS=0 \
CROSS_COMPILE=aarch64-linux-gnu- \
-j$(nproc)
빌드 산출물 확인
주요 결과물
| 파일 | 의미 |
|---|---|
vmlinux | ELF 커널 이미지 |
arch/x86/boot/bzImage | x86 부트 이미지 |
arch/arm64/boot/Image | arm64 커널 이미지 |
modules/ | 커널 모듈 |
빌드 성공 여부 빠른 체크
file out/vmlinux
아래처럼 “ELF 64-bit LSB pie executable, ARM aarch64” 정도가 확인되면 정상적으로 빌드됐다고 볼 수 있다.
$ file out/vmlinux
out/vmlinux: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), statically linked, BuildID[sha1]=b21eee087608e453d874e6e8ce457056496c39ac, with debug_info, not stripped
GCC 빌드와의 차이 요약
| 항목 | GCC | Clang/LLVM |
|---|---|---|
| 빌드 플래그 | 기본 | LLVM=1 |
| 링커 | ld.bfd | ld.lld |
| BTF 연계 | 보통 | 매우 좋음 |
| 분석 도구 | 제한적 | sanitizer, analyzer 풍부 |