Kbuild system

개발 조회 수 1359 추천 수 0 2017.06.13 12:05:53

출처 : https://wiki.kldp.org/wiki.php/DocbookSgml/KBUILD

1. 오버뷰

Makefile은 몇개의 부분으로 이루어져 있다.

표 1. Makefile의 구성

.config커널 설정 파일
arch/$(ARCH)/Makefile아키텍쳐 별 Makefile
scripts/Makefile.*모든 kbuild Makefile에 사용되는 규칙이 들어있는 파일
kbuild Makefiles약 500개 정도가 있다

최상위 Makefile은 커널 소스 트리의 루트 디렉토리에 있는 Makefile을 말한다(보통은 /usr/src/linux/Makefile). 그리고 커널 설정 프로세스로 부터 커널 설정 후 생성된 .config를 읽어 사용한다.

최상위 Makefile은 두개의 중요한 결과물을 만들어낸다. 첫번째로 vmlinux(메모리에 상주하는 커널 이미지)이고 두번째는 모듈들이다.

최상위 Makefile은 이런 결과물을 만들기 위해 커널 소스 디렉토리의 하위 디렉토리를 리커시브하게 찾아 들어가면서 만들어낸다. 사용되는 하위 디렉토리는 커널 설정에 따라 달라지고 최상위 Makefile은 arch/$(ARCH)/Makefile을 직접 include한다(보통의 다른 Makefile은 make에 의해 실행되어지는 형태지만 이것만 실행되지 않고 최상위 Makefile에 직접 포함되어 실행되어진다. 최상위 Makefile을 열어보면 알겠지만 include 명령이 사용된다). arch Makefile은 아키텍쳐에 따른 정보를 최상위 Makefile에 제공한다.

각 하위 디렉토리는 상위로부터 명령을 전달하는 kbuild Makefile을 하나씩 가지고 있다. kbuild Makefile은 built-in이나 modular 타겟을 만들기 위해 혹은 kbuild가 사용하는 많은 변수 리스트를 만들기 위해 .config로부터 정보를 사용한다 (built-in은 메모리에 상주하게될 커널 이미지인 vmlinux에 직접 포함되어 링크되는 것들을 말하고 modular는 모듈로 만들어질 오브젝트에 링크될 것들을 말한다).

scripts/Makefile.*은 kbuild Makefile을 기본으로하는 커널을 만드는데 사용되는 모든 정의나 규칙을 담고 있다.


2. 누가 무엇을?

커널 Makefile과 관계 있는 사람은 5 종류가 있다.

  • 사용자

    단순히 커널을 build해 사용하는 사람이다. 이 사람은 “make menuconfig”나 “make”와 같은 명령을 입력하는 사람이고 일반적으로는 커널 Makefile(그외의 다른 모든 소스 파일도 포함)을 읽거나 변경하지 않는다.

  • 보통 개발자

    디바이스 드라이버나 파일 시스템 혹은 네트웍 프로토콜 등을 조정하거나 하는 일은 한다. 이런 사람은 자신이 사용하는 하위 시스템에 대한 kbuild Makefile을 관리한다. 이런 일을 효율적으로 하기 위해선 커널 Makefile에 대한 전반적인 이해가 필요하고 kbuild에 대한 public interface의 상세한 것가지도 알고 있어야한다.

  • Arch 개발자

    i386, ppc, arm등의 전체 아키텍쳐에 걸쳐 일을 하는 사람이다. 아키텍쳐 개발자는 kbuild Makefile 뿐만 아니라 arch Makefile도 알고 있어야한다.

  • kbuild 개발자

    커널 build 시스템 자체를 개발하는 사람이고 커널 Makefile 전체의 돌아가는 방식에 대한 이해가 필요하다.

이문서는 일반 개발자나 arch 개발자를 위한 것이다.

그러나 커널 Makefile이 어떻게 동작하는지 아는 것이 좋은 경우가 많다. 단순히 새로운 커널을 컴파일해 설치해 사용하는 사용자가 아니고 시스템 엔지니어라면 커널이 어떻게 만들어지는 알고 있는 것이 도움이 될 때가 많다. 예를 들어 현재 설정에 의해 어떤 모듈이 어떤 파일로 이루어져 있는지 알수 있으면 그 파일들을 조사해 수정하거나 하는 일이 가능하기 때문이다.


3. kbuild Makefiles

커널 내의 대부분의 Makefile은 kbuild 인프라 스트럭쳐를 사용한다. 이 장에서는 kbuild makefile들에서 사용되는 문법에 대해 소개한다. 3.1장은 “Goal 정의”에 대한 간단한 소개고 그 이후 장에서 더 자세한 것을 다룰 것이다.


3.1. Goal 정의

Goal 정의는 kbuild Makefile의 가장 중요한 부분이다. Goal은 만들어져할 것, 특별한 컴파일 옵션, 사용되야할 하위디렉토리를 정의한다. 가장 간단한 kbuild makefile은 다음과 같은 한 줄을 갖는다.

	예:
		obj-y += foo.o
				
이 예가 말하는 것은 이 디렉토리 내에 foo.o(foo.c나 foo.S로부터 만들어질)란 이름의 한개의 오브젝트가 있다는 것이다. 만약 foo.o가 모듈로 만들어진다면 obj-m이란 변수가 사용된다. 그래서 다음과 같은 예처럼 된다.
	예:
		obj-$(CONFIG_FOO) += foo.o
				
