2/27/2020

Yocto 의 Recipe 기본작성방법

1. Yocto 의 Recipe 실행 및 설정 

Yocto에서 recipe가 존재하면, 아래와 같이 bitbake로 실행가능하며, 별도의 task가 존재한다면, -c 옵션을 이용하여 task도 실행가능하다.
그러므로 Yocto에서 원하는 Source를 수정하고 싶다면 반드시 Recipe 수정방법을 이해해야한다.


Yocto 기본문법 과 정리 (필독)
  https://ahyuo79.blogspot.com/2020/01/raspberry-pi3-linux-yocto.html

Yocto Layer 구성방법 과 기본 Recipe 구성  
  https://ahyuo79.blogspot.com/2020/02/yocto-layer-configuration.html

Yocto Partition (WIC) 관리 
  https://ahyuo79.blogspot.com/2020/02/yocto-partition.html


Yocto Uboot/Kernel 수정방법 

Yocto Kernel  Patch (bbappend) 실제예제 



  • bitbake로 각 recipe 를 task 기반으로 실행 예 
//Linux Kernel 설정 이름은 변경됨 
$ bitbake linux-imx  -c menuconfig    // 설정변경
$ bitbake linux-imx  -c diffconfig    //*.cfg 생성 
$ bitbake linux-imx  -c compile -f    // -f force로 강제로 실행 , 일반적으로 빌드되면 재빌드를 안함 
$ bitbake linux-imx  -c deploy

//Uboot 설정, 이름은 변경됨
$ bitbake u-boot-imx 
$ bitbake u-boot-imx -c menuconfig   //설정변경 
$ bitbake u-boot-imx -c diffconfig   // *.cfg
$ bitbake u-boot-imx -c compile -f
$ bitbake u-boot-imx -c deploy 

//busybox 관련설정 
$ bitbake busybox -c menuconfig
$ bitbake busybox -c diffconfig 

-c 는 recipe에서 task 이므로 이부분은 각각의 recipe 확인필요
-f 는 force 로 강제로 실행


  • 많이 사용되어지는 task
  1. config: fetch 된 상태, 즉 소스가 있는 상태에서 configuration 진행 
  2. compile : config 후 compile 진행 
  3. clean / cleanall:  compile 부분 clean
  4. install : rootfs로 install 
  5. deploy: package 배포 

  https://www.yoctoproject.org/docs/latest/ref-manual/ref-manual.html#ref-tasks

  • bitbake로 최종 Image 생성

//최종이미지 생성 
$ bitbake core-image-base     // core-image-minimal 기반에서 좀 더 원할하게 사용가능한 기본구성 

$ bitbake core-image-minimal  // Booting에 필요한 최소한의 Image 구성

// 이외 기타 , 각 Image 구성은 제조사 혹은 Yocto Version마다 다를 수 있으므로 실제 bbclass 와 같이 확인 
$ bitbake core-image-sato 
$ bitbake core-image-x11 

  https://wiki.yoctoproject.org/wiki/Minimal_Image


  • bitbake 적용중인 변수 값 확인
//bitbake를 이용하여 현재 사용중인 변수확인  
$ bitbake -e | grep ^CONF_VERSION  
CONF_VERSION="1"

$ bitbake -e | grep ^IMAGE  //IMAGE 에 연관된 변수 전체확인  
....

$ bitbake -e | grep ^KERNEL //KERNEL 에 연관된 변수 전체확인  
....

$ bitbake -e | grep ^IMAGE_INSTALL=  -A10//IMAGE_INSTALL  검색후 그다음 10줄 까지 확인   
....

$ bitbake -e | grep ^IMAGE_INSTALL=  -B10//IMAGE_INSTALL  검색후 그이전 10줄 까지 확인   
....

$ bitbake -e | grep ^IMAGE_INSTALL=  -A10 -B10 //IMAGE_INSTALL  검색후 그이전과 이후 총 20줄 모두 확인   
....


Yocto에서 사용되어지는 변수
  https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#ref-variables-glossary


1.1 Recipe 의 이름설정

Package NamePackage Version을 기록하고, *.bb 와 *.bbappend 작성하며, *.bbappend 주로 확장하는 개념으로 주로 Patch할 때 사용한다.
Yocto에서는 PN의 이름이 동일한 경우 PV가 높은 것을 자동 적용하여 실행한다.
(동일한 recipe가 여러개 존재하여도 PV가 높은것을 자동선택)

${PN}_${PV}.bb
bbexample_0.0.1.bb 
bbexample_0.0.1.bbappend


1.2 Recipe 의 내부기본구성 

  • Recipe의 서술부분
SUMMARY = "SUMMARY  Bitbake Recipe Example"  # 보통 SUMMARY or DESCRIPTION으로 설명 
DESCRIPTION = "DESCIRPTION  Bitbake Recipe Example"
SECTION = "example"              # 생략해도 무방하지만 필요에따라 사용 


  • Receip 에서 LICENSE 사용방법 및 위치파악 
- LICENSE 미사용할 경우
# LICENSE 사용안할 경우 LIC_FILES_CHKSUM  필요없음 
LICENSE = "CLOSED" 

- LICENSE가 Source 안에 있을 경우
# LICENSE 사용할 경우 아래의 File이 Source에 포함되어있음  
LICENSE = "GPLv2"
# COPYING File 과 COPYING의 md5sum 값 (Download 위치의 Source의 Root), 즉 Source에 포함
LIC_FILES_CHKSUM = "file://COPYING;md5=d7810f...." 

- LICENSE가 COMMON_LICENSE_DIR 에 있을 경우
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=3434..."

- bitbake를 이용하여 LICENCE DIR 확인
$ bitbake -e | grep ^COMMON_LICENSE_DIR   //COMMON_LICENSE_DIR 위치파악 

file://의 위치는 ${S}를 기본으로 있는 File
md5는 md5sum의 값

  • 사용할 File들 Remote or Local로 구성 
