'kbuild'에 해당되는 글 1건

  1. 2015.03.09 [Makefile] Kbuild 와 Module Compile
2015.03.09 17:38


Document/kbuild/makefile.txt 및 Document/kbuild/modules.txt 문서를 번역편집한 문서정리

출처좌표 : http://deepbluedawn.wordpress.com/2009/07/31/169/ 



이 문서는 리눅스 커널 2.6.x에 사용되는 kbuild System의 module build과정에 대해 설명하기 위한 문서입니다.Linux Kernel소스의 Documents/kbuild/makefiles.txt 및 Documents/kbuild/modules.txt문서를 번역및 편집한 것입니다. 따라서 상당부분이 난해하기도 하고 직역을 한 부분이 있으니 이해해 주셨으면 합니다. 번역이 매끄럽지 못한 부분은 반드시 원문을 읽어 영어 단어의 뜻을 파악하시기 바랍니다.

1.Kbuild system?

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

kbuild system은 리눅스 버젼 2.6.x대에 도입된 새로운 kernel build system이다.  kbuild는 kernel source tree 내부의 모듈들과 kernel source tree 외부의 모듈들에 대한 build를 지원한다.(후자의 경우 외부 혹은 “out-of-tree” 모듈이라고 불리우며 현재 개발 중이거나, 혹은 Kernel의 source tree에 포함되지  않는 module을 가리킬때 사용된다.)

외부 모듈 개발자들은 모든 복잡성을 숨길수 있는 간단한 하나의 makefile을 제공해야 하며, 이 makefile을 사용, 누구나  make 명령어를 통하여 module을 build할 수 있어야 한다.

1.1 Goal 정의

Goal 정의는 kbuild Makefile의 가장 중요한 부분이다. Goal은 Build과정을 통하여 최종적으로 만들어져할 것, 특별한 컴파일 옵션, 사용되야할 하위디렉토리를 정의한다. 가장 간단한 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의 값을 갖지 않는다면 이 파일은 컴파일되거나 링크되지 않는다.


1.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


1.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에 링크하게된다.


2.외부 모듈을 build하는 방법


kbuild를 사용하여 외부 모듈을 build하기 위해서는 다음의 두 가지 사항이 구비 되어 있어야 한다.

Full source tree와 이를 사용하여 build된 kernel image가 있어야 한다.

Kernel을 build 할때 사용된 target들의 일부 부분이 module build를 위하여 사용 가능하여야 한다.


2.1 외부 modules을 build하는 방법

외부 module을 build하는 일반적인 3가지 방법에 대해서 알아보자.


일반적인 module build 방법

make -C <path-to-kernel> M=’pwd’

현재 동작중인 kernel을 참조하여 module을 build하는 경우.

make -C /lib/modules/’uname -r’/build M=’pwd’

Build된 kernel을 install하는 경우

make -C <path-to-kernel> M=’pwd’ modules_install

여기에서 간단히 짚고 넘어가야 할 부분은 세가지 정도이다. 먼저 make에서 -C option은 뒤의 parameter로 directory를 변경하라는 의미이고 uname -r 은 현재 운영중인 커널의 릴리즈 버젼 정보를 출력해 주는 명령어이다.

M과 modules_install등은 추후 설명할 build target 들이다.


2.2 외부 modules을 build하는 방법


make -C <path-to-kernel> M=’pwd’: pwd로 지정되어 있는 현재 directory의 모듈을 build하며, build과정에서 생성된 모든 출력 파일은 같은 directory에 저장된다. kernel source에 대한 갱신은 이루어지지 않으며, 반드시 적어도 한번은 kernel source가 성공적으로 build되어 있어야 한다.

make -C <path-to-kernel> M=’pwd’ module: 위의 방법에서 명시적으로 “module” 이라고 하는 target을 선언한 것이며 동작은 위의 서술과 동일하다.

make -C <path-to-kernel> M=’pwd’ modules_install: Build된 module을 설치한다. 설치되는 기본 directory는 /lib/modules/<kernel-version>/extra 이지만, prefix INSTALL_MOD_PATH를 통하여 설치되는 경로를 지정할 수 있다.

make -C <path-to-kernel> M=’pwd’ clean: 모듈 build과정에서 생성된 모든 file들을 삭제하며, kernel source directory는 변경되지 않는다.

make -C <path-to-kernel> M=’pwd’ help: 외부 모듈을 build하는데 필요한 build target들을 설명하는 명령이다.

