yoncho`s blog
8. Depends | 의존성 본문
개발자라면 의존성을 모를 수 없다. 우리가 만드는 모든 S/W와 사용하는 패키지들은 의존성을 가지고있다.
Yocto에도 Bitbake가 제대로 이미지 빌드 및 실행 되기 위해 다른 패키지 혹은 라이브러리를 필요로한다.
이를 의존성이라 하고
#목차
1. 의존성의 종류
2. 의존성을 제공하는 PROVIDES 변수
3. 최종
[1] 의존성의 종류
Yocto에는 두가지 의존성이 있다.
I. 빌드의존성
II. 실행 시간 의존성
짧게 각각을 설명해보면
*빌드 의존성 : 어떤 S/W 패키지를 빌드하기 전에 설치되어있어야하는 패키지 관계를 말한다.
=> 즉, 빌드 의존성을 가진 패키지는 사전 설치가 완료되어야한다.
*실행 시간 의존성 : 빌드와는 상관 없이 어떤 S/W가 실행 중에 사용해야하는 패키지가 있는데. 그런 패키지와의 관계를 말한다.
=> 즉, 사전 설치가 의무는 아니지만 Bitbake의 경우 빌드 시작 전 패키지간의 의존 관계를 파악해 사전 설치가 안되어있다면 설치한다. 실행 중에는 패키지가 정상적으로 호출되고 사용될 수 있어야한다.
#상세 설명
I. 빌드 의존성
빌드의존성은 패키지를 빌드하기 위해 필요한 헤더 파일과 정적 라이브러리를 만들어내는 다른 레시피에 대한 의존성을 말한다.
빌드 의존성이 필요한 레시피는 DEPENDS 변수에 의존성을 제공하는 레시피의 이름 / 의존성을 제공하는 레시피의 PROVIDES 변수값을 할당한다. 중요!!
앞서 nano-editor에서 아래와 같이 DEPENDS를 사용했다.
DEPENDS = "ncurses"
위 코드는 bitbake 내부적으로 nano editor 레시피 파일의 do_prepare_recipe_sysroot Task가
ncurses 레시피의 do_populate_sysroot Task에 의존성을 갖고있다는 의미이다.
아래는 변수 플래그를 활용해 빌드 시간 의존성의 예제이다.
do_prepare_recipe_sysroot[task_name] = "do_populate_sysroot"
현재 레시피의 do_prepare_recipe_sysroot Task가 DEPENDS 변수에 기술된 레시피의 do_populate_sysroot Task에 의존성을 갖고 있다는 의미다.
=> do_prepare_recipe_sysroot Task가 실행되기 전 의존성이 있는 레시피의 do_populate_sysroot Task가 완료되어야한 다는 뜻이다.
앞서 진행한 nano editor에서 log.task_order 파일을 보면
"do_prepare_recipe_sysroot" Task 로그가 보일 것이다.
이 Task가 실행되면 recipe-sysroot/ , recipe-sysroot-native/ 디렉터리가 tmp/work/<architecture>/<recipe_name>/ 디렉터리 아래에 생성된다.
**sysroot란 무언인가? sysroot는 헤더와 라이브러리를 찾기 위한 root 디렉터리로 간주하는 디렉터리이다.
레시피 하나당 한개의 sysroot 디렉터리가 존재하며 recipe-sysroot/ , recipe-sysroot-native/ 2개가 있다.
(a) recipe-sysroot : 타깃 시스템에 사용되는 헤더, 라이브러리 포함, 각 레시피에서 STAGING_DIR_TARGET 변수에 경로가 지정되어있다.
(b) recipe-sysroot-native : 크로스 컴파일 사용되는 컴파일러, 링커, 빌드 스크립트 등 포함, 호스트 시스템에서 사용되는 빌드 관련 도구가 배치된다. 각 레시피에서 STAGING_DIR_NATIVE 변수에 경로가 지정되어있다.
특히, 의존성을 다룰 때는 **sysroot-providers/ 디렉터리를 꼭 알아야한다 (꼮!!!!!!!)
이 디렉터리에는 sysroot에 설치된 패키지 명이 포함된 텍스트 파일이 존재한다.
do_populate_sysroot Task는 do_install Task 실행 후 설치된 파일들을 의존성 가진 다른 레시피가 사용할 수 있도록 sysroot 디렉터리에 복사한다.
정리해보면 bitbake가 A레시피 빌드 시 do_prepare_recipe_sysroot Task를 실행하기 전 DEPENDS 변수에 의존성을 가진 (패키지) B레시피를 먼저 빌드한다. 이때 의존성 가진 레시피 빌드에서 do_populate_sysroot Task가 실행되면 sysroot 디렉터리에 빌드 결과물을 복사해놓고 추가로 결과물을 A레시피의 sysroot 디렉터리에 복사한다.
이후 A레시피 빌드 과정을 마무리하게 되면 최종 이미지가 생성된다.
위 내용은 아래 그림과 같다.
짧게 설명하면 bitbake가 A레시피 do_fetch Task를 실행할 때 B레시피의 do_fetch Task가 거의 바로 실행된다.
참고로 bitbake는 여러 Task를 동시에 실행이 가능하다.
단, 의존성 처리에 있어서는 다음과 같이 동작한다.
(a) A레시피의 do_prepare_recipe_sysroot는 전 단계 do_patch Task가 종료되어야 실행된다.
(b) 다음 단계 do_configure Task는 do_prepare_recipe_sysroot Task가 종료되어야 실행된다.
(c) A레시피의 do_prepare_recipe_sysroot는 B레시피의 do_populate_sysroot Task가 종료되어야 실행된다.
II. 실행 시간 의존성
실행 시간 의존성은 S/W 패키지가 정상 동작을 하기 위해 필요한 다른 패키지가 필요한 경우를 의미한다.
빌드 과정과 별개로 S/W 실행 동안 필요한 외부 패키지들과의 의존성이다.
S/W 패키지 실행 시점에서 필요한 라이브러리, 모듈, 실행 파일 등이 포함된다.
=> 빌드 의존성과는 상관 없을 것 같지만, 결국 설치되어 작동해야하는 패키지일 가능성이 높다.
실행 시간 의존성이 필요한 레시피는 RDEPENDS_${PN} 변수에 의존성을 제공하는 패키지 이름 혹은 레시피의 RPROVIDES 변수값을 할당한다.
RDEPENDS_${PN} 변수에는 패키지 이름이 할당된다.
RDEPENDS_${PN} = <package_name>
여기서 참고로 xxxx_${PN} 형식의 변수는 모두 패키징 단계에서 사용되는 이름이다.
아직 패키지를 학습안했어서 여기선 그냥 빌드 결과물이라 생각하자
bitbake는 실행 시간 의존성을 RDEPENDS_${PN} 혹은 RRECOMMEMDS 변수를 사용한다.
아래는 변수 플래그를 통한 실행 시간 의존성의 예제이다.
do_build[task_name] = "do_package_write_xxxx"
do_build Task가 RDEPENDS_${PN} 변수에 할당된 패키지를 생성하는 레시피의 do_package_write_xxx Task에 의존성을 갖고 있다는 의미이다.
=> 즉, do_build Task 실행 완료되기 전에 의존성을 갖고있는 패키지의 do_package_write_xxx Task가 수행 완료되어야한다.
앞 글에서 말했었지만 여기서 do_build Task는 사실 실행되지 않는 Task이고 Task Chain에 제일 마지막에 위치한다.
정확히 do_build Task는 Task Chain 구성을 위해 존재한다.
RDEPENDS 변수는 패키징 단계에서 사용되는데, 여기서 패키징을 수행하는 Task는 rootfs 이미지를 생성하는
레시피로 우리 예제에서는 core-image-minimal.bb와 같다.
rootfs 이미지를 생성하는 레시피는 우리가 아는 Task와는 다른 Task로 구성되어있다.
rootfs 이미지 생성 레시피에는 do_rootfs, do_image, do_image_complete 등의 Task가 존재하며
RDEPENDS 변수는 방금 소개한 Task와 의존관계를 갖는다.
+ 일반 레시피 파일의 do_configure, do_install 등과는 의존과계가 없다.
결론) do_build Task와 실행 시간 의존성을 가졌다는 것은 의존성을 가진 레시피의 빌드와 상관없이
rootfs 이미지가 생성되기 전, do_rootfs Task 실행 이전에 의존 관계에 있는 레시피의 do_package_write_xxx Task들이 실행되어야한다는 뜻이다.
=> 즉, rootfs 이미지 생성 되기 전에 의존 관계에 있는 패키지들이 모두 rootfs에 추가되어야한다.
글 위에 보면.. 내가..
bitbake는 실행 시간 의존성을 RDEPENDS_${PN} 혹은 RRECOMMEMDS 변수를 사용한다 라고 말했었다.
RDEPENDS_${PN} : 의존된 패키지가 존재하지 않을 경우 에러 발생
RRECOMMENDS : (부드러운 실행 시간 의존성) 의존된 패키지가 존재하지 않아도 빌드 진행
+추가. 실행 시간 의존성 사용하는 대체 패키지 생성
oe-core에는 kdb 패키지가 있는데 이는 리눅스 콘솔 다루기 위한 다양한 툴을 제공한다.
원래는 console-tools 패키지를 사용했는데 대체되고 있다.
만약 우리가 사용하던 패키지 이름이 변경될 때 아래와 같이 대응하면 쉽다.
기존 패키지 이름을 전부 새로운 패키지명으로 바꿀 수 없으니 우리는 kdb 패키지가 console-tools와 호환되게 바꿔줘야한다.
기존 console-tools 호환을 위해 kdb 레시피 파일에 아래와 같이 의존성 변수들을 작업해야한다.
RREPLACES_${PN} = "console-tools"
RPROVIDES_${PN} = "console-tools"
RCONFLICTS_${PN} = "console-tools"
RPROVIDES : 패키지 이름에 별칭을 만든다. 즉, 패키지를 인식할 수 있는 또 다른 이름을 부여하는 것!
=> 호환을 위해 이전 패키지 명을 여기에 넣으면 현재 패키지로 동작하게된다.
RCONFLICTS : 현재 패키지로 호환 시 충돌나는 패키지를 할당한다.
=> 이전 패키지 명을 넣어 이전 패키지 설치를 막는다.
RREPLACES : 이전 패키지 명을 넣어 패키지 대체됨을 알린다.
위 작업을 수행하면 기존 "console-tools"로 의존성 변수에 적혀있어도 kdb 레시피가 빌드되어 동작함으로써
패키지 명 변경에도 기존 파일들이 정상적으로 동작할 수 있는 것이다.
[2] 의존성을 제공하는 PROVIDES 변수
앞에서 빌드 의존성이 필요한 레시피는 DEPENDS변수에 의존된 레시피의 PROVIDES 변수값을 할당한다고 했다.
여기서 우리는 PROVIDES 변수를 알아야한다.
레시피는 PROVIDES 변수를 이용해 레시피 별칭을 지정할 수 있다.
즉, 레시피의 또 다른 호출 이름을 부여할 수 있는 것!!
그래서 의존성 표시를 위해 의존하는 레시피가 속한 파일의 PROVIDES 이름을 DEPENDS변수에 할당하면 된다.
#Bitbake가 제공하는 PROVIDES 변수 표현 방법
I. 레시피 파일 이름으로부터 PROVIDES 변수 값 할당
bitbake는 PN: package name / PV : package version / PR : package reversion 을
레시피 파일 명에 명시하지 않는 이상 레시피 파일 내 정의된 PN, PV, PR 변수 값으로 구한다.
nano-6.0-r0.bb
위와 같이 레시피 파일명이 있다고 하면
여기서 nano는 PN(package name)이고
6.0은 PV(package version)이고
r0는 PR(package reverison)이다.
참고로 r0는 bitbake가 파일 명에 PR 값이 없다면 기본으로 설정한다.
PROVIDES 변수는 따로 정의하지 않다고 기본적으로 PN 값을 가진다.
II. 명시적 PROVIDES 변수 값 할당
앞 단계는 레시피 파일 명에서 PROVIDES 값을 추출했다면 여기서는 사용자가 레시피 파일 내
PROVIDES 변수에 원하는 별칭을 지정하는 것이다.
PROVIDES += "nano-II"
위와 같이 nano 레시피 파일 내에 PROVIDES값을 명시했다고 가정하자
그러면 bitbake-getvar 명령어로 PROVIDES 값을 보면
"nano nano-II"로 표시된다.
이건 기본적으로 레시피 파일이름을 가지고 PROVIDES 변수에 '+=' 연산자로 nano-II를 추가했기 때문이다.
nano로 해도, nano-II로 해도 호출할 수 있다.
결론적으로 PROVIDES 변수는 많은 S/W 패키지 속에서 명칭이 같을 때 충돌나는걸 방지할 수 있다.
#다중 패키지, 다중 버전을 위한 virtual PROVIDER (매우 중요!!)
PROVIDES 변수 값을 'virtual/xxx'와 같이 할당할 수 있는데. 이는 다중 패키지들을 위함이다.
Yocto에서는 하나의 프로젝트 안에 두개의 커널을 구성할 수 있다.
즉, 어떤 레시피는 a 커널을 이용하고 다른 레시피는 b 커널을 이용하는 것이다.
이를 위해 각각의 커널을 별도 레시피 파일로 표현한다.
각 커널 레시피 파일 내 PROVIDES 변수에는 'virtual/kernel' 이라고 동일하게 부여한다.
그리고 환경 설정 파일에 PREFERRED_PROVIEDS_virtual/kernel = <kernel _name> 구문을 사용해 최종적으로 사용할 커널 레시피를 지정한다.
아래 그림이 그 예시이다. (다중 패키지를 가진 패키지의 선택)
virtual/ 접두 규칙은 다중의 PROVIDES를 제공하는데 사용하는 규칙이다. 다중 커널 이외 에도 많은 곳에서 사용하기 때문에 기억해두자!!!!
만약에 동일한 S/W 패키지이지만 버전이 다를 경우 환경 설정 파일에
PREFERRED_VERSION_<package_name> = "<package_version>"을 추가해주면 된다.
아래 그림이 그 예시이다. (다중 버전을 가진 패키지의 선택)
참고로 PREFERRED_VERSION_<package_name> 변수에 할당하는 버전 표시는
아래와 같이 와일드 카드가 존재한다.
#완전 명시
PREFERRED_VERSION_<package_name> = "22.04"
#와일드 카드 명시
PREFERRED_VERSION_<package_name> ="22.%"
%는 이후 버전 어떤게 와도 상관 없다는 걸 의미한다.
그래서 위 예제 中 와일드 카드 명시부분은 22.xxx 이상 버전이 오면 된다를 의미한다.
[3] 최종
이번 학습에서는 bitbake가 빌드 시 의존 관계 - 빌드/ 실행 시간에 따라 어떤 변수를 설정해야 하는지
그리고 어떻게 빌드 과정이 진행되는지 배울 수 있었다.
빌드시 필요한 라이브러리는 빌드 의존성을 가진 것이고, 실행 시 필요한 라이브러리가 실행 시간 의존성을 가진 것이다.
빌드 의존성은 DEPENDS 변수에 의존된 레시피 명 혹은 PROVIDES(별칭) 값을 할당 한다는 것!
실행 시간 의존성은 RDEPENDS 변수에 .. 할당한다는 것!!
그리고 다중 패키지, 다중 버전을 대응하기 위해 PROVIDES변수에 'virtual/kernel' 과 같이 virtual/ 접두 규칙을 적용시켜줘야하고 PREFERRED_PROVIDER/ PREFERRED_VERSION_<package_name> 변수를 통해 실제 사용할 패키지 혹은 버전을 지정한다..!!
점점 많은 것들을 배워가서 좋고, 흥이난다~
'기술, 나의 공부를 공유합니다. > [Vehicle] Yocto' 카테고리의 다른 글
10. Custom Image & BSP Layer | Poky기반 타깃 시스템 이미지와 BSP Layer (0) | 2024.09.21 |
---|---|
9. Package Group & Build Env. | 패키지 그룹과 빌드 환경 구축 (0) | 2024.06.28 |
7. Build Optimization | Autotools, Build History, rm-work, externalsrc (0) | 2024.06.26 |
6. Systemd | 초기화 관리자 추가 및 로그 파일 디버깅 (0) | 2024.06.24 |
5. Custom Layer | 레이어 생성을 위해 필요한 과정 (1) | 2024.06.23 |