# 1. remote protocol 로 tar.gz를 download 후 md5sum/sha256sum으로 확인
SRC_URI = "https://github.com/Lora-net/packet_forwarder/archive/v${PV}.tar.gz"  # 확장자 tar.gz로 unpack 자동진행 
SRC_URI[md5sum] = "a1f942e0cc7b02d604b11c8cb5f2a029"
SRC_URI[sha256sum] = "e68fadf6f1d2e5e7b601e504d5efb48b0a8f374c2c29c0476ab2fe9db68d33ae"

# 2. git 의 branch, tag 정보로 download
SRC_URI = "git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git;protocol=git;branch=name"
SRC_URI = "git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git;protocol=git;tag=v${PV}"

# 3. git 의 Commit number로 Download
SRC_URI = "git://github.com/DynamicDevices/bbexample.git"
SRCREV = "5c58a861ca31710f6433487b8b0d590a43afd0ad"

#4. Local files에 source에 보관 ${S}에서 찾아서 사용하며 아래 파일은 *.bb 같이존재
SRC_URI = "file://xxxxxxx.tar.gz
SRC_URI = "file://xxxxxxx.patch  
SRC_URI = "file://xxxxxxx.sh 

download의 error를 방지하기위해서 상위와 같이 md5sum 과 sha256sum checksum을 사용

  • 상위 File들을 Build Directory Source 위치 설정 
Build Directory에서 작업을 하는 위치이며, S의 위치는 WORKDIR기준으로 정의

# 1. Git Download 했을 경우 Build Directory의 S의 구성
S = "${WORKDIR}/git"

# 2. tar.gz로 Download 했을 경우, 압축을 풀어 packagename-${PV}
S = "${WORKDIR}/packagename-${PV}"

# 3. file을 직접 사용할경우 local or remote
S = "${WORKDIR}"

상위에서도 에러가 발생한다면, build space에서 상위 WORKDIR를 찾아 직접확인을 해보자.
Debug 방법은 bbplain을 사용해서 환경변수정보를 알아보자.

  https://www.yoctoproject.org/docs/2.7/ref-manual/ref-manual.html#var-TMPDIR

이외 Task 를 비롯하여 Class구성은 실제구성에서 알아보자.

1.3  Recipe 확장구성

  • *.bbappend의 구성 
보통 Patch용으로 사용하거나, 확장하기위해서 사용되어진다.
아래를 설정하지 않아도 기본으로 *.bb파일 기준으로 files에서 찾음

e.g 1
$ cd meta-xxx/.../   // 수정을 원하는 recipe 이동 
$ cat xxx_1.0.1.bb  //recipe 파일 확인 
$ mkdir files
$ vi  xxx_1.0.1.bbappend //patch file 구성 및 cfg 파일 구성 
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
## update
SRC_URI += "file://001_mypatch.patch"
SRC_URI += "file://002_mypatch.patch"

e.g 2
$ cd meta-xxx/.../     // 수정을 원하는 recipe 이동 
$ cat xxx_1.0.1.bb  //recipe 파일 확인 
$ mkdir v1.0.1
$ vi  xxx_1.0.1.bbappend //patch file 구성 및 cfg 파일 구성 
#*.bb 파일의 PV기준으로 v{PV} directory에서 찾음 
FILESEXTRAPATHS_prepend := "${THISDIR}/v${PV}:"
## update
SRC_URI += "file://001_mypatch.patch"
SRC_URI += "file://002_mypatch.patch"


2. Recipe의 이해와 예제 

Recipe 안에는 Class 와 Task를 이용하여 많은 기능들을 구현이 가능하다.

  • Recipe 의 Class 개념 
Recipe에서는 동일한 기능들을 library 처럼 불러사용이 가능한데, 이를 class라고 하며 구성은 package_name.bbclass file 구성으로 되어있다.
Recipe 안에서 이를 inherit package_name 을 호출을 하면 이 class 기능을 사용가능하다.

inherit systemd  

Yocto Class들의 구성
  https://www.yoctoproject.org/docs/latest/ref-manual/ref-manual.html#ref-classes
Codename(Warrior)의 Classes
  https://www.yoctoproject.org/docs/2.7/ref-manual/ref-manual.html#ref-classes
Codename (Fido) 의 Classes
  https://www.yoctoproject.org/docs/1.8/ref-manual/ref-manual.html#ref-classes



  • Recipe의 Task 개념
Recipe에서 기본동작은 Task 기반으로 호출이 되어 동작되어지며, 이는 함수와 비슷하다
물론 암묵적으로 Task를 선언하지 않아도 자동으로 규칙에 맞게 실행이 되어진다.
순서를 비롯하여 각각의 기능이 다르므로 각 기능에 맞는 Task를 사용해서 본인이 원하는 기능을 추가해서 넣는다.

## 이 Package가 빌드시 반드시 필요하며 종속적임(중요)
DEPENDS += "libusb1 udev" 

## 일반적으로 CFLAGS or LDFLAGS 상위 libusb 추가 (반드시 스페이스 추가) 
## 가끔세부적인 CFLAGS or LDFLAGS를 위해 세부적인 필요할때  
## TARGET_xxxx    (Target Device)  
## BUILD_xxx      (Build Host , i.e  -native)  
## BUILDSDK_xxx   (Build Host 의 SDK i.e. nativesdk-) 
CFLAGS_append = " -lusb-1.0 "

## CXXFLAGS 정보추가 가능 
## LDFLAGS  정보추가 가능 

## do_compile task 
## Makefile이 존재한다면 do_compile을 생략
## Makefile 이 있을 경우 CFLAGS/LDFLAGS 와 환경변수로 Control이 가능 (상위 DEPENDS 설정) 
## Makefile이 없을 경우 아래와 같이 직접찾아 빌드 
do_compile() {
        ${CC}  -o test main.c ${CFLAGS} ${LDFLAGS} 
}