$(CONFIG_FOO)는 y(built-in을 의미)나 m(모듈을 의미)의 값을 갖는다. 만약 CONFIG_FOO가 y나 m의 값을 갖지 않는다면 이 파일은 컴파일되거나 링크되지 않는다.


3.2. Built-in 오브젝트 Goal (obj-y)

kbuild Makefile은 $(obj-y) 리스트 내에 vmlinux에 필요한 오브젝트 파일을 지정해 놓는다.

kbuild는 모든 $(obj-y) 파일을 컴파일한다. 그리고 이런 모든 파일을 하나의 build-in.o로 만들기 위해 “$(LD) -r”을 부른다.

$(obj-y)에 기록된 파일의 순서는 매우 중요하다. 중복되서 나열되는 것도 허용되지만 첫번째로 나오는 것이 built-in.o에 링크되고 그 이후의 것은 무시된다.

어떤 기능 들은(예를 들어 module_init()나 __initcall) 부팅하는 동안 나타나는 순서대로 불려지기 때문에 링크 순서도 중요하다. 그래서 순서를 바꾸게되면 디스크 등의 드라이버가 사용되는 순서가 바뀌는 등의 일 때문에 디스크의 번호도 바뀔수 있다.

	예:
		#drivers/isdn/i4l/Makefile
		# Makefile for the kernel ISDN subsystem and device drivers.
		# Each configuration option enables a list of files.
		obj-$(CONFIG_ISDN) += isdn.o
		obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
			

3.3. Loadable module goals(obj-m)

$(obj-m)은 적재 가능한 모듈을 만들 때 사용된다.

모듈은 하나의 소스 코드나 여러 개의 소스 코드에서 만들어질 수 있다. 하나의 소스 코드로 만들어지는 경우엔 그냥 $(obj-m)에 더하기만 하면 된다.

	예:
		#drivers/isdn/i4l/Makefile
		obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

	Note: 이 예에서 $(CONFIG_ISDN_PPP_BSDCOMP)는 'm'을 나타낸다.
			

만약 커널 모듈이 여러 개의 소스 파일로부터 만들어지면 위에 나온 것과 같은 방식으로 지정하면된다.

kbuild는 만들고자하는 모듈이 어느 부분에서 오는지를 알면되고 $(<module_name>-objs)에 지정해 주면 된다.

	예:
		#drivers/isdn/i4l/Makefile
		obj-$(CONFIG_ISDN) += isdn.o
		isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
			

이 예에서 모듈 이름은 isdn.o이고 kbuild는 $(isdn-objs)안에 있는 오브젝트를 컴파일 한 후에 “$(LD) -r”을 실행해 isdn.o를 만들어낸다.

kbuild는 오브젝트를 접미사 -objs와 -y에 의해 만들어지는 복합 오브젝트로 인식할 수 있다. 만약 오브젝트가 복합 오브젝트의 일부라면 Makefile이 CONFIG_ 값을 사용하도록 할 수 있다.

	예:
		#fs/ext2/Makefile
		obj-$(CONFIG_EXT2_FS) += ext2.o
		ext2-y := balloc.o bitmap.o
		ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
			

이 예에선 xattr.o는 $(CONFIG_EXT2_FS_XATTR)이 'y'인 경우에만 복합 오브젝트인 ext2.o의 일부 뿐이다.

Note: 물론 커널 안에 모듈을 포함하는 경우에도 위와 같은 문법은 그대로 적용된다. 그래서 CONFIG_EXT2_FS=y인 경우 kbuild는 ext2.o 파일을 만들어 built-in.o에 링크하게된다.


3.4. 3.4. 심볼을 export하는 오브젝트

심볼을 export하는 모듈에 대한 특별한 요구 사항 같은 것은 없다. 커널 소스 디렉토리의 Documentation/modules.txt를 참조하기 바란다.


3.5. 라이브러리 Goal(lib-y)

obj-*로 지정된 오브젝트 들은 라이브러리 (lib.a와 같은 것)에 포함될 수도 있다. lib-y에 지정된 모든 오브젝트는 그 디렉토리에서 하나의 라이브러리로 만들어진다. obj-y와 lib-y에 동시 지정된 오브젝트는 라이브러리에 포함되지 않는다. 그렇지만 이 오브젝트 들은 어쨌든 접근 가능하게 된다. 같은 식으로 lib-m에 지정된 오브젝트는 lib.a에 포함된다.

때로는 같은 kbuild makefile이 built-in과 라이브러리를 동시에 지정할 수도있다. 이런 경우엔 같은 디렉토리에 built-in.o와 lib.a 둘다 존재할 수도 있다.

	예:
		#arch/i386/lib/Makefile
		lib-y := checksum.o delay.o
			

이 예제는 checksum.o와 delay.o를 기반으로하는 lib.a를 만든다.

