yoncho`s blog

5. Custom Layer | 레이어 생성을 위해 필요한 과정 본문

기술, 나의 공부를 공유합니다./[Vehicle] Yocto

5. Custom Layer | 레이어 생성을 위해 필요한 과정

욘초 2024. 6. 23. 15:15

 

이번 글에서는 새로운 레이어를 만들어 보는 과정을 설명하겠다. 
앞서 설명드렸다시피 Poky 구조에서 개발자들이 개발에 관여하는 큰 부분은 Custom Layer이다. 

이 과정에서는 bitbake 문법(.conf 파일에 작성되는 것들 위주)을 이해하고 

새로운 Layer 생성과 관련된 필요 부분을 배우게 된다.

 

#목차

1. 5장 환경 구성

2. Bitbake 문법 

3. Hello application recipe 작성

4. License, 라이선스

5. 레피시 확장 파일 (.bbappend)

6. Layer.conf의 BBFILE_COLLECTIONS, BBFILE_PATTERN 변수 

7. 최종

 

[1] 5장 환경 구성

5장 진행을 위해 새로운 레이어를 만들어놓겠다.

 

I. meta-hello 레이어추가

poky/ 디렉터리 아래 meta-hello/ 디렉터리를 만들어준다.

poky에서 meta-xxx가 레이어 명칭으로 xxx가 layer 이름이다.

 

II. meta-hello/ 아래 필요 디렉터리 생성

meta-hello/ 디렉터리 아래 conf/ 와 recipes-hello/ 디렉터리를 만들어준다.

 

III. conf/ 디렉터리 아래 layer.conf 파일을 생성하고 아래 내용을 추가한다.

BBPATH                          =. "${LAYERDIR}:"
BBFILES                         += "${LAYERDIR}/recipes*/*.bb"
BBFILE_COLLECTIONS              += "hello"
BBFILE_PATTERN_hello            = "^${LAYERDIR}/"
BBFILE_PRIORITY_hello           = "10"
LAYERSERIES_COMPAT_hello        = "${LAYERSERIES_COMPAT_core}"
GLOBAL_VAR                      = "global var"

 

IV. recipes-hello/ 디렉터리 아래 hello.bb 레시피 파일을 생성하고 아래 내용을 추가한다.

DESCRIPTION = "Simple Hello World"
LICENSE = "CLOSED"

do_printhello(){
	bbwarn "hello world!"
}

addtask do_printhello after do_compile before do_install

레시피에는 정보 제공을 위해 아래 명령어들을 사용할 수 있다.

(a) SUMMARY : 패키지 간단 소개 (1줄, 최대 80자)

(b) DESCRIPTION : 패지키 자세한 설명 

(c) AUTHOR : 패키지 저자 명/ 이메일 주소  (Ex: yoncho <yoncho@pxxxxxxx.com>)

(d) HOMEPAGE : 'http://'로 시작하는 URL - 패키지 제공 하는 곳

(e) BUGTRACKER : 'http://'로 시작하는 URL - 프로젝트 버그 추적 시스템 주소

 

추가로 bbwarn이라는 지시어는 로그 출력 함수인데. python과 shell 에 따라 살짝 다르다.

아래 로그 표가 그에 해당하며 plain => fatal 로 갈 수록 위험도가 높은 것이다.
참고로 fatal 함수로 로그 출력 시 bitbake가 빌드를 멈추기 때문에 주의가 필요하다.

Log Level python function shell function
plain bb.plain(msg) bbplain msg
debug bb.debug(msg) bbdebug level msg
note bb.note(msg) bbnote msg
warn bb.warn(msg) bbwarn msg
error bb.error(msg) bberror msg
fatal bb.fatal (msg) bbfatal msg

 

위 I~IV까지 진행했다면 meta-hello/ 디렉터리 구조는 아래와 같다.

meta-hello/
|--conf/
|	|--layer.conf
|--recipes-hello/
	|--hello.bb

 

V. bblayer.conf 파일에 새롭게 만든 hello layer 경로 추가

새롭게 만든 hello Layer를 Bitbake가 빌드시 찾을 수 있게 bblayer.conf 파일에 경로를 추가해준다.

 

# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
  /home/yoncho/poky_src/poky/meta \
  /home/yoncho/poky_src/poky/meta-poky \
  /home/yoncho/poky_src/poky/meta-yocto-bsp \
  /home/yoncho/poky_src/poky/meta-hello \
  "

기존 내용에서 BBLAYERS 변수에 meta-hello를 추가해줬다.

 

VI. 실행 결과

새롭게 만든 Layer 테스트를 위해 아래 실행 명령어와 그 결과이다.

#명령어
bitbake hello

#결과
...
WARNINGl hello-1.0-r0 do_printhello: hello world!
...

추가로 bitbake 명령어로 현재 layer들을 보고 싶다면 아래가 명령어와 그 결과이다.

#명령어
bitbake-layers show-layers

#결과
NOTE: Starting bitbake server...
layer                 path                                      priority
==========================================================================
meta                  /home/yoncho/poky_src/poky/meta           5
meta-poky             /home/yoncho/poky_src/poky/meta-poky      5
meta-yocto-bsp        /home/yoncho/poky_src/poky/meta-yocto-bsp  5
meta-hello            /home/yoncho/poky_src/poky/meta-hello     10

 

 

[2] Bitbake 문법 

 

I. 변수의 범위

앞서 설명했듯 Bitbake에서는 *환경변수 파일에 선언한 변수는 전역 변수다.

A레시피에서 선언한 변수는 B레시피 안에서만 사용할 수 없고,

레시피 전역 변수는 Task 안에서 값 변경을 해도 해당 Task 안에서만 유효하며 다른 Task나 전역변수 자체가 변경되지 않는다.

 

II. DEFENDS 지시어 - recipe file

레시피 파일 간의 의존성 설정, DEFENDS(<recipe_name>)일 경우 

<recipe_name>이 먼저 빌드 돼야 한다는 뜻이다.

 

III. '?=' 기본값 할당 - recipe file

'?='는 기본 값 할당하는 명령어이다. 

#변수 
A_VAR ?= "A"
B_BAR ?= "B"
B_BAR ?= "C"
C_BAR ?= "D"
C_BAR = "E"

#처리결과
A_VAR = "A"
B_BAR = "B"
C_BAR = "E"

위 예제는 변수를 설정했을 시 그에 대한 결과 내용으로

*동일한 변수에 대해 '?=' 기본값을 수행했을 시 최초 적용된 기본값으로 설정된다.

*'?='는 기본값임을 잊지말자, 동일한 변수에 '=' 값할당 연사자가 적용되면 해당 값으로 적용된다.

 

IV. '??=' 약한 기본값 할당 - recipe file

'??='는 '?=' 보다 약한 기본값 할당 명령어이다.

#변수 
A_VAR ??= "A"
B_BAR ??= "B"
B_BAR ??= "C"
C_BAR ??= "D"
C_BAR ?= "E"
D_BAR ??= "F"
C_BAR = "G"

#처리결과
A_VAR = "A"
B_BAR = "C"
C_BAR = "E"
D_BAR = "G"

위 예제는 변수를 설정했을 시 그에 대한 결과 내용으로

*동일한 변수에 대해 '??=' 약한 기본값을 수행했을 시 마지막 적용된 기본값으로 설정된다.

*'??='보다 '?='가 우선순위 높아서 '?=' 기본값이 적용된다.

 

V. 변수 확장 - recipe file

#확장
VAR1 = "HELLO"
VAR2 = "${VAR1} WORLD"

#사용
bbwarn "VAR2 : ${VAR2}"

#결과
VAR2 : HELLO WORLD

변수를 다른 변수 내에서 참조할 수 있다. 문법은 ${<variable_name>} 이다.

 

VI. ':=' 즉시 변수 확장 - recipe file

':='는 할당 즉시 확장된다. 정확히는 ':=' 연산자 사용 시점에 변수에 값이 할당되는 것이다.

#즉시확장
VAR1 = "HELLO"
VAR2 = "${VAR1} WORLD"
VAR1 = "YONCHO"
VAR4 := "${VAR2}"

#사용
bbwarn "VAR4 : ${VAR4}"

#결과
VAR4 : YONCHO WORLD

위 예제를 보면 결과가 "HELLO WORLD" 일 줄 알았으나 "YONCHO WORLD"이다.
이유는 VAR4가 실행되기 VAR1이 "HELLO"에서 "YONCHO"로 변경되었다.

만약 VAR4의 연산자가 "=" 였다면 "HELLO WORLD" 였을 것이다.

 

VII. '+=' / '=+'  공백있는 후입/선입 - recipe file

개발자라면 흔히 알고 있을 연산자지만 Bitbake에서 살짝 다르다.

Bitbake의 모든 변수는 String으로 연산자 '+=' or '=+'를 사용할 경우

변수에 공백을 한칸 두고 값을 추가한다.

#공백있는 후입,선입
VAR1 = "12"
VAR1 += "34"
VAR1 =+ "0"

#사용
bbwarn "VAR1 : ${VAR1}"

#결과
VAR1 : 0 12 34

 

 

VIII. '.=' / '=.'  공백없는 후입/선입 - recipe file

'+=' / '=+' 연산자는 두 변수 사이에 공백을 넣기 때문에 

공백없이 두 변수를 합치려면 '.=' / '=.' 를 사용해야한다.

#공백없는 후입,선입
VAR1 = "12"
VAR1 .= "34"
VAR1 =. "0"

#사용
bbwarn "VAR1 : ${VAR1}"

#결과
VAR1 : 01234

 

 

IX. '_append' / '_prepend'  공백없는 선입/후입 - recipe file

'.=' / '=.' 과 마찬가지로 공백 없이 추가하는 연산자이다.

#공백없는 후입,선입
VAR1 = "12"
VAR1_append = "34"
VAR1_prepend = "0"

#사용
bbwarn "VAR1 : ${VAR1}"

#결과
VAR1 : 01234

 

위 변수는 보통 코드에서 'SRC_URI_append = xxx' 와 같은 형태로 쓰인다. 

*SRC_URI_append += "xxxx" 의 경우 SRC_URI에 공백을 넣고 변수를 추가하겠다는 것이다.

=> 이렇게 사용하는 이유가 SRC_URI_append = " xxx" 식으로 공백을 추가하려는 값 앞에 미리 넣어 놓는 경우가 있다. 

그래서 보통 사람들이 특정 경우에 _append와 +=을 함께 사용한다.

*참고로 Yocto Honister 버전 이상 부터는 _append가 아니라 :append로 바뀌었다. ( _ => : )

 

X. '_remove' 삭제 - recipe file

변수에서 특정 값을 제거하려고 할때 사용하며, 주의할 점은 공백으로 분리된 값만 제거된다.

#공백없는 후입,선입
VAR1 = "123 45 1234 1236"
VAR1_remove = "123"

#사용
bbwarn "VAR1 : ${VAR1}"

#결과
VAR1 : "45 1234 1236"

공백으로 구분 되어있어야 인식한다..!!

*참고로 Yocto Honister 버전 이상 부터는 _remove 가 아니라 : remove 로 바뀌었다. ( _ => : )

 

XI. 함수의 선입/후입

Bitbake는 실행 가능한 함수도 변수와 동일하게 취급하기 때문에 함수도 선입/후입이 가능하다.

#공백없는 후입,선입
do_printhello(){ bbwarn "hello" }
do_printhello_prepend(){ bbwarn "prepend" }
do_printhello_append(){ bbwarn "append" }

#결과
prepend
hello
append

 

 

XII. 연산자 우선 순위

bitbake에서 연산자 우선 순위를 아래와 같다.

<metadata> 
=> =,:=,?=,??=,+=,=+,.=,=.
=> _append, _prepend, _remove 
=> <final_value>

적용 순위 예시는 아래와 같다.

#변수
V = "1"
V_append = "2"
V_prepend = "3"
V += "4"
V .= "5"

#결과
1 4523

 

 

[3] Hello application recipe 작성

이제 본격적으로 나만의 레시피 작성을 해볼 것이다.

목차 1에서 구성한 meta-hello 레이어 진행하겠다.

 

I. recipes-hello/ 디렉터리 아래 source/ 디렉터리 생성 후 hello.c 파일 작업

#source/ 디렉터리 생성
mkdir source
cd source

#hello.c 생성 및 작업
vi hello.c

--hello.c 내용--
#include <stdio.h>
#include <unistd.h>

int main(){

        int i = 0;
        while (i < 10){
                printf("hello world!\n");
                sleep(1);
        }
        return 0;
}

 

II. recipes-hello/ 디렉터리 아래 source/ 디렉터리 아래 COPYING 파일 작업

EXAMPLE LICENSE FILE
                January 2024
Copyright (C) 2024, YONCHO.Com
This is example license file

새로운 레시피 파일이 생성되면 그에 대한 적절할 라이선스와 설명 파일에 대한 checksum을 지정하는 것이 필수다.

 

III. hello.c 실행을 위한 recipes-hello/ 디렉터리 아래 hello.bb 파일 수정 작업

DESCRIPTION = "Simple Hello World"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://COPYING;md5=fc535da43eabb329160c3db56b2d9e7e"

SRC_URI = "file://hello.c"
SRC_URI_append = " file://COPYING"
S = "${WORKDIR}"

do_compile(){
        ${CC} hello.c ${LDFLAGS} -o hello
}

do_install(){
        install -d ${D}${bindir}
        install -m 0755 hello ${D}${bindir}
}

FILESEXTRAPATHS_prepend := "${THISDIR}/source:"
FILE_${PN} += "${bindir}/hello"

SRC_URI : 'file://'은 Local file을 사용하는 페처를 의미한다. 

FILESEXTRAPATHS_prepend : "${THISDIR}/source:" 는 파일의 상대 경로를 얻기 위해 필요한 작업으로

THISDIR은 레시피 파일 위치 절대 경로 값이며, 여기서 recipe-hello 디렉터리 경로를 가지고있다.

FILESEXTRAPATHS변수는 FILESPATH를 확장하며 'poky/meta/classes/base.bbclass'에 정의되어있다.

 

bitbake는 SRC_URI에 추가한 파일, 패치를 FILESPATH 변수에 있는 경로에서 찾는다. 그래서 새로 추가되는 경로는 

반드시 FILESPATH 변수에 추가되어야한다. 이때 FILESEXTRAPATHS는 FILESPATH를 확장시켜주기 때문에

FILESEXTRAPATHS 변수에 추가해주면 된다.

본 예제는 위 방법대로 안하고 호스트 로컬에서 찾을 수 있게 "file://" 변수로 SRC_URI에 적용해놨다.

 

페처가 하는 일은 hello.c를 FILESPATH에 저장된 경로에서 찾아 S변수에 지정된 경로로 복사한다.

 S변수는 WORKDIR 값이 있는데 이건 bitbake가 레시피 빌드시 생성된 각종 정보를 저장하는 디렉터리 경로이다.

 

LICENSE: 변수가 "CLOSED" 가 아니라면 별도로 LICENSE 파일 LICENSE checksum 값을 가지고 있어야한다.

앞서 만든 COPYING이라는 파일을 사용할 것이기 때문에 SRC_URI에 COPYING파일을 추가했다. 

라이선스 파일에 대해 checksum 값을 계산해야하는데 보통 md5sum 혹은 sha256sum을 사용한다.

우리는 md5sum을 사용해 COPYING 파일에 대한 checksum 값을 아래 명령어로 계산했다.

#명령어
md5sum COPYING

#결과
fc535da43eabb329160c3db56b2d9e7e  COPYING

checksum값을 LIC_FILES_CHKSUM 변수에 위 예제 처럼 형태에 맞춰 주면 된다. 

 

do_compile()과 do_install()은 base.bbclass에 정의되어있고 hello.bb에서 재정의한 것이다.

do_install()에서 "install -d ${D}${bindir}"는 ${D}${bindir} 디렉터리를 만들겠다는 shell 명령어이고,

${D}는 빌드 결과물로 생성된 바이너리가 위치하는 경로이고, ${bindir}은 /usr/bin을 뜻하는 사전 정의 디렉터리 이름이다.

"install -m 0755 hello ${D}${bindir}"은 hello파일의 실행권한을 0755로 주고 ${D}${bindir} 경로로 복사하겠다는 뜻이다.

 

아래는 사정 정의된 디렉터리 변수들이다.

variable name to_directory
bindir /usr/bin
sbindir /usr/sbin
libdir /usr/lib
libexecdir /usr/lib
sysconfdir /etc
datadir /usr/share
mandir /usr/share/man
includedir /usr/include

 

install Task는 바이너리, 라이브러리, 헤더파일, 문서 들을 타깃 시스템의 루트파일 시스템과 같은 구조를 갖는 변수 D가 가리키는 디렉터리에 복사한다. 

변수 D가 가리키는 디렉터리를 ${WORKDIR}/image 이고 보통 프로그램 파일들은

사용자 프로그램은 /usr/bin, 시스템관리 프로그램은 /usr/sbin, 라이브러리 /usr/lib, 환경 설정 파일 /etc 에 저장된다.

 

+ 번외: 현재 파일 구조

meta-hello/
|--conf/
|	|--layer.conf
|--recipes-hello/
	|--hello.bb
    |--source/
    	|--hello.c
        |--COPYING

 

 

IV. 최종

위 I~III 까지 진행했다면 아래 명령어를 실행해 결과를 보자

#명령어
bitbake hello -c cleanall
bitbake hello

#결과
--

여기서 -c 옵션은 cleanall Task만 실행하라는 명령어이다.

 

bitbake의 기본 Task는 build Task로 실존하는건 아니고 Task Chain상에서 젤 마지막에 실행되며

BB_DEFAULT_TASK 변수가 기본 태스크를 나타낸다. 

bitbake에서 build Task를 실행한다는건 빌드를 끝까지 진행하라는 것이다.

 

위 명령어를 실행하면 아무일도 일어나지 않는다!! 

왜냐하면 지금 타깃 시스템에서만 동작한다.. 그래서 우리는 hello Application Binary를 루트파일 시스템 (rootfs)에 포함시켜야한다. 이 방법은 목차 4. 레시피 확장 파일에서 진행할 것이다.

 

아래 그림은 각 Task 실행 시 결과물들이 저장되는 디렉터리를 정리한 것이다.

 

 

[4] License, 라이선스

오픈소스 라이선스는 크게 GPL, BSD 두가지이다.

*GPL : 라이브러리와 링크된 모든 소스 코드를 공개해야한다.

 

Yocto에서 라이선스와 관련된 두가지 중요 변수는 아래와 같다.

I. LICENSE : 모든 레시피는 레시피에 사용된 S/W 패키지에 대한 라이선스 목록을 LICENSE 변수에 할당해야한다.

값이 "CLOSED"가 아니라면 해당 레시피는 라이선스가 있다는 뜻이고 라이선스 파일과 LIC_FILES_CHKSUM 변수에 checksum 값을 기술해야한다. 

II. LIC_FILES_CHKSUM :  라이선스파일과 checksum 값을 가지고 있는 변수, checksum은 보통 md5 / sha256을 사용

 

#라이선스를 제공 받는 방법 세가지

I. oe-core에서 제공해주는 라이선스

meta/files/common-licenses 디렉터리에는 공통으로 사용할 수 있는 라이선스가 모여있고, 이 디렉터리 경로를 가리키는 변수는 COMMON_LICENSE_DIR이다.

II. 라이선스를 갖고있는 OpenSource 사용

III. 자체적으로 라이선스 부여
*II. III 모두 같은 방법으로 라이선스 작업을 한다.
보통 OpenSource의 경우 디렉터리 최상단에 COPYING, LICENSE 파일이 존재한다. 

SRC_URI에 LICENSE 파일을 추가해주고, 각 파일에 대한 checksum값을 아래 방법과 같이 제공해줘야한다.

SRC_URI = "file://hello.c;name=hello \
		   http://yonch.org/downloads/y_package.tar.gz;name=yoncho_package \
           "
SRC_URI[hello.md5sum] = "1fsadfasdwerqwdasf"
SRC_URI[yoncho_package.md5sum] = "asdfasqwrqwsdfasdf1231dsfa"

SRC_URI 가 한개 이상의 파일을 넣게 될 경우 ';name=xxxxx'을 뒤에 붙여 구분할 수 있다.

 

빌드가 완료된 레시피 라이선스 정보는 build/tmp/deploy/licenses 디렉터리에서 확인할 수 있다.

yoncho@Desktop_yoncho:~/poky_src/build/tmp/deploy/licenses/core-image-minimal-qemux86-64-20240623043828$ ls
image_license.manifest  license.manifest  package.manifest

위 구성은 미리 빌드해본 이미지에 대한 라이선스 폴더로 package.manifest에는 최종 이미지를 포함한 패키지 이름을 가지고있고, license.manifest에는 패키지 이름, 버전, 레시피이름, 라이선스 내용 등을 포함하고있다.

 

 

[5] 레피시 확장 파일 (.bbappend)

목차 4. 에서 마지막에 실행한 결과가 아무것도 표시되지 않았을 것이다.

그 이유는 앞서 설명했지만 타깃 시스템에서만 동작하기 때문이다..!!

그리고 여기서 우리가 놓친건 생성된 파일이 타깃 시스템에서 동작하려면 

생성된 실행 파일이 루트파일시스템(rootfs)에 포함돼야한다!!! (중요!!)

 

실행 파일을 rootfs에 추가하려면 IMAGE_INSTALL변수에 추가해야한다. 

실제 IMAGE_INSTALL변수에는 패키지 이름이 추가되지만 여기선 레시피 이름이라 해도 무방하다.

 

IMAGE_INSTALL 변수는 rootfs 이미지를 생성하는 레시피 core-image-minimal.bb 파일 내에서만 사용해야한다.

core-image-minimal.bb는 poky/meta/ 디렉터리에 존재한다. 하지만 이 파일 내용을 직접 수정하는거는 좋지 않다. 

=> 원래 대부분의 작업은 origin 파일을 직접 건드리는건 좋지 않다... 갠적인 생각

 

우리는 그래서 레시피 확장 파일을 사용해 IMAGE_INSTALL에 변수를 추가해줄 것이다.

레시피 확장 파일은 .bbappend 확장자를 가지며 특정 레이어의 레시피를 현재 혹은 다른 레이어에 추가/수정이 필요할 때 원래 레시피 파일을 건드리지않고 추가/ 수정할 수 있는 방법이다.

 

Yocto의 규약에서 레이어 이름을 짓는건 meta-xxxx 형식이다. 여기서 xxxx가 레이어 이름이다.

레이어에는 메타데이터가 있고, 레이어 간의 우선순위가 존재한다.

**서로 다른 레이어에 동일한 이름의 레이어가 있다면 우선순위가 높은 레이어가 실행된다. 이걸 우린 재정의(override)라 하며 이부분을 꼭 기억하자!!

 

어떤 레시피 파일을 원본 파일 수정 없이 수정하고 싶다면 다른 레이어를 만들고 해당 레이어에 수정하려는 레시피의 확장 파일(.bbappend)를 만들면 된다. 단, 레시피 확장 파일을 가진 레이어가 원본 레이어보다 우선순위가 높아야한다.

아래 그림은 레이어 우선순위에 따른 레시피 재정의 및 최종 결과이다.

(참고 : https://www.dornerworks.com/blog/building-linux-with-the-yocto-project-is-it-really-worth-the-trouble/)

아래는 하나의 레시피 파일이 우선순위 레이어의 레시피 확장파일들을 거쳐 최종 적용된 모습이다.

 

 

우리가 진행하는 예제에도 레시피 확장 파일에 hello 실행 파일을 추가해 타깃 시스템에서 동작할 수 있게 해보자.

#레시피 확장으로 rootfs에 hello 실행 파일 올리기

I. meta-hello/ 디렉터리 아래에 recipes-core/images/ 디렉터리 생성하기

mkdir -p recipes-core/images

 

II. recipes-core/images/ 디렉터리 아래에 core-image-minimal.bbappend 파일 생성 후 작업하기

#경로 이동
cd poky/meta-hello/recipes-core/images

#파일 생성 및 작업
vi core-image-minimal.bbappend

---core-image-minimal.bbappend 내용---
IMAGE_INSTALL_append = " hello"

새로운 레시피 확장 파일을 만들었다. 그러나 아직 Bitbake가 해당 경로를 알지 못 해서 레시피 확장 파일을 실행시키지 못 할 것이다.

아래 과정을 통해 Bitbake에게 레시피 확장 파일을 알려주자.

 

III. layer.conf파일의 BBFILES 변수에 레시피 확장 파일 경로를 추가하기

conf/ 디렉터리 아래 layer.conf 파일에 아래 내용을 작업한다.

BBPATH                          =. "${LAYERDIR}:"
BBFILES                         += "${LAYERDIR}/recipes*/*.bb \
                                    ${LAYERDIR}/recipes*/*/*.bbappend"
BBFILE_COLLECTIONS              += "hello"
BBFILE_PATTERN_hello            = "^${LAYERDIR}/"
BBFILE_PRIORITY_hello           = "10"
LAYERSERIES_COMPAT_hello        = "${LAYERSERIES_COMPAT_core}"
GLOBAL_VAR                      = "global var"

BBFILES에 recipes*하위 *모든것 하위에서 확장자가 bbappend인것을 찾으라는 경로를 추가했다.

이러면 Bitbake가 빌드시 해당 경로를 보고 레시피 확장 파일 작업을 진행할 수 있다.

 

IV. 최종

I~III 단계에서 진행한 것으로 준비가 끝났으니 루트 파일 시스템을 새로 생성해보자. 

#초기화 및 빌드
bitbake hello -c cleanall && bitbake hello
#루트파일시스템만 빌드
bitbake core-image-minimal -C rootfs

위 명령을 통해 core-image-minimal rootfs에 hello 실행 파일이 추가됨을 확인하려면

pocy_src/build/tmp/work/qemu .../core-image-minimal/1.0-r0/rootfs/usr/bin 디렉터리 아래 가면 확인할 수 있다.

 

#QEMU 실행을 통해 hello 실행파일 확인

I. qumu 실행

runqemu core-image-minimal nographic

실행 하면 아래와 같이 가상 타깃 시스템이 실행되고 login id로 'root'를 입력해준다.

 

II. hello 실행파일 실행해서 확인

#가상 타깃 머신 - 명령어 hello 실행
root@qemux86-64:~# hello

#결과
hello world!
hello world!
hello world!
hello world!
hello world!

위 결과를 보니 정상적으로 동작한다.

여기서 중요한 점은 bitbake는 실제 빌드시 레시피 확장 파일을 별도로 인식하지않고 원본 파일에 레시피 확장 파일 내용을 반영해 하나의 파일로 인식하게 한다.

 

III. 빌드 결과에서 레시피 확장 파일이 원본에 적용된 내용 확인

빌드 결과에 대해 여러 레이어에서 사용된 메타데이터를 단일 계층 디렉터리로 생성하는 명령어

'bitbake-layers flatten <결과 저장 디렉터리 명>' 으로 진행해보자.

#명령어
bitbake-layers flatten result_recipes

#결과
result_recipies/ 
|--recipes-core/
|	|--images/
|	|	|-- core-image-minimal.bb
|	|	...
|	...
...

result_recipes/images/ 디렉터리 아래 core-image-minimal.bb를 확인해보면 아래와 같이 확인할 수 있다.

SUMMARY = "A small image just capable of allowing a device to boot."

IMAGE_INSTALL = "packagegroup-core-boot ${CORE_IMAGE_EXTRA_INSTALL}"

IMAGE_LINGUAS = " "

LICENSE = "MIT"

inherit core-image

IMAGE_ROOTFS_SIZE ?= "8192"
IMAGE_ROOTFS_EXTRA_SPACE_append = "${@bb.utils.contains("DISTRO_FEATURES", "systemd", " + 4096", "" ,d)}"

##### bbappended from meta-hello #####
IMAGE_INSTALL_append = " hello"

 

위 작업을 끝으로 우리가 직접 생성한 Layer의 특정 실행 파일을 만들어보고 타깃 시스템에도 동작시켜보기까지 했다.

여기서 중요한 부분은 Layer 생성 방법과 rootfs에 실행파일 추가 방법일 것 같다.

 

 

[6] Layer.conf의 BBFILE_COLLECTIONS, BBFILE_PATTERN 변수 

layer.conf 파일에서 사용하는 두 변수를 설명할려고 한다.

I. BBFILE_COLLECTIONS : 

해당 변수에는 현재 레이어의 이름이 할당된다.

II. BBFILE_PATTERN :

해당 변수에는 bitbake가 빌드시 특정 레이어에 포함된 레시피 파일들(.bb, .bbappend)을 검색하는데 사용되는 정규식으로 레이어 최상위 디렉터리 이름이 할당된다.

 

bitbake는 파싱 단계에서 각각의 레이어에 속하는 레시피 및 레시피 확장 파일을 별도로 모아둔다. 

이렇게 하는 이유는 레이어마다 우선순위가 존재하기 때문에 혹시라도 레시피 이름이 동일한게 있다면 레이어의 우선순위로 실행 여부를 확인해야하기 때문이다.

 

bitbake는 BBFILE_COLLECTIONS 변수에서 특정 레이어 이름을 가져온다. 

특정 레이어에 속한 레시피를 찾아내려고 BBFILES 변수에 저장된 경로를 참조하는데. 현재 작업 진행 레이어에 속한 경로만 필터링하는데 이때 사용되는게 BBFILE_PATTERN 변수다.

BBFILE_PATTERN변수는 각각의 레이어에 속한 layer.con 파일에서 "^${LAYERDIR}" 값을 가지고 있고, 여기서 LAYERDIR은 레이어의 최상단 디렉터리 경로를 말한다. 

 

따라서 특정 레이어에 속한 파일을 찾고자 할때 BBFILE_PATTERN 변수에 저장된 정규식 즉, 특정 레이어의 디렉터리 경로를 가지고 BBFILES변수에서 찾는것이다.

 

아래 그림은 Poky를 사용할 때 Bitbake의 실행 과정이다.

#Poky`s Bitbake Process