2.3 사용가능한 option


make -C <path-to-kernel> M=’pwd’ M= 옵션은 kbuild에게 “외부 모듈”이 build되고 있다라는 사실을 알리는 옵션이며 SUBDIRS= 의 backward compatibility도 지원한다.


2.4 모듈 build를 위한 kernel tree 준비하기


외부 모듈을 build하기 위한 정보를 생성하기 위하여 kernel build target인 modules_prepare가 반드시 사용되어야 한다. (CONFIG_MODVERSIONS가 설정되어 있는 경우에도 modules_prepare target은 Module.symvers를 생성하지는 않는다. 조심할 것)


2.5 모듈의 파일 하나씩 build하기


kbuild는 하나의 모듈을 구성하는 각각의 파일들을 따로 build 할 수 있다.

(예)


make -C <path-to-kernel> M=’pwd’ bar.lst

make -C <path-to-kernel> M=’pwd’ bar.o

make -C <path-to-kernel> M=’pwd’ foo.ko

make -C <path-to-kernel> M=’pwd’ /


3. Kbuild/Makefile을 사용한 예제


kbuild system은 linux kernel을 효과적으로 build하기 위한 framework이다. Linux kernel과 밀접한 관련이 있는 kernel module은 다음과 같은 이유때문에 kbuild system을 사용하여야 한다.


전체 build system의 변경사항에 대하여 compatible하기 위하여

gcc등 compilation에 필요한 tool들과 해당 옵션들에 대하여 kernel build와 동일한 규칙을 적용하기 위하여

아래의 file들로 구성되어진 모듈을 compile하기 위하여 Makefile 하나를 생성해 보도록 하자.


8123_if.c

8123_if.h

8123_pci.c

8123_bin.o_shipped <- binary blob


3.1 모듈과 Kernel을 위한 공유 Makefile


외부 모듈은 항상 argument없이 단순한 ‘make’명령만으로 해당 module을 build할수 있는 wrapper Makefile을 포함하여야 한다.

Example 1:

–> filename: Makefile

ifneq ($(KERNELRELEASE),)

# kbuild part of makefile

obj-m  := 8123.o

8123-y := 8123_if.o 8123_pci.o 8123_bin.o

else

# Normal Makefile


KERNELDIR := /lib/modules/`uname -r`/build

all::

$(MAKE) -C $(KERNELDIR) M=`pwd` $@


# Module specific targets

genbin:

echo “X” > 8123_bin.o_shipped

endif


위의 예제에서 KERNELRELEASE 변수는 하나의 Makefile을 두 부분으로 나누는 역할을 수행한다. 위의 예제에서 make utility는 kbuild를 위한 두줄의 선언문만 인식을 못함에 비해 kbuild system은 두 라인의 선언문만 인식할 수 있다. 최근 version의 kernel에서 kbuild system은 먼저 Kbuild를 찾고 두번째 옵션으로 Makefile을 찾도록 되어 있다. Kbuild 파일을 사용하여 위의 예제에서 제공된 Makefile은 아래의 두가지 파일로 분리할 수 있다.


Example 2:

–> filename: Kbuild

obj-m  := 8123.o

8123-y := 8123_if.o 8123_pci.o 8123_bin.o

–> filename: Makefile

KERNELDIR := /lib/modules/`uname -r`/build

all::

$(MAKE) -C $(KERNELDIR) M=`pwd` $@

# Module specific targets

genbin:

echo “X” > 8123_bin.o_shipped


위의 예제에서는 상당히 작은 2개의 파일을 얻을 수 있었다. 그러나, 이렇게 작은 경우의 파일에 대해서 이러한 분리가 과현 실효성이 있는가에 대한 의문을 가질수 있으나, 매우 큰 Makefile의 경우, 이렇게 분리하는 것이 실효성을 가질수도 있다라는 점에 주목하자.

신고

'Programming > Linux/Unix' 카테고리의 다른 글

디바이스 트리 작성법 (2편)  (1) 2015.03.24
디바이스 트리 작성법 (1편)  (0) 2015.03.24
[Linux] Module 관련  (0) 2015.03.13
[Makefile] Kbuild 와 Module Compile  (0) 2015.03.09
[Makefile] Device Driver  (0) 2015.03.09
Makefile 문법 및 관련 내용  (0) 2015.03.09


Posted by injunech