## do_install task
## 가장 많이 사용할 task로 install이 되는 위치를 정하고 package가 된후 
## 최종으로 자동으로 rootfs에 들어가진다. 
## install 명령어 이외에도 삭제하고싶다면 rm으로 삭제 
do_install() {
        ## install 장소정의 
        install -d ${D}${bindir}
        install -d ${D}${sysconfdir}/systemd/network
        install -d ${D}${systemd_system_unitdir}

        ## 실제 파일 Install 
        install -D -m 0744 ${S}/*.sh ${D}${bindir}
        install -D -m 0744 ${S}/test ${D}${bindir}
} 

Task 역시 prepend or append 로 task 뒤에 추가가능
  1. do_configure(): Configure를 설정을 해줌
  2. do_compile() : 존재하지 않는다면, oe_runmake가 Makefile 찾아 자동 Build 
  3. do_install(): RootFS로 이를 Install 

Yocto 다양한 Task의 구성
상위에 언급한 Task 이외에 다양한 Task가 많이 존재하므로 반드시 확인하자
  https://www.yoctoproject.org/docs/latest/ref-manual/ref-manual.html#ref-tasks
Codename(Warrior)의 Tasks
  https://www.yoctoproject.org/docs/2.7/ref-manual/ref-manual.html#ref-tasks
Codename (Fido) 의 Tasks
  https://www.yoctoproject.org/docs/1.8/ref-manual/ref-manual.html#ref-tasks


  • Recipe의 각 Task 마다 prepend 와 append 적용
Makefile이 제대로 구현이 되어있다면, do_compile의 필요가 없지만, do_compile_prepend를 이용하여 환경변수 구성을 할 수가 있다.

## 환경변수는 본인이 설정 
do_configure_prepend() {
 export PATH=""
}

## 환경변수는 본인이 설정 
do_compile_prepend() {
 export PATH=""
}

  • Recipe 의 Task do_complie 없애고, Makefile 직접구성 
Simple하게 구성을 해지만 가능하다면 CFLAGS / LDFLAGS를 적용가능하도록 구성하자

$ vi Makefile  
APP_TEST1   := test1 
APP_TEST2   := test2
APP_TEST3   := test3
APP_TEST4   := test4


APP_NAME := $(APP_TEST1) $(APP_TEST2) $(APP_TEST3) $(APP_TEST4) 

ARCH ?=
CROSS_COMPILE ?=

OBJDIR = obj
INCLUDES = $(wildcard inc/*.h)

LIBS_USB := -lusb-1.0 
LIBS_SSL := -lssl -lcrypto
LIBS_PTH := -lpthread 

FILES_LIB := mylib.c mysimplelib.c 

OPT_USB   := $(FILES_LIB) $(CFLAGS) $(LIBS_USB)
OPT_SSL   := $(CFLAGS) $(LIBS_SSL)
OPT_PTH   := $(CFLAGS) $(LIBS_PTH)
OPT_BOTH  := $(FILES_LIB) $(CFLAGS) $(LIBS_USB) $(LIBS_SSL)

all: $(APP_NAME)

clean:
 rm -f $(OBJDIR)/*.o
 rm -f $(APP_NAME)

$(APP_TEST1): $(INCLUDES) 
 @echo "TEST0: ${INCLUDES} CC:${CC} CFLAGS:${CFLAGS} " > log    
 $(CC) -o $(APP_TEST1) test1.c $(OPT_USB)

$(APP_TEST2): $(INCLUDES)   
 $(CC) -o $(APP_TEST2) test2.c $(OPT_SSL)

$(APP_TEST3): $(INCLUDES)   
 $(CC) -o $(APP_TEST3) test3.c $(OPT_PTH)

$(APP_TEST4): $(INCLUDES)   
 $(CC) -o $(APP_TEST4) test4.c $(OPT_BOTH)



  • Recipe의 Package 개념 및 설정
Yocto는 Recipe를 Package 단위로 구성하기 때문에 당연히 현재의 Package를 알아야 하며,
아래와 같이 Package에 관련부분을 설정해야줘야한다.

Package 관련설정
  https://ahyuo79.blogspot.com/search/label/Yocto-UserConf

e.g 1
## Package 심플하게 구성하게 이름만 선언하고, 이를 IMAGE_INSTALL에 추가 
## 
PACKAGES = "${PN}"
##
## FILE은 Package 내부의 File List로 Package가 이 위치구성되고 최종 RootFS에 적용된다.
## 
FILES_${PN} = "${bindir}/* "

##
## 매번 QA Issue에러 발생하면 관련부분을 생략하자 
##
INSANE_SKIP_${PN} = "ldflags"
INSANE_SKIP_${PN} += "installed-vs-shipped"


e.g 2
##
## PACKAGE 구성시 DEBUG를 어떻게 구성할 것인지 (필요없다면 생략)
## 
PACKAGE_DEBUG_SPLIT_STYLE = "debug-without-src"

##
## Package 의 리스트 구성 으로 간단하게 하고자 하면  
## 
PACKAGES = "${PN}-dbg ${PN} ${PN}-doc"

## QA Issue에서 아래에러를 때문에  추가 
# Avoid QA Issue: No GNU_HASH in the elf binary
INSANE_SKIP_${PN} = "ldflags"

##
## 상위에서 PACKAGE들의 저장위치 
FILES_${PN}-dbg = " \
 ${bindir}/.debug \
"
FILES_${PN} = " \
 ${bindir}/* \
 ${docdir}/* \
"
FILES_${PN}-doc = " \
 ${docdir} \
"



  • Recipe의 관련정보 Debug 방법
Recipe를 작성하다보면 Recipe의 내부변수의 정보를 비롯하여 print를 해서 보고 싶을 경우가 많을 것이며, 이를 bbplain이라는 것을 이용하여 확인하자

do_compile() {
        bbplain "--------    COMPILE DEBUG ${CFLAGS} "  
        ${CC}  -o test main.c ${CFLAGS} ${LDFLAGS} 
}

do_install() {
        bbplain "--------    INSTALL DEBUG ${bindir} " 
        install -d ${D}${bindir}
        install -d ${D}${sysconfdir}/systemd/network
        install -d ${D}${systemd_system_unitdir}
} 

bbplain/bbwarn/bbnote 등을 이용한 debug방법 (각 변수정보확인)
  https://git.yoctoproject.org/cgit.cgi/poky/plain/meta/classes/logging.bbclass


2.1 Image recipe 예제

class image(*.bbclass)를 사용하여 구성을 하여도 되겠지만, 가장쉽게 구성하는 방법은 기존의 Image bb 파일 기반으로 재구성하는 방법이다.

  • IMAGE recipe 예제
bitbake 이용하여 빌드할 경우, 보통 core-image-base 기반으로 나만의 Image를 만들 경우 아래와 같이 구성

$ cd sources/meta-xxxx  // 관련 Layer
$ mkdir recipes-core
$ cd recipes-core
$ vi core-image-mine.bb  
SUMMARY = "My raspberry's Image "

## bitbake core-image-base 기반으로 작성됨
## 이 방법말고 inherit core-image를 이용하여 즉 bbclass를 직접이용하여 사용하는 방법으로도 가능 
include recipes-core/images/core-image-base.bb  

## 상위 기반으로 필요한 Package를 추가하여 설치 
IMAGE_INSTALL += "openssh"  
## 항상 추가된 Package의 bb 파일 검색해서 필요한 Package 추가 한 후 
## 종속관계를 알기위해서 bb 파일에서 반드시 아래 두 항목확인
## DEPENDS : Build를 위해 필요 Package
## RDEPENDS : Runtime시 필요한 Package  
IMAGE_INSTALL += "tcpdump"

## 나만의 Image name 선언 
export IMAGE_BASENAME = "core-image-mine"  

##오직 TEST를 위해 do_rootfs 후에 진행되는 Task 기능추가 추가 
my_postprocess_function() {
   echo "hello" > ${IMAGE_ROOTFS}/hello.txt
}
ROOTFS_POSTPROCESS_COMMAND += "my_postprocess_function; " 

class image를 좀 더 알고 싶다면  core-image-base.bb 파일 이외 inherit core-image를 사용하므로 core-image.bbclass를 세부분석

2.2  Simple Build Recipe 작성 

  • local 기반의 simple recipe 작성예제 
Simple 하게 이미 Source가 존재한다고 가정하고 아래와 같이 구성
    ## recipe의 설명 및 라이센스 설정
    SUMMARY = "TEST"
    SECTION = "TEST"
    LICENSE = "CLOSED"
    
    ## Build할 Source 의 위치 아래는 Local로 설정
    SRC_URI = "file://demo.c"
    S = "${WORKDIR}"
    
    ## Build시 CFLAGS 의 설정 
    CFLAGS_append = "-lusb-1.0 "
    
    ## Build 실 필요한 Package 이름 
    DEPENDS += "libusb1" 
    
    ## Compile task 
    do_compile() {       
     ${CC} demo.c ${LDFLAGS} ${CFLAGS} -o demo
    }
    
    ## 컴파일전에 환경설정 
    do_compile_prepend() {
        export LIBUSB_PATH="${STAGING_LIBDIR}/libusb1"    
    }
    
    ## 설치진행 
    do_install() {
        install -d ${D}${bindir}
        install ${B}/demo ${D}${bindir}
    }
    
    INSANE_SKIP_${PN} += "installed-vs-shipped"
    
    ## Package 이름 
    PACKAGES = "${PN}"
    
    ## install에서 설치되어지는 곳 각 설정 
    FILES_${PN} = "${bindir}/* "
    


    • DEPENDS 와 RDEPENDS 의 차이 
    DEPENDS의 경우 이 recipe를 Build 하기전에 반드시 필요한 Package 구성이며 일반적으로Library 경우가 많다.
    하지만 RDEPENDS의 경우는 이 Program이 Runtime으로 동작할때 필요한 Library가 필요할 경우 많이 사용한다.
    이때 CFLAGS or LDFLAGS or CXXFLAGS를 같이 사용하여 관련 library를 추가하고 세부설정도 가능하다.
    (주의: 스페이스로 반드시 이전 FLAGS정보와 분리)

    일반적으로 상위 FLAGS들을 설정하면, 세부 플래그는 동일하게 설정되지만, 크로스 컴파일 환경이다보니, 세부적으로 조절해야 할 경우가 발생한다.
    1. TARGET_xxx  :  Target Device
    2. BUILD_xxx :  Build Host  i.e    -native 
    3. BUILDSDK_xxx: Build Host  i.e. nativesdk-


    • 상위 Recipe 작성 중 다양한 QA Issue 해결
    Recipe 작성 후 bitbake 실행시 QA Issue라면서 에러가 발생을 할 경우가 있는데, 필요없다면, 생략가능하므로 아래와 같이 설정하여 해결

    $ bitbake core-base-image
    ......
    ERROR: .... do_package_qa: QA Issue: .....
    ......
    installed and not shipped files. [installed-vs-shipped]
    
    //상위와 같은 에러 발생
    
    ./tmp/sstate-control
    ......
    manifest-cortexa9hf-neon-tcpdump.package             //각 Package의 확인 
    manifest-cortexa9hf-neon-tcpdump.package_qa
    manifest-cortexa9hf-neon-tcpdump.package_write_rpm
    manifest-cortexa9hf-neon-tcpdump.populate_lic
    manifest-cortexa9hf-neon-tcpdump.populate_sysroot
    .......
    

    • 보통 QA Issue가 발생하면 Recipe(*bb)에 추가항목

    # Avoid QA Issue: No GNU_HASH in the elf binary
    INSANE_SKIP_${PN} = "ldflags"
    
    # Avoid QA Issue: installed-vs-shipped
    INSANE_SKIP_${PN} += "installed-vs-shipped"
    


    2.3 Kernel/Uboot/Busybox Recipe 수정방법 


    • Uboot/Kernel Device Tree Blob 확인 및 설정확인
    Device Tree Blob은 확인은 아래에서 쉽게가능하지만, 이중 한개만을 사용한다.

    $ bitbake -e | grep ^KERNEL_DEVICETREE=    // KERNEL Device Tree 전체확인가능 (이중 하나만 사용하며, Uboot Script에서 확인가능) 
    KERNEL_DEVICETREE="imx6sx-sdb.dtb imx6sx-sdb-emmc.dtb imx6sx-sdb-m4.dtb                      imx6sx-sdb-sai.dtb imx6sx-sdb-lcdif1.dtb imx6sx-sdb-ldo.dtb                      imx6sx-sdb-reva-ldo.dtb imx6sx-sdb-reva.dtb                      imx6sx-sdb-btwifi.dtb imx6sx-sdb-mqs.dtb"
    
    $ bitbake -e | grep ^KERNEL       // KERNEL 관련설정확인
    ...
    $ bitbake -e | grep ^UBOOT        // UBOOT 관련설정확인 (Kernel의 Device Tree 같이 사용안할수 있음)
    ...
    $ bitbake -e | grep ^UBOOT_CONFIG // i.MX일 경우,UBOOT_CONFIG에서 Device Tree 선택
    UBOOT_CONFIG="emmc"
    

    User Config 설정관련사항 (UBOOT_CONFIG)
      https://ahyuo79.blogspot.com/2020/02/yocto-user-configuration.html

    User Config 와 Machin Layer (UBOOT_CONFIG)
      https://ahyuo79.blogspot.com/2020/02/yocto-layer-configuration.html

    • Uboot/Kernel Device Tree Syntax 설정 (*dts,*dtsi)
    Device Tree는 *.dts 와 *.dtsi 파일 구성이 되어있으며, 보통 include 형식으로 참조하여 여러개의 dts 와 dtsi로 구성이 되어있다.

    DTS 수정방법 두가지
    1. 최종 설정되는 dts 파일을 직접 수정 (맨 아래의 녹색 DTS파일)
    2. 새로 파일 dts 생성 후 최종 dts를 include 생성 후 이것으로 DTS 설정 

    아래의 구성처럼 맨 아래의 최종 녹색 *.dts 기반으로 생성이 되므로, 본인이 원하는 dts가 있다면. 이를 한번 더 include하면 된다. 



    출처 
      https://developer.toradex.com/device-tree-customization#2-imx-6ull-based-modules

    ** 상위그림에서 마지막으로 참조되는 *.dts들은 마지막 Layer인 진한녹색 부분이며 이는 아래의 dts들을 포함하고 있다.

    *.dts 에서 본인의 원하는 device의 설정 및 설정값들은 중복설정 하여도 상관없다. 
    다만, *.dts의 내용이 중복될 경우 상위 그림 구성처럼 마지막으로 참조되는 *.dts 의 내부값으로 최종설정되기때문에 중복부분 확인필요


    기본최종 dts기반으로 새로구성할 경우

    기존에 존재하는 마지막 *.dts 파일를 찾은 후 새로 생성할 *.dts의 내부에 include로 최종 dts를 포함하여 새로생성한다
    변경할 사항들은 새로 생성한 dst에 중복설정한 후 이를 최종 dts로 만들어 빌드를 진행한다.
    (다만 너무 많이 수정한다면, 어쩔 수 없이 중복설정보다는 직접 수정을 하자)

    Uboot 와 Kernel의 dts의 구성은 같지만,  사용방법은 Chip Maker마다 다르므로  주의하자.

    TI 인경우, 한개의 dtb를 Uboot 와 Kernel이 같이 서로 공유하여 사용
    i.MX일 경우는, Uboot와 dtb를 합쳐서 Uboot Image 생성한 후, Kernel용은 dtb를 별도사용하므로, Uboot 소스와 Kernel 소스에서 각각 수정해서 반영

    Uboot 와 Kernel Device Tree 관련내용
      https://ahyuo79.blogspot.com/2015/08/kernel-boot-kernel-device-tree.html

    • Kernel/Uboot/Busybox  Config  수정 (*.cfg)
    Kernel/Uboot/Busybox는 각각의 기본 Config 존재하며, board 기반으로 설정이 되어진다.
    CONFIG_xxx =y 역시 중복설정가능하며 최종설정되는 값으로  진행되므로 cfg로 이전 설정을 변경이 가능하다.

    수정방법
    1. 기본적으로 본인의 defconfig  직접수정하여 변경
    2. 추가로 *.cfg 파일을 생성


    • Uboot의 Config 관련부분 Python 분석 (*.cfg)
    Uboot에서 Config 부분(*.cfg)를 어떻게 처리하는지를 보기위해서 소스분석
    $ find . -name u-boot-imx_*bb*   // 현재 Uboot 검색 
    ./meta-fsl-bsp-release/imx/meta-bsp/recipes-bsp/u-boot/u-boot-imx_2019.04.bb         // Yocto는 항상 PV가 높은 것을 자동선택 
    ./meta-fsl-bsp-release/imx/meta-bsp/recipes-bsp/u-boot/u-boot-imx_2019.04.bbappend
    ./meta-freescale/recipes-bsp/u-boot/u-boot-imx_2018.03.bb
    
    $ vi ./meta-fsl-bsp-release/imx/meta-bsp/recipes-bsp/u-boot/u-boot-imx_2019.04.bb // 현재 Uboot Recipe 분석 
    .....
    require u-boot-common.inc
    require u-boot.inc
    inherit pythonnative
    ....
    inherit fsl-u-boot-localversion
    

    상위와 같이 u-boot.inc를 포함되어있으며, 이부분을 분석해야 이해가 되며, 최종 do_configure()에서 이 부분을 처리함 
    $ find . -name u-boot.inc   //source에서 검색
    ./sources/meta-fsl-bsp-release/imx/meta-bsp/recipes-bsp/u-boot/u-boot.inc 
    ./sources/poky/meta/recipes-bsp/u-boot/u-boot.inc
    $ cd meta-xxx/...   // U-boot recipe 이동 
    $ cat u-boot.inc  // *.cfg 처리파일 (Uboot Config)
    .......
    # returns all the elements from the src uri that are .cfg files
    def find_cfgs(d):
        sources=src_patches(d, True)
        sources_list=[]
        for s in sources:
            if s.endswith('.cfg'):
                sources_list.append(s)
    
        return sources_list
    
    do_configure () {
        if [ -z "${UBOOT_CONFIG}" ]; then
            if [ -n "${UBOOT_MACHINE}" ]; then
                oe_runmake -C ${S} O=${B} ${UBOOT_MACHINE}
            else
                oe_runmake -C ${S} O=${B} oldconfig
            fi
            merge_config.sh -m .config ${@" ".join(find_cfgs(d))}
            cml1_do_configure
        fi
    }
    ......
    

    • Busybox 의 Config 관련부분 Python 분석 (*.cfg)
    동일하게 Busybox의 Config 관련부분(*.cfg) 부분 소스분석 
    $ find . -name busybox_*bb*   // 현재 busybox 검색 
    ./meta-fsl-bsp-release/imx/meta-bsp/recipes-core/busybox/busybox_%.bbappend  
    ./poky/meta/recipes-core/busybox/busybox_1.30.1.bb              // Yocto는 항상 PV가 높은것 자동선택 
    ./poky/meta-skeleton/recipes-core/busybox/busybox_%.bbappend
    ./poky/meta-poky/recipes-core/busybox/busybox_%.bbappend
    
    $ vi ./poky/meta/recipes-core/busybox/busybox_1.30.1.bb // 현재 busybox Recipe 분석 
    require busybox.inc
    ......
    

    Uboot와 동일하게 busybox.inc가 존재하며 이부분의 do_configure 부분에서 처리 
    $ find . -name busybox.inc   //source에서 검색
    ./sources/poky/meta/recipes-core/busybox/busybox.inc
    $ cd meta-xxx/...   // busybox recipe 이동 
    $ cat busybox.inc  // *.cfg 처리파일 (busybox Config)
    .......
    # returns all the elements from the src uri that are .cfg files
    def find_cfgs(d):
        sources=src_patches(d, True)
        sources_list=[]
        for s in sources:
            if s.endswith('.cfg'):
                sources_list.append(s)
    
        return sources_list
    
    do_configure () {
            do_prepare_config
            merge_config.sh -m .config ${@" ".join(find_cfgs(d))}
            cml1_do_configure
    }
    ......
    


    • Kernel 의 Config 관련부분 분석 (*.cfg)
    동일하게 Kernel 의 Config 처리방법(*.cfg) 소스분석 
    $ find . -name linux-imx_*bb //Kernel Recipe 검색 
    ./meta-fsl-bsp-release/imx/meta-bsp/recipes-kernel/linux/linux-imx_4.19.35.bb   //자동으로 Version 높은 것을 선택사용 
    ./meta-freescale/recipes-kernel/linux/linux-imx_4.9.123.bb
    
    $ vi ./sources/meta-fsl-bsp-release/imx/meta-bsp/recipes-kernel/linux/linux-imx_4.19.35.bb // Kernel Recipe 분석
    .....
    require recipes-kernel/linux/linux-imx.inc
    ...
    ## 아래와 같이 기존에 Yocto Manual 존재하는 Task를 미사용하고 새로추가된 Task 사용 
    do_preconfigure_prepend() {
        # meta-freescale/classes/fsl-kernel-localversion.bbclass requires
        # defconfig in ${WORKDIR}
        install -d ${B}
        cp ${S}/arch/${ARCH}/configs/${DEFCONFIG} ${WORKDIR}/defconfig
    }
    

    이상하게 Kernel도 구조는 동일하지만, 이상하게 제대로 동작이 되지 않아 세부분석 
    제대로 지원되지 않아 상위 처럼 내가 직접 do_preconfigure_prepend로 만들어서 지원

    $ find . -name linux-imx.inc
    ./sources/meta-freescale/recipes-kernel/linux/linux-imx.inc 
    
    $ vi ./sources/meta-freescale/recipes-kernel/linux/linux-imx.inc // bbclass 연결됨 
    ....
    inherit kernel fsl-kernel-localversion fsl-vivante-kernel-driver-handler
    ...
    
    $ find . -name kernel*bbclass  //bbclass 분석 
    ./poky/meta/classes/kernel.bbclass
    
    $ find . -name fsl-kernel-localversion*bbclass //bblcass 분석
    ./meta-freescale/classes/fsl-kernel-localversion.bbclass
    
    $ find . -name fsl-vivante-kernel-driver-handler*bbclass  //bblcass 분석
    ./meta-freescale/classes/fsl-vivante-kernel-driver-handler.bbclass
    
    ##
    ## 상위 소스분석 했지만, merge_config 부분 발견못함 
    ## 원래의 Kernel Recipe는 cfg가 제대로 지원이 되어야 하지만 미지원됨 (문제확인)
    
    $ grep -r merge_config.sh .  // cfg 지원되는 부분 검색 
    ./meta-freescale/recipes-kernel/linux/linux-qoriq_4.19.bb  
    ..
    ./poky/meta/classes/kernel-yocto.bbclass
    

    결론 Kernel Recipe는 문제가 존재하며 별도의 Task do_preconfigure 사용중 

    • Uboot/Busybox 의 bbappend file 생성 후 Patch 적용
    1. bitbake package -c diffconfig 이용하여 cfg 와 patch를 넣어 적용
    2. cfg 동작 안된다면, 소스를 분석하여 task에 넣어 강제설정
    3. 이것도 안되면 defconfig에 대한 patch를 생성하여 patch로 적용 


    $ cat u-boot-imx_xxxx.bb // u-boot recipe 확인 
    $ vi  u-boot-imx_xxxx.bbappend //u-boot 관련수정사항 추가 
    FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
    SRC_URI += "file://001_uboot_device_tree.patch"
    SRC_URI += "file://002_uboot_defconfig.patch"
    SRC_URI += "file://000_uboot.cfg"
    SRC_URI += "file://001_uboot.cfg"
    SRC_URI += "file://002_uboot.cfg"
    

    • Kernel 의 bbappend file 생성 후 Patch 적용
    1. bitbake kernel_name -c diffconfig 이용하여 cfg 와 patch를 넣어 적용
    2. cfg 동작 안되다면 do_preconfigure_append or 다른 task로 강제설정
    3. 이것도 안되면 defconfig에 대한 patch를 생성하여 patch로 적용 

    Kernel 추가 Config (*.cfg) 파일생성
    $ cd build    // Yocto build space 이동  
    $ bitbake linux-imx  -c menuconfig    // kernel config 변경 
    $ bitbake linux-imx  -c diffconfig    //변경된 config  *.cfg 생성 후 이를 Kernel Recipe에 추가 
    $ cat fragment.cfg
    $ cp fragment.cfg 001_kernel.cfg
    

    Kernel patch 파일생성 (path 중요)
    $ cd build    // Yocto build space에서 Kernel Source 위치파악하고, kernle 수정  
    
    $ mkdir -p  ~/patch/kernel    // Yocto 의 Patch를 위해 임시 directory생성  
    $ cp -a tmp/work-shared/imx6sxsabresd/kernel-source ~/patch/kernel/kernel_org   // Yocto에서 Download Kernel위치
    $ cp -a tmp/work/imx6sxsabresd-poky-linux-gnueabi/linux-imx/4.19.35-r0/kernel-source ~/patch/kernel/kernel_new // Yocto에서 Build 된 Kernel 위치(이부분 수정)
    
    // Kernel-source 위치 기준으로 Patch 생성 
    $ cd ~/patch/kernel     // Kernel Patch directory 이동 
    $ diff -urN  kernel-source_org  kernel-source_new  > kernel.patch   // Kernel 전체 Patch 생성 or 이위치에서 file patch 생성
    
    // 여러 File Patch 파일이므로 분할 or 상위위치에서 필요파일 Patch 생성
    $ cp kernel.patch 001_kernel_imx6sx-sdb.dtsi.patch  // 001_kernel_filename 구성후 나머지삭제
    $ cp kernel.patch 002_kernel_imx6sx-sdb-emmc.dts.patch //구성후 나머지 삭제
    
    //Kernel-source 위치중요 (현재 kernel_org,kernel_new로 생성되며, 날짜확인중요)  
    $ cat 001_kernel_imx6sx-sdb.dtsi.patch 
    diff -urN kernel-source_org/arch/arm/boot/dts/imx6sx-sdb.dtsi kernel-source_new/arch/arm/boot/dts/imx6sx-sdb.dtsi
    .....
    

    Patch 관련사항 (주의사항)

    Yocto에서는 Build Directory 내부에 Download 되는 위치와 Build 되는 위치거의 비슷한데, 간혹가다가 위치가 다른 경우가 있다. 
    예를 들면. 현재 Kernel의 경우 Build 방법이 달라서 인지 몰라도 위치가 다른데, work-shared의 용도는 다른 recipe와 공유목적이라고 한다.

    $ cd build     // Yocto Build directory
    
    tmp/work/imx6sxsabresd-poky-linux-gnueabi/u-boot-imx/1_2019.04-r0/git/                                  //Uboot  Download 위치 
    tmp/work/cortexa9hf-neon-mx6sx-poky-linux-gnueabi/linux-imx-headers/4.19.35-r0/git/                   //Kernel Download 위치 
    
    tmp/work/imx6sxsabresd-poky-linux-gnueabi/u-boot-imx/1_2019.04-r0/build/mx6sxsabresd_emmc_config/   //Uboot  Build 된 위치                   
    tmp/work-shared/imx6sxsabresd/kernel-source/                                                                //Kernel Build 된 위치 
    
    // 아래와 같이 Yocto는 거의 Download 위치와 Build 위치는 같은위치
    $ ls tmp/work/imx6sxsabresd-poky-linux-gnueabi/u-boot-imx/1_2019.04-r0/                 
    001_uboot_devicetree.patch    build/                        image/                        pkgdata/                      sysroot-destdir/
    002_uboot_defconfig.patch     deploy-rpms/                  license-destdir/              pseudo/                       temp/
    003_uboot_mmc.patch           deploy-u-boot-imx/            package/                      recipe-sysroot/               u-boot-imx.spec
    004_uboot_mx6sxsabresd.patch  git/                          packages-split/               recipe-sysroot-native/
    
    // 아래와 같이 예외적으로 다른사항도 있으니 주의 (Kernel build 위치가 다름) 
    // 현재 이유는 Compile시 neow으로 build해서 다른 것으로 생각 
    
    $ ls tmp/work/cortexa9hf-neon-mx6sx-poky-linux-gnueabi/linux-imx-headers/4.19.35-r0/   
    configure.sstate        git/                    license-destdir/        package/                pkgdata/                recipe-sysroot/         sysroot-destdir/
    deploy-rpms/            image/                  linux-imx-headers.spec  packages-split/         pseudo/                 recipe-sysroot-native/  temp/
    


    Kernel Recipe에 적용
    $ cd sources     // Yocto의 source 이동 
    $ cd meta-xxx/...  // Kernel recipe 이동 
    $ cat linux-imx_xxxxx.bb                  // Kernel recipe 확인 
    $ vi linux-imx_xxxxx.bbappend
    FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
    SRC_URI += "file://001_kernel_imx6sx-sdb.dtsi.patch"
    SRC_URI += "file://002_kernel_imx6sx-sdb-emmc.dts.patch"
    SRC_URI += "file://001_kernel.cfg"
    SRC_URI += "file://002_kernel.cfg"
    
    
    ## 문제사항 
    # 상위 *.cfg가 적용되지 않아 .config까지 적용하기위해서 아래와 같이 do_preconfigure를 이용하여 직접적용함 
    #
    ## 주의사항 (이것도 문제가 있음)
    # kernel menuconfig or config 전에 추가되기 때문에, 
    # Kernel diffconfig 를 하여도 동작안되므로, diffconfig를 원하면, 이부분을 막아야함 
    do_preconfigure_append() {
            cat ${WORKDIR}/001_kernel.cfg >> ${WORKDIR}/defconfig
            cat ${WORKDIR}/001_kernel.cfg >> ${WORKDIR}/build/.config
            cat ${WORKDIR}/002_kernel.cfg >> ${WORKDIR}/defconfig
            cat ${WORKDIR}/002_kernel.cfg >> ${WORKDIR}/build/.config
    }
    


    Kernel 관련된 Task
      https://www.yoctoproject.org/docs/latest/ref-manual/ref-manual.html#kernel-related-tasks

    /sys/kernel/debug 사용할 경우 
      https://yoctoproject.org/docs/3.0.4/profile-manual/profile-manual.html#profile-manual-general-setup

    2.4 systemd class를 이용한 recipe 작성

    systemd class를 이용하여 systemd의 service를 쉽게 제어가능하며, 각각의 File들을 쉽게 install 이 가능하다.

    • system 관련 서비스 기능추가 
    $ cat systemd.bb 
    ## Systemd 관련부분 설정
    SUMMARY = "Systemd Setting "
    DESCRIPTION = "Systemd Setting"
    LICENSE = "CLOSED"
    
    ## systemd bbclass 이용 
    inherit systemd 
    
    ## FILE관련 PATH를 별도로 추가를 하지 않아도 이곳에서 files에서 아래 파일들을 찾음 
    ## FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
    
    SRC_URI =  "file://eth0.network"
    SRC_URI += "file://test-0.service"
    SRC_URI += "file://test-1.service"
    SRC_URI += "file://test-2.service"
    SRC_URI += "file://test.sh"
    SRC_URI += "file://Seoul"
    SRC_URI += "file://30-mmc.rules"
    
    ## S설정
    ## 상위 Local File로 구성되어있기에 별도의 Directoryr가 필요없음 
    
    S = "${WORKDIR}"
    
    ##
    ## 본인이 원하는 systemd service를 SYSTEMD_SERVICE_ 설정 아래 설치별도로 존재 
    ## 이곳을 설정을 하지 않고 udev와 systemd의 service 연결하여 실행하고자 한다면, 이곳이 선언하지 말자. 
    ## https://ahyuo79.blogspot.com/2020/02/sdcard-udev.html
    SYSTEMD_PACKAGES = "${PN}"
    SYSTEMD_SERVICE_${PN} = "test-0.service test-1.service test-2.service"
    
    do_install() {
    ## Debug를 위해 삽입 bbplain기능 
      bbplain "--------    Systemd Setting Install     -----------------"
    ## 설치될 부분을 정의 
     install -d ${D}${bindir}
     install -d ${D}${sysconfdir}/systemd/network
     install -d ${D}${systemd_system_unitdir}
    
    ## systemd의 상위 service에서 사용하는 shell script 
     install ${S}/*.sh ${D}${bindir}
    
    ## systemd의 service기능 설치 
     install -D -m 0644 ${S}/*.service    ${D}${systemd_system_unitdir}
    
    ## 기타 필요한 부분 복사설치 
     install -D -m 0644 ${S}/eth0.network ${D}${sysconfdir}/systemd/network/eth0.network 
     install -D -m 0644 ${S}/Seoul        ${D}${sysconfdir}/localtime
     install -D -m 0644 ${S}/30-mmc.rules ${D}${sysconfdir}/udev/rules.d/30-mmc.rules
    }
    
    
    #PACKAGES = "${PN} "
    ## 상위 Install에서 설치될 부분을 반드시 정의 
    FILES_${PN} += " \
     ${sysconfdir} \
     ${bindir} \
     ${systemd_system_unitdir} \
    "
    

    install 시 상위 sysconfdir/systemd_system_unitdir/  변수정보
      https://git.yoctoproject.org/cgit.cgi/poky/plain/meta/conf/bitbake.conf

    bbplain 을 이용한 debug방법 (각 변수정보확인)
      https://git.yoctoproject.org/cgit.cgi/poky/plain/meta/classes/logging.bbclass

    • systemd 의 service 관련 설정 및 Shell Script 
    이 부분은 별도로 systemd 관련 Manual을 참고

    $ cat files/test-0.service
    [Unit]
    Description=TEST Service
    After=network-online.target
    Wants=network-online.target
    
    
    [Service]
    Type=simple
    ExecStart=/usr/bin/test.sh
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target 


    • logger 와 간단한 Shell script 구성 
    service에서 사용하는 쉬운 shell script
    $ cat files/test.sh
    #!/bin/sh
    
    WAIT_100MS() { sleep 0.1}
    
    ## /var/log 에 tag는 test 설정 하고 우선순위및 설정  
    echo ">> Start TEST Service\n\n" | logger -t test -p local3.notice
    
    /bin/ls
    
    ## 상위 실행의 최종 return 값 체크 
    if [ $? -eq 0 ]
    then
      echo "Success: ls" | logger -t test -p local3.notice
    else
      echo "Failure: ls" >&2 | logger -t test  -p local3.notice
      exit 1
    fi
    
    ## 본인이 원하는 프로그램 실행 
    /bin/xxxxx
    
    ## 이프로그램 실패를 해서 exit 1이 되며 상위 Service의 Restart=on-failure 에 의해 재실행 
    echo -e ">> Failed TEST Service\n\n" | logger -t test -p local3.notice
    exit 1
    

    2.5 다양한 class와 task 이용한 Recipe 작성법

    항상 본인이 사용하는 Yocto의 Version을 확인 한 후 해당 Manual 참조
    bbclass 의 이해와 사용법 (inherit allarch , systemd, ... )

    • Yocto 의 class systemd (inherit systemd) 의 예제
      https://stackoverflow.com/questions/45614578/enable-systemd-services-using-yocto
      https://community.nxp.com/thread/472820
      https://www.yoctoproject.org/pipermail/yocto/2015-April/024469.html
      https://hub.mender.io/t/startup-script-for-raspberrypi3-using-yocto/201/2


    • Yocto 의 class allarch (inherit allarch) 의 예제
      https://git.yoctoproject.org/cgit.cgi/poky/plain/meta/classes/allarch.bbclass
      https://stackoverflow.com/questions/50906048/bitbake-recipes-simple-file-copy


    • Yocto의 다양한 Class 정보 
      https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#ref-classes

    • Yocto 의 다양한 Task
      https://www.yoctoproject.org/docs/2.7/ref-manual/ref-manual.html#ref-tasks

    • Yocto 의 Kernel 관련된 Task 
      https://www.yoctoproject.org/docs/2.7/ref-manual/ref-manual.html#kernel-related-tasks


    • BBexmple 의 예제
      https://github.com/DynamicDevices/meta-example/blob/master/recipes-example/bbexample/bbexample_1.0.bb
      https://github.com/DynamicDevices/bbexample/releases
      https://github.com/DynamicDevices/bbexample/commit/5c58a861ca31710f6433487b8b0d590a43afd0ad