I. 'source poky/oe-init-build-env' 빌드 환경 초기화 스크립트를 실행

=> 이때 build/conf/ 디렉터리가 생성된다.

=> BBPATH 변수에 생성된 build/ 디렉터리 절대 경로 할당

 

II. bitbake는 BBPATH에 저장된 build/ 디렉터리 절대 경로를 가지고 build/conf/ 디렉터리 아래 bblayer.conf 파일을 찾는다.

=> bblayer.conf 파일에는 사용되는 레이어들의 경로들이 BBLAYERS변수에 할당되어있다.

 

III. bitbake는 BBLAYERS변수에 할당된 각각의 레이어 경로에서 conf/ 디렉터리 아래 layer.conf 파일을 찾는다.

=> bitbake는 각 레이어의 layer.conf 파일에서 레이어 이름, 버전, 의존성을 파악한다.

=> bitbake는 각 레이어의 layer.conf 파일의 BBFILES 변수를 통해 레시피 파일 위치와 목록을 확인한다.

 

IV. bitbake는 meta/conf/ 디렉터리 아래 bitbake.conf 파일을 찾는다.

=> bitbake.conf 파일은 기본적인 환경 변수를 선언 및 정의한다.

=> local.conf 파일을 비롯 중요한 환경 설정 파일이 bitbake.conf 파일을 통해 include 된다.

 

