먼저 결론
Ubuntu 22.04에서 Linux 커널 메인라인 소스를 직접 빌드해 bzImage까지 만들었다. 처음에는 gelf.h: No such file or directory에서 멈췄는데, 빌드 의존성을 빠뜨린 것이 원인이었다. 아래는 실패 로그까지 포함한 실제 기록이다.
이번에는 최신 메인라인 소스를 기준으로 빌드했다.
환경 세팅
$ sudo apt update
$ sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev bc git ccache -y
- build-essential : 핵심 컴파일러 툴체인 모음 (gcc, g++, make, libc6-dev – 표준 c 라이브러리 헤더파일들)
- libncurses-dev : 텍스트 기반 화면 (TUI) 라이브러리. (커널 make menuconfig할 때 나오는 창)
- bison & flex : 컴파일러 구문 분석기 생성 도구. 커널 소스 내 config 파일 해석할 때 필요함.
- libssl-dev : OpenSSL 라이브러리. 커널 빌드 시 보안 서명.
- libelf-dev : ELF 라이브러리. 커널 내부의 디버깅 정보 생성할 때 쓰임.
- bc : 터미널용 정밀 계산기. 빌드 시간 측정 & 내부 수치 계산할 때 쓰임.
- git : 알지?
- ccache : 컴파일러 캐시 유틸리티. 속도 업.
작업 디렉토리 세팅
$ mkdir -p ~/kernel_study/build
$ cd ~/kernel_study
$ git clone --depth 1 https://github.com/torvalds/linux.git
$ cd linux
- 리누스 토발즈님의 소스를 직접 빌드해본다.
- git clone –depth 1을 주어 방대한 history 모두 받지 않도록 함 (수 GB 넘어감).
-> ‘–depth 1’ 주면 전체 디렉토리는 2.1GB
커널 설정 파일 생성
여기서 파일 시스템, 네트워크, 그래픽 드라이버같은걸 켜고 끌 수 있음.
$ make defconfig O=../build
- make defconfig : define 이 아닌 default config. 현재 컴퓨터에 맞도록 기본적인 권장 설정해줌.
- O= : output 디렉토리 설정. 처음보는 문법이네..
~/kernel_study/linux$ make defconfig O=../build
make[1]: Entering directory '/home/worker/kernel_study/build'
UPD /home/worker/kernel_study/build/Makefile
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
HOSTCC scripts/kconfig/confdata.o
HOSTCC scripts/kconfig/expr.o
LEX scripts/kconfig/lexer.lex.c
YACC scripts/kconfig/parser.tab.[ch]
HOSTCC scripts/kconfig/lexer.lex.o
HOSTCC scripts/kconfig/menu.o
HOSTCC scripts/kconfig/parser.tab.o
HOSTCC scripts/kconfig/preprocess.o
HOSTCC scripts/kconfig/symbol.o
HOSTCC scripts/kconfig/util.o
HOSTLD scripts/kconfig/conf
*** Default configuration is based on 'x86_64_defconfig'
#
# configuration written to .config
#
make[1]: Leaving directory '/home/worker/kernel_study/build'
<build/.config>
~/kernel_study/build$ cat .config -n | head
1 #
2 # Automatically generated file; DO NOT EDIT.
3 # Linux/x86 7.3.0-rc7 Kernel Configuration
4 #
5 CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
6 CONFIG_CC_IS_GCC=y
7 CONFIG_GCC_VERSION=110400
8 CONFIG_CLANG_VERSION=0
9 CONFIG_AS_IS_GNU=y
10 CONFIG_AS_VERSION=23800
총 5486 lines;;
빌드
$ make -j$(nproc) O=../build
$ echo $(nproc)
64
근데 에러남.
/home/worker/kernel_study/linux/tools/objtool/include/objtool/elf.h:10:10: fatal error: gelf.h: No such file or directory
10 | #include <gelf.h>
| ^~~~~~~~
compilation terminated.
make[5]: *** [/home/worker/kernel_study/linux/tools/build/Makefile.build:96: /home/worker/kernel_study/build/tools/objtool/signal.o] Error 1
In file included from /home/worker/kernel_study/linux/tools/objtool/include/objtool/objtool.h:13,
from /home/worker/kernel_study/linux/tools/objtool/include/objtool/arch.h:11,
from /home/worker/kernel_study/linux/tools/objtool/include/objtool/check.h:11,
from arch/x86/decode.c:18:
/home/worker/kernel_study/linux/tools/objtool/include/objtool/elf.h:10:10: fatal error: gelf.h: No such file or directory
10 | #include <gelf.h>
| ^~~~~~~~
compilation terminated.
make[6]: *** [/home/worker/kernel_study/linux/tools/build/Makefile.build:96: /home/worker/kernel_study/build/tools/objtool/arch/x86/decode.o] Error 1
make[5]: *** [/home/worker/kernel_study/linux/tools/build/Makefile.build:158: arch/x86] Error 2
make[4]: *** [Makefile:125: /home/worker/kernel_study/build/tools/objtool/objtool-in.o] Error 2
make[3]: *** [Makefile:74: objtool] Error 2
make[2]: *** [/home/worker/kernel_study/linux/Makefile:1632: tools/objtool] Error 2
make[2]: *** Waiting for unfinished jobs....
HOSTLD scripts/mod/modpost
CC kernel/bounds.s
CHKSHA1 /home/worker/kernel_study/linux/include/linux/atomic/atomic-arch-fallback.h
CHKSHA1 /home/worker/kernel_study/linux/include/linux/atomic/atomic-instrumented.h
CHKSHA1 /home/worker/kernel_study/linux/include/linux/atomic/atomic-long.h
UPD include/generated/timeconst.h
UPD include/generated/bounds.h
CC arch/x86/kernel/asm-offsets.s
UPD include/generated/asm-offsets.h
CC kernel/sched/rq-offsets.s
UPD include/generated/rq-offsets.h
CALL /home/worker/kernel_study/linux/scripts/checksyscalls.sh
make[1]: *** [/home/worker/kernel_study/linux/Makefile:248: __sub-make] Error 2
make[1]: Leaving directory '/home/worker/kernel_study/build'
make: *** [Makefile:248: __sub-make] Error 2
오류의 핵심은 gelf.h 누락이었다. 위의 의존성 설치 명령을 실행하지 않은 상태였고, libelf-dev를 포함한 패키지를 설치한 뒤 같은 빌드 명령을 다시 실행했다.
패키지 설치하고 빌드 시작
.....
AS arch/x86/boot/pmjump.o
CC arch/x86/boot/printf.o
CC arch/x86/boot/regs.o
CC arch/x86/boot/string.o
CC arch/x86/boot/tty.o
CC arch/x86/boot/video.o
CC arch/x86/boot/video-mode.o
CC arch/x86/boot/version.o
CC arch/x86/boot/video-vga.o
CC arch/x86/boot/video-vesa.o
CC arch/x86/boot/video-bios.o
CPUSTR arch/x86/boot/cpustr.h
LDS arch/x86/boot/compressed/vmlinux.lds
AS arch/x86/boot/compressed/kernel_info.o
AS arch/x86/boot/compressed/head_64.o
VOFFSET arch/x86/boot/compressed/../voffset.h
CC arch/x86/boot/cpu.o
CC arch/x86/boot/compressed/string.o
CC arch/x86/boot/compressed/cmdline.o
CC arch/x86/boot/compressed/error.o
OBJCOPY arch/x86/boot/compressed/vmlinux.bin
RELOCS arch/x86/boot/compressed/vmlinux.relocs
HOSTCC arch/x86/boot/compressed/mkpiggy
CC arch/x86/boot/compressed/cpuflags.o
CC arch/x86/boot/compressed/early_serial_console.o
CC arch/x86/boot/compressed/kaslr.o
CC arch/x86/boot/compressed/ident_map_64.o
CC arch/x86/boot/compressed/idt_64.o
AS arch/x86/boot/compressed/idt_handlers_64.o
CC arch/x86/boot/compressed/pgtable_64.o
CC arch/x86/boot/compressed/acpi.o
CC arch/x86/boot/compressed/efi.o
GZIP arch/x86/boot/compressed/vmlinux.bin.gz
CC arch/x86/boot/compressed/misc.o
MKPIGGY arch/x86/boot/compressed/piggy.S
AS arch/x86/boot/compressed/piggy.o
LD arch/x86/boot/compressed/vmlinux
ZOFFSET arch/x86/boot/zoffset.h
OBJCOPY arch/x86/boot/vmlinux.bin
AS arch/x86/boot/header.o
LD arch/x86/boot/setup.elf
OBJCOPY arch/x86/boot/setup.bin
BUILD arch/x86/boot/bzImage
Kernel: arch/x86/boot/bzImage is ready (#1)
make[1]: Leaving directory '/home/worker/kernel_study/build'
패키지를 설치한 뒤에는 빌드가 완료됐다.
커널 훑기
~/kernel_study$ tree -L 1 build
build
├── arch
├── block
├── built-in.a
├── built-in-fixup.a
├── certs
├── crypto
├── drivers
├── fs
├── include
├── init
├── io_uring
├── ipc
├── kernel
├── lib
├── Makefile
├── mm
├── modules.builtin
├── modules.builtin.modinfo
├── modules.order
├── Module.symvers
├── net
├── scripts
├── security
├── sound
├── source -> /home/worker/kernel_study/linux
├── System.map
├── tools
├── usr
├── virt
├── vmlinux
├── vmlinux.a
├── vmlinux.o
└── vmlinux.unstripped
21 directories, 12 files
아래 vmlinux 파일이 따끈따끈한 커널 바이너리임.
52M Oct 12 19:27 vmlinux*
아래 bzImage실제 메모리에 올라가는 이미지임. vmlinux에서 불필요한 정보 빼고 gzip압축한 파일임.
~/kernel_study/build/arch/x86/boot/bzImage
끝.
이후엔 커널 드라이버(*.ko) 까보기.
결론
이번 빌드에서 가장 오래 걸린 건 컴파일 자체보다 의존성 확인이었다. defconfig로 설정을 만들고, O=../build로 결과물을 소스 트리 밖에 분리하면 실패 뒤에도 다시 살펴보기 편했다. 빌드 구조와 타깃은 Linux 커널 공식 Kbuild 문서에서 더 확인할 수 있다.