보통 lib-y의 사용은 lib/와 arch/*/lib 디렉토리에 한한다.


3.6. 하위 디렉토리로 내려가기

Makefile은 그것이 속한 디렉토리만을 책임진다. 하위 디렉토리에 있는 파일들은 그 하위 디렉토리에 있는 다른 Makefile에 의해 관리된다. 빌드 시스템은 자동적으로 하위 디렉토리를 리커시브하게 부른다.

그렇게 하기 위해서 obj-y와 obj-m이 사용된다. 원하는 디렉토리 이름 뒤에 /를 붙여 이렇게 한다. ext2라는 모듈은 여러 디렉토리에 걸쳐 있고 fs/에 Makefile이 있다. 이 Makefile은 kbuild에게 아래와 같은 할당을 동해 하위 디렉토리로 내려가도록 한다.

	예:
		#fs/Makefile
		obj-$(CONfIG_EXT2_FS) += ext2/
			

CONFIG_EXT2_FS가 'y'나 'm'이면 obj- 변수는 세트되고 kbuild는 하위 디렉토리로 내려가게 된다. kbuild는 이 정보를 다른 디렉토리를 방문해야하는지 결정하는데만 사용한다. 즉 하위 디렉토리의 Makefile에게 무엇이 모듈이고 무엇이 built-in인지 지정한다.

CONFIG_ 변수를 사용해 디렉토리 이름을 나타내도록 하는 것은 좋은 방법이다. 이렇게 하면 'y'나 'm'이 아닌 이상엔 그 디렉토리를 완전히 무시하게 할 수있다.


3.7. 컴파일 플래그

EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS

모든 EXTRA_ 변수는 지정되어 있는 kbuild makefile에만 적용되고 그 makefile의 모든 실행되는 명령에 적용된다.

  • $(EXTRA_CFLAGS)

    $(CC)로 컴파일 하는 C 프로그램에 대한 옵션을 지정한다.

    	예:
    		# drivers/sound/emu10k1/Makefile
    		EXTRA_CFLAGS += -I$(obj)
    		ifdef DEBUG
    			EXTRA_CFLAGS += -DEMU10K1_DEBUG
    		endif
    					

    최상위 Makefile은 $(CFLAGS)를 가지고 있고 전체 트리에 대한 컴파일 플래그로 사용되므로 이 변수가 필요한 것이다.

  • $(EXTRA_AFLAGS)

    어셈블리 코드를 컴파일 할 때 필요한 디렉토리 별 옵션이다.

    	예:
    		#arch/x86_64/kernel/Makefile
    		EXTRA_AFLAGS := -traditional
    					

    $(EXTRA_LDFLAGS)와 $(EXTRA_ARFLAGS)는 $(LD)와 $(AR)을 위한 디렉토리 별 옵션이다.

    	예:
    		#arch/m68k/fpsp040/Makefile
    		EXTRA_LDFLAGS := -x
    					

CFLAGS_$@, AFLAGS_$@

CFLAGS_$@와 AFLAGS_$@는 현재 kbuild makefile 내의 명령에만 적용된다.

  • $(CFLAGS_$@)

    $(CC)에 대한 디렉토리 별 옵션이다. $@는 문자 값을 나타내고 파일을 지정한다.

    	예:
    		# drivers/scsi/Makefile
    		CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
    		CFLAGS_gdth.o = -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
    		CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
    					

    이 3줄은 aha152x.o, gdth.o, seagate.o에 대한 컴파일 플래그를 각각 지정하고 있다.

  • $(AFLAGS_$@)

    어셈블리 언어 소스 파일에 대한 옵션이다.

    	예:
    		# arch/arm/kernel/Makefile
    		AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
    		AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional
    					

3.8. 의존성 추적

kbuild는 다음과 같은 의존성을 추적한다.

  • 모든 미리 지정된(prerequisite) 파일 (*.c와 *.h 모두)

  • 모든 미리 지정된 파일에 대해 사용된 CONFIG_ 옵션

  • 컴파일 타겟에 사용된 커맨드 라인

그래서 $(CC)에 대한 옵션이 바뀌면 관련된 모든 파일은 재컴파일 된다.


3.9. 특별 규칙

특별한 규칙은 kbuild 인프라 스트럭쳐가 필요로 하는 기능을 제공하지 못할 때 사용한다. 대표적인 예가 빌드 동안 생성되는 헤더 파일 같은 것이다. 다른 예는 아키텍쳐에 따라 부트 이미지 등을 준비등에 필요한 특별한 규칙을 필요로 하는 경우다.

특별 규칙은 보통의 make 규칙을 사용해 씌어지고 Makefile이 존재하는 곳에서는 kbuild가 실행되지 않는다. 그래서 모든 특별 규칙은 필요한 파일이나 타겟 파일에 대한 상대 경로(relative path)를 제공해야만 한다.

특별 규칙을 정의할 때 사용되는 두가지의 변수:

  • $(src)

    $(src)는 Makefile이 위치하고 있는 디렉토리를 가리키는 상대 경로다. 소스 트리에 존재하는 모든 파일을 가리킬 땐 항상 $(src)를 사용해야 한다.

  • $(obj)

    $(obj)는 타켓이 저장되는 디렉토리를 가리키는 상대 경로다. 일반 적인 파일을 가리킬 땐 항상 $(obj)를 사용해야 한다.

    	예:
    		#drivers/scsi/Makefile
    		$(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl
    			$(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl
    						

    이 예는 일반 문법을 사용하는 특별 규칙이다. 타겟 파일은 두개의 미지 지정된 파일에 대한 의존성을 갖고 있다. 타겟 파일은 $(obj)를 사용하고 미리 지정된 파일은 일반 파일이 아니기 대문에 $(src)를 사용한다.


4. 호스트 프로그램 지원

kbuild는 컴파일 스테이지 동안 사용되는 호스트 상에서 돌아가는 프로그램을 만들기도 한다. 호스트 실행 파일을 만들기 위해선 두 스텝의 절차가 필요하다.

첫번째 스텝은 kbuild에게 호스트 프로그램이 존재한다고 알리는 것이다. 이건 host-prog를 사용해 한다. 두번재 스텝은 실행 파일에 대한 정확한 의존성을 더해주는 것이다. 이것은 규칙에 의존성을 더하거나 $(always) 변수를 사용하는 방법이 있다.


4.1. 간단한 호스트 프로그램

때로는 빌드가 실행되는 컴퓨터 상에서 프로그램을 컴파일 하고 실행할 필요가 있다. 아래 예는 kbuild에게 bin2hex를 호스트에서 만들라고 알려준다.

	예:
		host-progs := bin2hex
			

kbuild는 bin2hex가 Makefile과 같은 디렉토리에 있는 bin2hex.c라는 하나의 소스 파일에서 만들어진다고 가정한다.


4.2. 복합적인 호스트 프로그램

호스트 프로그램은 여러 개의 오브젝트로 구성될수도 있다. 복합 오브젝트를 정의하는 문법은 커널 오브젝트에 사용된 문법과 비슷하다. $(<executeable>-objs)는 최종 실행 파일을 구성하는 오브젝트를 나타낸다.

	예:
		#scripts/lxdialog/Makefile
		host-progs    := lxdialog  
		lxdialog-objs := checklist.o lxdialog.o
			

.o 확장자를 갖는 오브젝트는 그에 상응하는 .c 파일로 부터 컴파일된다. 위의 예에선 checklist.c가 컴파일 되 checklist.o를 만든다. 최종적으로 두개의 .o 파일이 하나의 실행 파일인 lxdialog로 링크된다.

Note: <executable>-y와 같은 문법은 호스트 실행 파일에는 적용되지 않는다.


4.3. 공유 라이브러리 정의

.so 확장자를 같는 오브젝트는 공유 라이브러리를 나타내고 위치에 상관 없는 오브젝트로 컴파일 된다. kbuild는 고유 라이브러리를 제공하지만 사용은 제한 되어 있다. 아래 예에서 conf라는 실행 파일을 링크하기 위해 libkconfig.so가 사용된다.

	예:
		#scripts/kconfig/Makefile
		host-progs      := conf
		conf-objs       := conf.o libkconfig.so
		libkconfig-objs := expr.o type.o
				

공유 라이브러리는 언제나 그에 상응하는 -objs 를 필요로 한다. 그리고 위 예제에서 libkconfig는 두개의 오브젝트 expr.o와 type.o로부터 만들어진다. expr.o와 type.o는 위치 독립 적인 코드로 만들어지고 libkconfig.so로 링크된다. C++은 공유 라이브러리를 지원하지 않는다.


4.4. 호스트 프로그램에 C++ 사용하기

kbuild는 C++로 작성된 호스트 프로그램을 지원한다. 이것은 kconfig를 위해 소개되지만 일반적인 사용에서는 추천하지 않는다.

	예:
		#scripts/kconfig/Makefile
		host-progs	:= qconf
		qconf-cxxobjs	:= qconf.o
				

예제에서 실행 파일은 C++파일인 qconf.cc로 작성되어 있고 $(qconf-cxxobjs)로 정의된다. 만약 qconf가 .c와 .cc 파일로 이뤄져 있다면 이를 구분하기 위해 추가 줄이 더 필요할 수도 있다.

	예:
		#scripts/kconfig/Makefile
		host-progs	:= qconf
		qconf-cxxobjs	:= qconf.o
		qconf-objs	:= check.o
				

4.5. 호스트 프로그램용 컴파일러 옵션 설정

호스트 프로그램을 컴파일 하는 동안에 특별한 플래그가 필요할 수도 있다. 프로그램은 언제나 $(HOSTCC)를 사용해 컴파일 되므로 $(HOSTCFLAGS)를 사용하면 된다. Makefile에의해 만들어지는 모든 호스트 프로그램에 걸쳐 영향을 주는 플래그를 세팅하기 위해선 HOST_EXTRACFLAGS 변수를 사용한다.

	예:
		#scripts/lxdialog/Makefile
		HOST_EXTRACFLAGS += -I/usr/include/ncurses
				

한개의 파일 만을 위한 플래그는 아래와 같은 방법으로 한다.

	예:
		#arch/ppc64/boot/Makefile
		HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE)
				

아래 예제는 링커에게 특별한 옵션을 추가 지정해준다.

	예:
		#scripts/kconfig/Makefile
		HOSTLOADLIBES_qconf := -L$(QTDIR)/lib
				

qconf를 링크할 때 특별 옵션인 “-L$(QTDIR)/lib”이 전달된다.


4.6. 호스트 프로그램이 실제로 만들어질 때

kbuild는 호스트 프로그램이 정확하게 미리 지정됐을 경우에만 만든다. 이런 경우는 두가지가 존재할 수 있다.

  1. 특별한 규칙 내에 명확하게 미리 지정된 파일을 나열한다.

    	예:
    		#drivers/pci/Makefile
    		host-progs := gen-devlist
    		$(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist
    			( cd $(obj); ./gen-devlist ) < $<
    						

    타겟 $(obj)/devlist.h는 $(obj)/gen-devlist가 업데이트 되기 전에는 만들어지지 않는다. 특별 규칙에서 호스트 프로그램에 대한 레퍼런스는 $(obj)로 시작해야만 한다.

  2. $(always) 사용

    적당한 특별 규칙이 없는 경우엔 makefile에서 호스트 프로그램이 만들어질 때 $(always) 변수가 사용된다.

    	예:
    		#scripts/lxdialog/Makefile
    		host-progs    := lxdialog
    		always        := $(host-progs)
    							
    이 예제는 kbuild에게 어느 규칙에도 언급되지 않았지만 lxdialog를 만들도록 한다.


5. kbuild clean 인프라 스트럭쳐

"make clean"은 커널이 컴파일 되는 소스 트리 내에서 생성된(호스트 프로그램 포함) 모든 파일을 지운다. $(host-progs), $(always), $(extra-y)에 지정된 모든 타겟이 지워진다. "*.[oas]", "*.ko"와 kbuild에 의해 만들어진 약간의 추가 파일이 지워진다.

추가 파일은 $(clean-files)에 지정된다.

	예:
		#drivers/pci/Makefile
		clean-files := devlist.h classlist.h
		

"make clean"을 실행 하면 두개의 파일 “devlist.h classlist.h”가 지워지고 kbuild는 $(clean-files)에 지정된 이 두 파일을 makefile이 있는 디렉토리에서 찾는다.

보통 kbuild는 “obj-* := dir/”에 의해 하위 디렉토리로 내려가지만 아키텍쳐 별 makefile에서는 이게 충분하지 않아 때로는 정확하게 지정해야할 필요가 있다.

	예:
		#arch/i386/boot/Makefile
		subdir- := compressed/
		

위의 예제는 “make clean”이 실행될 때 compressed/ 디렉토리로 내려가서 지우란 것을 가르쳐주고 있다.

최종 부트 이미지를 만드는 Makefile에서 지우기를 지원하기 위해선 archclean:이란 이름의 타겟을 사용한다.

	예:
		#arch/i386/Makefile
		archclean:
			$(Q)$(MAKE) $(clean)=arch/i386/boot
		

"make clean"이 실행되고 arch/i386/boot로 내려가면 거기 들어있는 Makefile은 하위 디렉토리로 더 내려가기 위해 subdir- 트릭을 사용한다.

Note 1: arch/$(ARCH)/Makefile은 최상위 Makefile에 포함되므로 “subdir-”을 사용할 수 없다. 그리고 최상위 Makefile에서는 kbuild 인프라 스트럭쳐가 동작하지 않는다.

Note 2: core-y, libs-y, drivers-y, net-y에 나열된 모든 디렉토리는 “make clean” 동안 모두 방문된다.


6. 아키텍쳐 Makefiles

최상위 Makefile은 각 디렉토리로 내려가기 전에 환경을 설정하고 준비를 한다. 최상위 Makefile은 일반적인 부분을 가지고 있고 arch/$(ARCH)/Makefile이 아키텍쳐에 따른 kbuild를 셋업하는데 필요한 것을 담고 있다. 이렇게 하기 위해서 최상위 Makefile에 포함되는 arch/$(ARCH)/Makefile은 몇가지 변수와 타겟을 정의한다.

kbuild가 실행될 때 대략 다음과 같은 절차를 거친다.

  1. 커널 설정

    .config를 만들어 냄

  2. 커널 버전을 include/linux/version.h에 저장

  3. include/asm-$(ARCH)에 대한 심볼릭 링크를 만든다

  4. 그 외의 다른 모든 타겟을 준비한다

    필요한 것은 arch/$(ARCH)/Makefile에서 지정된다.

  5. 하위 디렉토리로 내려감

    init-* core* driver-* net-* libs-*과 모든 타겟을 만듬

    위의 변수 값은 arch/$(ARCH)/Makefile에서 확장된다.

  6. 모든 오브젝트는 링크되고 소스 트리의 루트 디렉토리에 vmlinux를 만들어 낸다

    Head-y와 arch/$(ARCH)/Makefile에 지정된 오브젝트가 가장 먼저 링크된다.

  7. 마지막으로 포스트 프로세싱이나 최종 부트 이미지를 만들기 위한 아키텍쳐에 따른 부분이 실행된다

    부트 레코드를 만드는 일과 initrd 이미지와 같은 것을 만드는 일이 포함된다.


6.1. 아키텍쳐 빌드를 수정하기 위한 변수 세팅

  • LDFLAGS - 일반적인 $(LD) 옵션

    링커를 부를 때 항상 사용되는 플래그이다. 보통 에뮬레이션을 지정하는 것만으로도 충분하다.

    	예:
    		#arch/s390/Makefile
    		LDFLAGS := -m elf_s390
    						
    Note: EXTRA_LDFLAGS와 LDFLAGS_$@는 플래그를 좀더 커스터마이즈 하는데 사용된다. 7장을 참조하라.

  • LDFLAGS_MODULE - 모듈을 링크할 때 $(LD)에 사용되는 옵션

    LDFLAGS_MODULE은 모듈을 만드는데 사용되는 .ko 파일을 링크할 때 $(LD)에 지정되는 플래그다. 기본은 재배치를 위한 “-r”.

  • LDFLAGS_vmlinux - vmlinux를 링크할 때 사용되는 $(LD)용 플래그

    LDFLAGS_vmlinux는 마지막으로 vmlinux를 링크할 때 링커에게 전달되는 플래그다. LDFLAGS_vmlinux는 LDFLAGS_$@를 사용할 수 있다.

    	예:
    		#arch/i386/Makefile
    		LDFLAGS_vmlinux := -e stext
    						

  • LDFLAGS_BLOB - initramfs blob을 링크할 때 $(LD)에 사용되는 플래그

    Initramfs에 사용되는 이미지는 빌드 프로세스 동안 만들어진다. LDFLAGS_BLOB은 initramfs_data.o 파일을 만드는에 사용된다.

    	예:
    		#arch/i386/Makefile
    		LDFLAGS_BLOB := --format binary --oformat elf32-i386
    						

  • OBJCOPYFLAGS - objcopy 플래그

    .o 파일을 번역하기 위해 $(call if_changed,objcopy)가 사용되면 OBJCOPYFLAGS가 사용된다. $(call if_changed,objcopy)는 보통 vmlinux에서 바이너리를 추출하기 위해 사용된다

    	예:
    		#arch/s390/Makefile
    		OBJCOPYFLAGS := -O binary
    
    		#arch/s390/boot/Makefile
    		$(obj)/image: vmlinux FORCE
    			$(call if_changed,objcopy)
    						
    이 예제에선 $(obj)/image가 vmlinux의 바이너리 버전이다. $(call if_changed,xxx)의 용도는 나중에 설명된다.

  • AFLAGS - $(AS) 어셈블러 플래그

    기본 값은 최상위 Makefile을 보라. 필요에 따라 아키텍쳐 마다 추가하거나 수정하라.

    	예:
    		#arch/sparc64/Makefile
    		AFLAGS += -m64 -mcpu=ultrasparc
    						

  • CFLAGS - $(CC) 컴파일러 플래그

    기본 값은 최상위 Makefile을 보라. 필요에 따라 아키텍쳐 마다 추가하거나 수정하라. 보통 CFLAGS는 설정에 따라 달라진다.

    	예:
    		#arch/i386/Makefile
    		cflags-$(CONFIG_M386) += -march=i386
    		CFLAGS += $(cflags-y)
    						
    많은 아키텍쳐 Makefile은 동적으로 타겟 C 컴파일러를 실행해 지원되는 옵션을 검사한다.
    		#arch/i386/Makefile
    		check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc \
    			/dev/null\ > /dev/null 2>&1; then echo "$(1)"; \
    			else echo "$(2)"; fi)
    		cflags-$(CONFIG_MCYRIXIII) += $(call check_gcc,-march=c3,-march=i486)
    
    		CFLAGS += $(cflags-y)
    						

  • CFLAGS_KERNEL - built-in용 특정 $(CC) 옵션

    $(CFLAGS_KERNEL)는 메모리 상주 커널 코드를 컴파일하는데 사용되는 특별 C 컴파일러 플래그를 담고 있다.

  • CFLAGS_MODULE - 모듈용 특정 $(CC) 옵션

    $(CFLAGS_MODULE)은 적재 가능한 커널 모듈을 컴파일하는데 사용되는 특별 C 컴파일러 플래그를 담고 있다.


6.2. Add prerequisites to prepare

The prepare: 하위 디렉토리로 내려가기 전에 미리 지정된 리스트를 만들기 위해 사용되는 규칙을 준비한다. 이것은 보통 어셈블러 상수를 담고 있는 헤더파일이다.

	예:
		#arch/s390/Makefile
		prepare: include/asm-$(ARCH)/offsets.h
			

이 예에서 include/asm-$(ARCH)/offsets.h는 하위 디렉토리로 내려가기 전에 만들어진다. kbuild가 offset header 파일을 만드는 것은 다른 장을 참조하기 바란다.


6.3. List directories to visit when descending

아키텍쳐 Makefile은 vmlinux를 어떻게 만드는지 지정하기 위해 최상위 Makefile과 같이 협조한다. 모듈에 대해선 아키텍져 별로 특별히 구분하는 것이 없다. 즉 모듈을 만드는 것은 아키텍쳐에 독립적이다.

  • head-y

    $(head-y)는 vmlinux에 링크될 오브젝트를 나열하고 있다. $(libs-y)는 lib.a가 존재할 수 있는 디렉토리를 나열하고 있다. 나머지는 각각 built-in.o 오브젝트 파일이 존재할 수 있는 디렉토리를 나열하고 있다.

  • init-y

    $(init-y) 오브젝트는 $(head-y) 뒤에 위치한다. 그리고 나서 나머지 들은 다음과 같은 순서로 위치한다.

    $(core-y), $(libs-y), $(drivers-y) 그리고 $(net-y).

    최상위 Makefile은 모든 일반 디렉토리에 대한 값을 정의한다. arch/$(ARCH)/Makefile은 아키텍쳐 에 따른 디렉토리에만 더해진다.

    	예:
    		#arch/sparc64/Makefile
    		core-y += arch/sparc64/kernel/
    		libs-y += arch/sparc64/prom/ arch/sparc64/lib/
    		drivers-$(CONFIG_OPROFILE)  += arch/sparc64/oprofile/
    						


6.4. Architecture specific boot images

arch Makefile은 vmlinux 파일을 만들고 압축하고 부트스랩핑 코드로 감싸고 해서 결과를 어딘가에 저장하는 일을 담당한다. 이것은 여러 종류의 설치 명령을 포함한다. 실제 목표는 아키텍쳐 마다 다르기 때문에 표준화 되어 있진 않다. 보통 arch/$(ARCH)/ 밑에 있는 boot/ 디렉토리에서 여러 프로세싱이 실행된다. kbuild는 boot/내에 있는 타겟을 만들기 위한 방법을 제공하지 않는다. 그래서 arch/$(ARCH)/Makefile은 boot/에 있는 타겟을 빌드하기 위해 make를 매뉴얼로 실행한다.

추천된 접근 방법은 arch/$(ARCH)/Makefile에 숏컷을 포함시키고 arch/$(ARCH)/boot/Makefile로 내려갈 때 전체 패스를 사용하도록 하는 것이다.

	예:
		#arch/i386/Makefile
		boot := arch/i386/boot
		bzImage: vmlinux
			$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
				

"$(Q)$(MAKE) $(build)=<dir>"은 하위 디렉토리에서 make를 실행하는 방법이 좋다.

아키텍쳐에 따른 타겟의 이름을 정하는데는 규칙이 없다. 그러나 “make help”를 실행할 때 관계된 모든 타겟을 출려해줘야한다. 이를 지원하기 위해선 $(archhelp)가 반드시 정의되어 있어야한다.

	예:
		#arch/i386/Makefile
		define archhelp
			echo  '* bzImage      - Image (arch/$(ARCH)/boot/bzImage)'
		endef
				

Make를 아규먼트 없이 실행했을 땐 첫번째 목표가 만들어 진다. 최상위 Makefile에서 첫번째 목표는 all: 이다. 일반적으론 부트 가능한 이미지를 만들도록 되어 있다. "make help"를 하면 나오는 리스트에서 기본 목표가 '*'로 구분되어 있다.

	예:
		#arch/i386/Makefile
		all: bzImage 
				
예제에선 아규먼트 없이 “make”를 실행 했을 때 bzImage가 만들어진다.


6.5. Building non-kbuild targets

extra-y는 obj-*에 의해 지정된 타겟 말고 현재 디렉토리에서 만들어지는 추가 타겟을 지정한다. extra-y에 모든 타겟을 열거하는 것은 다음과 같은 두가지 목적이 필요하기 때문이다.

  1. kbuild가 커맨드라인에 변경이 있는지 체크할수 있도록 하기 위해 $(call if_changed,xxx)가 사용된 경우

  2. kbuild가 “make clean” 동안 무슨 파일이 지워졌는지 알세 하기 위해

	예:
		#arch/i386/kernel/Makefile
		extra-y := head.o init_task.o
			

이 예제에선 extra-y가 만들어지긴 하지만 built-in.o의 부분으로 링크되지는 않는 것을 열거하고 있다.


6.6. Commands useful for building a boot image

kbuild는 부트 이미지를 만드는데 유용한 몇 가지의 매크로를 제공한다.

  • if_changed

    if_changed는 아래와 같은 때에 유용한 인프라 스트럭쳐다.

    	사용법:
    		target: source(s) FORCE
    			$(call if_changed,ld/objcopy/gzip)
    						

    규칙이 평가될 때 어느 파일이든지 업데이트 되야하거나 명령이 마지막 호출된 이후로 변경되었다면 규칙은 체크될 것이다. 실행 파일에 대한 어느 옵션이든지 바뀌었다면 나중에 강제로 다시 만들어질 것이다. if_changed를 사용하는 어떤 타겟이든지 $(targets)안에 무조건 나열되야한다. 그렇지 않으면 명령 체크는 실패하고 타겟은 만들어지지 않을 것이다. $(targets)에 할당한 것은 $(obj)/ 접두사가 필요 없다. if_changed는 6.7절에서 정의되는 커스텀 커맨드와 충돌할 수도 있다.

    Note: 보통은 이런 실수가 FORCE를 까먹어서 생긴다.

  • ld

    타겟을 링크한다. 보통 LDFLAGS_$@가 ld에 특별한 옵션을 세트하기 위해 사용된다.

  • objcopy

    바이너리를 카피한다. OBJCOPYFLAGS가 arch/$(ARCH)/Makefile에서 사용된다. OBJCOPYFLAGS_$@는 추가 옵션을 설정할 때 사용될 수 있다.

  • gzip

    타겟을 압축한다. 최대 압축을 사용하라.

    	예:
    		#arch/i386/boot/Makefile
    		LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
    		LDFLAGS_setup    := -Ttext 0x0 -s --oformat binary -e begtext
    
    		targets += setup setup.o bootsect bootsect.o
    		$(obj)/setup $(obj)/bootsect: %: %.o FORCE
    			$(call if_changed,ld)
    						
    이 예제에서는 서로다른 링커 옵션을 필요로 하는 두가지의 타겟이 가능하다. 링커 옵션은 LDFLAGS_$@ 문법을 사용해 각각에게 지정된다. $(targets)는 모든 비중있는 타겟에 할당된다. kbuild는 타겟을 알고 있고 다음과 같은 것을 실행한다.

    1. 커맨드 라인이 변경됐는지 체크

    2. make clean 동안 타겟이 지운다

  • ": %: %.o"

    setup.o와 bootsect.o 파일을 나열하는데서 해방시켜주는 약어다.

    Note: 보통 "target :="을 까먹어 아무런 이유도 없이 타겟이 다시 컴파일되는 실수를 만들어낸다.


6.7. Custom kbuild commands

KBUILD_VERBOSE=0인 상태로 kbuild가 실행되면 화면엔 약식의 표시만된다. 이런 모양의 커스텀 커맨드를 가능하게 하기위해선 두변수를 세팅할 필요가 있다.

quiet_cmd_<command> - 무엇이 출력될 것인가?

cmd_<command> - 실행될 커맨드

	예:
		#
		quiet_cmd_image = BUILD   $@
		cmd_image = $(obj)/tools/build $(BUILDFLAGS) \
			$(obj)/vmlinux.bin > $@

		targets += bzImage
		$(obj)/bzImage: $(obj)/vmlinux.bin $(obj)/tools/build FORCE
			$(call if_changed,image)
			@echo 'Kernel: $@ is ready'
			

$(obj)/bzImage 타겟 라인을 업데이트할 때 BUILD arch/i386/boot/bzImage는 "make KBUILD_VERBOSE=0"을 출력할 것이다.


7. kbuild Variables

최상위 Makefile은 다음과 같은 변수를 export한다.

  • VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION

    이 변수들은 현재 커널의 버전을 나다낸다. 몇 몇 소수의 arch Makefile 만이 이 값을 직접 사용한다. 보통은 $(KERNELRELEASE)를 대신 사용한다. $(VERSIlN), $(PATCHLEVEL), $(SUBLEVEL)은 '2", "4", "0"과 같은 기본적인 버전의 세부분을 나타낸다. 이 세 값은 언제나 숫자다. $(EXTRAVERSION)은 프리 패치나 추가 패치의 서브레벨을 나타낸다. 문자 스트링이고 “-pre4”와 같은 값을 갖고 보통은 공백이다.

  • KERNELRELEASE

    $(KERNELRELEASE)는 "2.4.0-pre4"와 같은 버전을 나타내거나 커널이 인스톨되는 디렉토리 이름이되는 하나의 스트링이다. 몇몇 arch Makefile은 이런 용도로 이것을 사용한다.

  • ARCH

    이 변수는 타겟 아키텍쳐를 정의한다. 몇몇 kbuild Makefile 들은 $(ARCH)를 테스트해 컴파일되야하는 파일을 정한다. 기본은 최상위 Makefile이 $(ARCH)를 호스트 시스템과 같은 아키텍쳐로 설정한다. 크로스 컴파일 하려면 이 값을 커맨드 라인에서 지정하면 된다.

    make ARCH=m68k ...

  • INSTALL_PATH

    메모리에 상주할 커널 이미지와 System.map 파일의 설치 위치를 나타낸다. 인스톨할 타겟은 아키텍쳐에 다라 다른 것을 사용한다.

  • INSTALL_MOD_PATH, MODLIB

    $(INSTALL_MOD_PATH)는 모듈의 설치 위치인 $(MODLIB)의 접두사다. 이 변수는 Makefile에 정의되어 있지 않고 필요한 경우에 사용자에 의해 넘겨진다. $(MODLIB)는 모듈이 설치될 위치를 나타낸다. 최상위 Makefile은 $(MODLIB)를 $(INSTALL_MOD_PAHT)/lib/modules/$(KERNELRELEASE)로 정의한다. 사용자는 필요한 경우 이 변수를 재지정할 수 있다.


8. Makefile language

커널 Makefile은 GNU Make와 동작하도록 만들어져 있다. Makefile 들은 GNU Make의 문서에 나온 것들만을 사용하지만 GNU 확장도 많이 사용한다. GNU Make는 함수를 처리하는 기본 리스트를 제공한다. 커널 Makefile 들은 약간의 “if” 문장으로 만들어지거나 유지될 리스트에 대한 novel style을 사용한다. GNU Makef는 두 가지의 할당 연산자를 사용한다. “:=”은 오른 편의 값을 바로 계산하고 왼편으로 대입한다. “=”는 공식 정의와 비슷해서 오른 편의 값을 계산하지 않고 왼편의 값이 사용될 때 마다 계산한다. 여러 경우에서 “=”이 적당하다. 그럼에도 불구하고 “:=”이 올바른 선택이다.


9. Credits

Original version made by Michael Elizabeth Chastain, <mailto:mec (at) shout.net>

Updates by Kai Germaschewski <kai (at) tp1.ruhr-uni-bochum.de>

Updates by Sam Ravnborg <sam (at) ravnborg.org>


10. TODO

- Describe how kbuild support shipped files with _shipped.

- Generating offset header files.

- Add more variables to section 7

List of Articles
번호 제목 글쓴이 날짜 조회 수
공지 개발 오디오 분석을 위한 소스 빌드 사전작업 secret eastsky 2010-12-16 3
공지 개발 Android Tips secret eastsky 2010-11-15 5
27 개발 Android6.0 - PowerManagerService状态分析 eastsky 2017-07-21 752
26 개발 Android6.0 - PowerManagerService Notifier 分析 eastsky 2017-07-21 705
25 개발 Android 개발 전반에 대한 연재 eastsky 2017-06-13 1158
24 개발 kBuild eastsky 2017-06-13 1136
» 개발 Kbuild system eastsky 2017-06-13 1359
22 개발 [Linux] make menuconfig 사용방법 [1] eastsky 2017-06-12 1629
21 개발 ADB 명령어 및 Log Filter eastsky 2017-06-12 1811
20 개발 GNU Make eastsky 2017-06-09 1397
19 개발 Android Build System [1] eastsky 2017-06-09 1662
18 개발 Linux and Android - Suspend / Resume eastsky 2012-12-24 30412
17 개발 안드로이드 터치 보정값을 얻자. file [1] 이종일 2011-02-23 42955
16 개발 Android에 BusyBox 첨가 하기. [3] 이종일 2011-02-22 48676
15 개발 Android 동호문서 따라하기 file 이종일 2011-02-18 29595
14 개발 Linux RamDisk 참고 자료 file 이종일 2011-02-17 33247
13 일반 Android 2.3 Platform Highlights eastsky 2010-12-08 20047
12 개발 안드로이드 초기화 과정 eastsky 2010-12-02 43044
11 일반 하이씨엘 앱 에디터 eastsky 2010-12-01 23703
10 개발 Android 2.2 - Market Client on ADV file eastsky 2010-11-30 26052
9 개발 Android 2.2 - SDK & AVD Manager file eastsky 2010-11-30 27316