V. bitbake는 BBPATH변수에 저장된 경로들 아래 classes/ 디렉터리에서 클래스 파일을 찾아 분석한다.

=> base.bbclass 파일은 항상 포함(필수 클래스), 나머지 추가 클래스파일은 앞단계 환경 설정 파일에서 INHERIT 지시어를 통해 추가된 클래스 파일들을 대상으로 한다.

 

VI. bitbake는 BBFILES변수에 지정된 경로의 각 레시피파일을 분석 및 다영한 변수 값을 저장한다.

=> 이과정에서 각 레시피 파일에 대해 환경 설정 파일에서 변수, 기본 클래스들을 통한 변수 및 태스크가 추가된다.

=> 레시피 파일 자체의 데이터와 레시피 파일에 포함될 수 있는 상속 클래스 파일의 변수 및 태스크가 추가된다.

 

 

[7] 최종

본 글에선 앞서 배운 내용들과 이번 글을 통해 배운 내용으로 새로운 레이어를 만들고 직접 만든 실행 파일을 타깃 시스템에서 동작시켜보기 까지 했다.

기본적인 bitbake 문법을 통해 layer.con와 bblayers.conf 파일 내용을 보다 더 자세히 알게되었다.

새로운 레시피를 만들고 해당 레시피의 라이선스 정보와 레시피 확장 파일을 경험해보았다.

 

특히, 레시피 확장 파일은 oe-core에서 제공하는 레시피 파일의 추가/ 변경 작업에 많이 쓰이기 때문에 꼭 기억하고 있자.

 

 

Comments