1. 오버뷰Makefile은 몇개의 부분으로 이루어져 있다. 표 1. Makefile의 구성
최상위 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 종류가 있다.
이문서는 일반 개발자나 arch 개발자를 위한 것이다. 그러나 커널 Makefile이 어떻게 동작하는지 아는 것이 좋은 경우가 많다. 단순히 새로운 커널을 컴파일해 설치해 사용하는 사용자가 아니고 시스템 엔지니어라면 커널이 어떻게 만들어지는 알고 있는 것이 도움이 될 때가 많다. 예를 들어 현재 설정에 의해 어떤 모듈이 어떤 파일로 이루어져 있는지 알수 있으면 그 파일들을 조사해 수정하거나 하는 일이 가능하기 때문이다. 3. kbuild Makefiles커널 내의 대부분의 Makefile은 kbuild 인프라 스트럭쳐를 사용한다. 이 장에서는 kbuild makefile들에서 사용되는 문법에 대해 소개한다. 3.1장은 “Goal 정의”에 대한 간단한 소개고 그 이후 장에서 더 자세한 것을 다룰 것이다. 3.1. Goal 정의Goal 정의는 kbuild Makefile의 가장 중요한 부분이다. Goal은 만들어져할 것, 특별한 컴파일 옵션, 사용되야할 하위디렉토리를 정의한다. 가장 간단한 kbuild makefile은 다음과 같은 한 줄을 갖는다.
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) 부팅하는 동안 나타나는 순서대로 불려지기 때문에 링크 순서도 중요하다. 그래서 순서를 바꾸게되면 디스크 등의 드라이버가 사용되는 순서가 바뀌는 등의 일 때문에 디스크의 번호도 바뀔수 있다.
3.3. Loadable module goals(obj-m)$(obj-m)은 적재 가능한 모듈을 만들 때 사용된다. 모듈은 하나의 소스 코드나 여러 개의 소스 코드에서 만들어질 수 있다. 하나의 소스 코드로 만들어지는 경우엔 그냥 $(obj-m)에 더하기만 하면 된다.
만약 커널 모듈이 여러 개의 소스 파일로부터 만들어지면 위에 나온 것과 같은 방식으로 지정하면된다. kbuild는 만들고자하는 모듈이 어느 부분에서 오는지를 알면되고 $(<module_name>-objs)에 지정해 주면 된다.
이 예에서 모듈 이름은 isdn.o이고 kbuild는 $(isdn-objs)안에 있는 오브젝트를 컴파일 한 후에 “$(LD) -r”을 실행해 isdn.o를 만들어낸다. kbuild는 오브젝트를 접미사 -objs와 -y에 의해 만들어지는 복합 오브젝트로 인식할 수 있다. 만약 오브젝트가 복합 오브젝트의 일부라면 Makefile이 CONFIG_ 값을 사용하도록 할 수 있다.
이 예에선 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 둘다 존재할 수도 있다.
이 예제는 checksum.o와 delay.o를 기반으로하는 lib.a를 만든다. 보통 lib-y의 사용은 lib/와 arch/*/lib 디렉토리에 한한다. 3.6. 하위 디렉토리로 내려가기Makefile은 그것이 속한 디렉토리만을 책임진다. 하위 디렉토리에 있는 파일들은 그 하위 디렉토리에 있는 다른 Makefile에 의해 관리된다. 빌드 시스템은 자동적으로 하위 디렉토리를 리커시브하게 부른다. 그렇게 하기 위해서 obj-y와 obj-m이 사용된다. 원하는 디렉토리 이름 뒤에 /를 붙여 이렇게 한다. ext2라는 모듈은 여러 디렉토리에 걸쳐 있고 fs/에 Makefile이 있다. 이 Makefile은 kbuild에게 아래와 같은 할당을 동해 하위 디렉토리로 내려가도록 한다.
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의 모든 실행되는 명령에 적용된다.
CFLAGS_$@, AFLAGS_$@ CFLAGS_$@와 AFLAGS_$@는 현재 kbuild makefile 내의 명령에만 적용된다.
3.8. 의존성 추적kbuild는 다음과 같은 의존성을 추적한다.
그래서 $(CC)에 대한 옵션이 바뀌면 관련된 모든 파일은 재컴파일 된다. 3.9. 특별 규칙특별한 규칙은 kbuild 인프라 스트럭쳐가 필요로 하는 기능을 제공하지 못할 때 사용한다. 대표적인 예가 빌드 동안 생성되는 헤더 파일 같은 것이다. 다른 예는 아키텍쳐에 따라 부트 이미지 등을 준비등에 필요한 특별한 규칙을 필요로 하는 경우다. 특별 규칙은 보통의 make 규칙을 사용해 씌어지고 Makefile이 존재하는 곳에서는 kbuild가 실행되지 않는다. 그래서 모든 특별 규칙은 필요한 파일이나 타겟 파일에 대한 상대 경로(relative path)를 제공해야만 한다. 특별 규칙을 정의할 때 사용되는 두가지의 변수:
4. 호스트 프로그램 지원kbuild는 컴파일 스테이지 동안 사용되는 호스트 상에서 돌아가는 프로그램을 만들기도 한다. 호스트 실행 파일을 만들기 위해선 두 스텝의 절차가 필요하다. 첫번째 스텝은 kbuild에게 호스트 프로그램이 존재한다고 알리는 것이다. 이건 host-prog를 사용해 한다. 두번재 스텝은 실행 파일에 대한 정확한 의존성을 더해주는 것이다. 이것은 규칙에 의존성을 더하거나 $(always) 변수를 사용하는 방법이 있다. 4.1. 간단한 호스트 프로그램때로는 빌드가 실행되는 컴퓨터 상에서 프로그램을 컴파일 하고 실행할 필요가 있다. 아래 예는 kbuild에게 bin2hex를 호스트에서 만들라고 알려준다.
kbuild는 bin2hex가 Makefile과 같은 디렉토리에 있는 bin2hex.c라는 하나의 소스 파일에서 만들어진다고 가정한다. 4.2. 복합적인 호스트 프로그램호스트 프로그램은 여러 개의 오브젝트로 구성될수도 있다. 복합 오브젝트를 정의하는 문법은 커널 오브젝트에 사용된 문법과 비슷하다. $(<executeable>-objs)는 최종 실행 파일을 구성하는 오브젝트를 나타낸다.
.o 확장자를 갖는 오브젝트는 그에 상응하는 .c 파일로 부터 컴파일된다. 위의 예에선 checklist.c가 컴파일 되 checklist.o를 만든다. 최종적으로 두개의 .o 파일이 하나의 실행 파일인 lxdialog로 링크된다. Note: <executable>-y와 같은 문법은 호스트 실행 파일에는 적용되지 않는다. 4.3. 공유 라이브러리 정의.so 확장자를 같는 오브젝트는 공유 라이브러리를 나타내고 위치에 상관 없는 오브젝트로 컴파일 된다. kbuild는 고유 라이브러리를 제공하지만 사용은 제한 되어 있다. 아래 예에서 conf라는 실행 파일을 링크하기 위해 libkconfig.so가 사용된다.
공유 라이브러리는 언제나 그에 상응하는 -objs 를 필요로 한다. 그리고 위 예제에서 libkconfig는 두개의 오브젝트 expr.o와 type.o로부터 만들어진다. expr.o와 type.o는 위치 독립 적인 코드로 만들어지고 libkconfig.so로 링크된다. C++은 공유 라이브러리를 지원하지 않는다. 4.4. 호스트 프로그램에 C++ 사용하기kbuild는 C++로 작성된 호스트 프로그램을 지원한다. 이것은 kconfig를 위해 소개되지만 일반적인 사용에서는 추천하지 않는다.
예제에서 실행 파일은 C++파일인 qconf.cc로 작성되어 있고 $(qconf-cxxobjs)로 정의된다. 만약 qconf가 .c와 .cc 파일로 이뤄져 있다면 이를 구분하기 위해 추가 줄이 더 필요할 수도 있다.
4.5. 호스트 프로그램용 컴파일러 옵션 설정호스트 프로그램을 컴파일 하는 동안에 특별한 플래그가 필요할 수도 있다. 프로그램은 언제나 $(HOSTCC)를 사용해 컴파일 되므로 $(HOSTCFLAGS)를 사용하면 된다. Makefile에의해 만들어지는 모든 호스트 프로그램에 걸쳐 영향을 주는 플래그를 세팅하기 위해선 HOST_EXTRACFLAGS 변수를 사용한다.
한개의 파일 만을 위한 플래그는 아래와 같은 방법으로 한다.
아래 예제는 링커에게 특별한 옵션을 추가 지정해준다.
qconf를 링크할 때 특별 옵션인 “-L$(QTDIR)/lib”이 전달된다. 4.6. 호스트 프로그램이 실제로 만들어질 때kbuild는 호스트 프로그램이 정확하게 미리 지정됐을 경우에만 만든다. 이런 경우는 두가지가 존재할 수 있다.
5. kbuild clean 인프라 스트럭쳐"make clean"은 커널이 컴파일 되는 소스 트리 내에서 생성된(호스트 프로그램 포함) 모든 파일을 지운다. $(host-progs), $(always), $(extra-y)에 지정된 모든 타겟이 지워진다. "*.[oas]", "*.ko"와 kbuild에 의해 만들어진 약간의 추가 파일이 지워진다. 추가 파일은 $(clean-files)에 지정된다.
"make clean"을 실행 하면 두개의 파일 “devlist.h classlist.h”가 지워지고 kbuild는 $(clean-files)에 지정된 이 두 파일을 makefile이 있는 디렉토리에서 찾는다. 보통 kbuild는 “obj-* := dir/”에 의해 하위 디렉토리로 내려가지만 아키텍쳐 별 makefile에서는 이게 충분하지 않아 때로는 정확하게 지정해야할 필요가 있다.
위의 예제는 “make clean”이 실행될 때 compressed/ 디렉토리로 내려가서 지우란 것을 가르쳐주고 있다. 최종 부트 이미지를 만드는 Makefile에서 지우기를 지원하기 위해선 archclean:이란 이름의 타겟을 사용한다.
"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가 실행될 때 대략 다음과 같은 절차를 거친다.
6.1. 아키텍쳐 빌드를 수정하기 위한 변수 세팅
6.2. Add prerequisites to prepareThe prepare: 하위 디렉토리로 내려가기 전에 미리 지정된 리스트를 만들기 위해 사용되는 규칙을 준비한다. 이것은 보통 어셈블러 상수를 담고 있는 헤더파일이다.
이 예에서 include/asm-$(ARCH)/offsets.h는 하위 디렉토리로 내려가기 전에 만들어진다. kbuild가 offset header 파일을 만드는 것은 다른 장을 참조하기 바란다. 6.3. List directories to visit when descending아키텍쳐 Makefile은 vmlinux를 어떻게 만드는지 지정하기 위해 최상위 Makefile과 같이 협조한다. 모듈에 대해선 아키텍져 별로 특별히 구분하는 것이 없다. 즉 모듈을 만드는 것은 아키텍쳐에 독립적이다.
6.4. Architecture specific boot imagesarch Makefile은 vmlinux 파일을 만들고 압축하고 부트스랩핑 코드로 감싸고 해서 결과를 어딘가에 저장하는 일을 담당한다. 이것은 여러 종류의 설치 명령을 포함한다. 실제 목표는 아키텍쳐 마다 다르기 때문에 표준화 되어 있진 않다. 보통 arch/$(ARCH)/ 밑에 있는 boot/ 디렉토리에서 여러 프로세싱이 실행된다. kbuild는 boot/내에 있는 타겟을 만들기 위한 방법을 제공하지 않는다. 그래서 arch/$(ARCH)/Makefile은 boot/에 있는 타겟을 빌드하기 위해 make를 매뉴얼로 실행한다. 추천된 접근 방법은 arch/$(ARCH)/Makefile에 숏컷을 포함시키고 arch/$(ARCH)/boot/Makefile로 내려갈 때 전체 패스를 사용하도록 하는 것이다.
"$(Q)$(MAKE) $(build)=<dir>"은 하위 디렉토리에서 make를 실행하는 방법이 좋다. 아키텍쳐에 따른 타겟의 이름을 정하는데는 규칙이 없다. 그러나 “make help”를 실행할 때 관계된 모든 타겟을 출려해줘야한다. 이를 지원하기 위해선 $(archhelp)가 반드시 정의되어 있어야한다.
Make를 아규먼트 없이 실행했을 땐 첫번째 목표가 만들어 진다. 최상위 Makefile에서 첫번째 목표는 all: 이다. 일반적으론 부트 가능한 이미지를 만들도록 되어 있다. "make help"를 하면 나오는 리스트에서 기본 목표가 '*'로 구분되어 있다.
6.5. Building non-kbuild targetsextra-y는 obj-*에 의해 지정된 타겟 말고 현재 디렉토리에서 만들어지는 추가 타겟을 지정한다. extra-y에 모든 타겟을 열거하는 것은 다음과 같은 두가지 목적이 필요하기 때문이다.
이 예제에선 extra-y가 만들어지긴 하지만 built-in.o의 부분으로 링크되지는 않는 것을 열거하고 있다. 6.6. Commands useful for building a boot imagekbuild는 부트 이미지를 만드는데 유용한 몇 가지의 매크로를 제공한다.
6.7. Custom kbuild commandsKBUILD_VERBOSE=0인 상태로 kbuild가 실행되면 화면엔 약식의 표시만된다. 이런 모양의 커스텀 커맨드를 가능하게 하기위해선 두변수를 세팅할 필요가 있다. quiet_cmd_<command> - 무엇이 출력될 것인가? cmd_<command> - 실행될 커맨드
$(obj)/bzImage 타겟 라인을 업데이트할 때 BUILD arch/i386/boot/bzImage는 "make KBUILD_VERBOSE=0"을 출력할 것이다. 7. kbuild Variables최상위 Makefile은 다음과 같은 변수를 export한다.
8. Makefile language커널 Makefile은 GNU Make와 동작하도록 만들어져 있다. Makefile 들은 GNU Make의 문서에 나온 것들만을 사용하지만 GNU 확장도 많이 사용한다. GNU Make는 함수를 처리하는 기본 리스트를 제공한다. 커널 Makefile 들은 약간의 “if” 문장으로 만들어지거나 유지될 리스트에 대한 novel style을 사용한다. GNU Makef는 두 가지의 할당 연산자를 사용한다. “:=”은 오른 편의 값을 바로 계산하고 왼편으로 대입한다. “=”는 공식 정의와 비슷해서 오른 편의 값을 계산하지 않고 왼편의 값이 사용될 때 마다 계산한다. 여러 경우에서 “=”이 적당하다. 그럼에도 불구하고 “:=”이 올바른 선택이다. 9. CreditsOriginal 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 |











