클래스와 레시피

  • 비트베이크는 클래스(.bbclass)와 레시피(.bb, .bbappend) 파일을 작성하기 위해 Python과 Shell Script가 혼합된 형태의 코드를 사용한다.
  • 여기에는 =, ?=, +=, .=, :=, :append, :prepend, OVERRDIES, ${@<python-command>} 등 다양한 문법이 존재한다. 각 문법들이 비트베이크에서는 어떠한 형식으로 해석하는지 본 페이지를 통해 설명한다.

 

변수 할당

  • 비트베이크의 변수 할당에는 아래와 같이 3가지 타입의 변수 할당 연산자(=, ?=, ??=)가 존재한다.

 

= (deferred assignment)

  • 지연 변수 할당을 위해 사용하는 연산자이다.
  • 여기서 지연(deferred)에 대한 개념 설명은 뒤 변수 확장 섹션에서 추가 설명한다.
FOO = "bar"
  • 위 예시와 같이 사용하여, 특정 변수(FOO)에 특정 값("bar")을 할당가능하다.

 

?= (soft assignment)

  • =보다 낮은 순위의 변수 할당을 위해 사용하는 연산자이다.
  • ?=는 주로 특정 변수에 기본값(default)을 할당할 때에 사용한다.
FOO ?= "bar"
  • 위 예시와 같이 사용하여, 특정 변수(FOO)에 기본 값("bar")을 할당가능하다.
FOO = "bar"
FOO ?= "BAR"
  • 앞에서 ?=는 =보다 낮은 우선순위를 갖는다고 하였다. 이에 대한 설명을 위해 위와 같은 예시 코드를 작성하였다.
  • 비트베이크는 레시피 내용을 파싱하고 빌드를 실행할 때 ?=보다 높은 우선순위인 =로 변수의 값을 할당한다.
  • 따라서, 비트베이크는 FOO에 "bar" 값을 할당하여 빌드를 수행하게 된다.

 

??= (weak default assignment)

  • ?=보다 낮은 순위의 변수 할당을 위해 사용하는 연산자이다.
FOO  ?= "barbar"
FOO   = "barbarbar"
FOO ??= "bar"
  • 앞서 설명하였다시피 비트베이크는 레시피의 파싱을 수행하고 빌드를 진행할 때 변수 할당 연산자의 우선순위를 따진다. 그렇기 때문에, FOO에는 "barbarbar"가 담겨져 최종적으로 빌드가 수행된다. 다시 말해, 변수 할당 연산자는 "= > ?= > ??="와 같은 관계를 가진다.
  • 이 세가지 연산자는 특정 레시피가 빌드될 때에 여러 환경의 조합으로 변수에 기본값(?=, ??=)을 사용할 지 혹은 지연된 값(=)을 사용할 지 목적에 따라 유연하게 사용될 수 있다. 

 

변수 확장

A = "aValue"
B = "before-${A}-after"
  • 비트베이크에는 변수 확장이라는 개념이 존재한다.
  • 예를 들어, 위 예시와 같이 작성되어 있다면 B에는 "before-aValue-after"라는 값으로 확장된다.
A = "aValue"
B = "before-${A}-after"
A = "aNewValue"
  • 여기서 일반적인 순차적 모델에 기반한 프로그래밍 언어를 접했던 개발자라면 B는 당연히 "before-aValue-after"이다.
  • 하지만 비트베이크는 빌드를 하는 그 순간까지 B를 "before-${A}-after" 형태로 저장해두며, 빌드를 수행(태스크가 실행되는)하는 그때, B에 A의 값을 대입시켜 "before-aNewValue-after"로 완성시킨다.
A = "aValue"
B := "before-${A}-after"
A = "aNewValue"
  • 여기서 한가지 재미난 점은 :=(immediate assignment) 연산자를 사용하면 즉시 변수를 확장할 수 있다는 점이다.
  • 다시 말해, 위와 같은 예시에서 B는 :=로 인해서 즉시 "before-aValue-after"로 확장된다는 것이다.
MIRROR = "http://internal"
SRC_URI := "${MIRROR}/pkg.tar.gz"
  • 한가지 예시로 특정 소스를 내려받을 때 MIRROR 서버의 경로가 즉시 반영되어야 하는 경우가 존재한다.
  • 만약, 비트베이크가 빌드를 수행할 때에 MIRROR 값이 도중에 변경된다면 소스를 내려받는 경로가 달라져 빌드 결과물의 버전에 이상이 생길 수 있다. 그렇기에 적절하게 =와 :=를 사용하여 레시피 파일을 작성할 수 있어야 한다.

 

문자열 추가/삭제

  • 빌드를 수행할 때에 특정 변수에 할당된 문자열 값에 여러 값들을 추가 혹은 삭제해야 하는 경우가 존재할 것이다. 이때에는 아래와 같은 5가지 타입의 할당자(+=, .=, :append, :prepend, :remove)를 사용가능하다.

 

+= (append with space), =+ (prepend with space)

A = "aValue"
A += "AfterNewValue" # 1. aValue AfterNewValue
A =+ "BeforeNewValue" # 2. BeforeNewValue aValue AfterNewValue
  • +=와 =+를 통해서 특정 변수에 공백으로 구분된 문자열을 추가할 수 있다.
  • +=를 사용하게 되면, A 변수 뒤에 공백 문자와 추가할 문자열이 붙는다. (위 예시의 1. 참조)
  • =+를 사용하게 되면, A 변수 앞에 공백 문자와 추가할 문자열이 붙는다. (위 예시의 2. 참조)

 

.= (append without space), =. (prepend without space)

A = "aValue"
A .= "AfterNewValue" # 1. aValueAfterNewValue
A =. "BeforeNewValue" # 2. BeforeNewValueaValueAfterNewValue
  • .=와 =.를 통해서 특정 변수에 공백 없이 문자열을 추가할 수 있다.
  • .=를 사용하게 되면, A 변수 뒤에 추가할 문자열이 공백 없이 붙는다. (위 예시의 1. 참조)
  • =.를 사용하게 되면, A 변수 앞에 추가할 문자열이 공백 없이 붙는다. (위 예시의 2. 참조)

 

:append, :prepend

A = "aValue"
A:append  = "AfterNewValue" # 1. aValueAfterNewValue
A:prepend = "BeforeNewValue" # 2. BeforeNewValueaValueAfterNewValue
  • :append와 :prepend를 통해서 특정 변수에 공백 없이 문자열을 추가할 수 있다.
  • :append를 사용하게 되면, A 변수 뒤에 추가할 문자열이 공백 없이 붙는다. (위 예시의 1. 참조) 
  • :prepend를 사용하게 되면, A 변수 앞에 추가할 문자열이 공백 없이 붙는다. (위 예시의 2. 참조)
  • 이 두 연산자는 바로 앞 절의 연산자(.=, =.)와 동일한 연산을 수행하는 것을 알 수 있다. 하지만 아래 예시와 같이 연산이 실행되는 순서에서 차이가 존재한다.
A:append = "AfterNewValue"
A = "aValue" # 1. aValueAfterNewValue
B .= "AfterNewValue"
B = "aValue" # 2. aValue
  • :append 연산은 변수에 특정 값이 할당될 때에 동작한다. 따라서, 위 예시의 1.과 같은 결과를 확인가능하다.
  • .= 연산은 변수에 즉각적으로 할당된다. 따라서, 위 예시의 2.와 같은 결과를 확인가능하다.

 

:remove

FOO = "1 2"
FOO:remove = "2 3"
FOO += "3"
FOO:append = " 4"
  • 공백으로 구분된 문자열 중 특정 문자열을 삭제하기 위해 :remove 연산을 사용할 수 있다.
  • :remove 연산의 경우에는 문자열 추가 연산(+=, .=, :append 등)이 모두 실행된 후에 실행되는 연산자이다.
  • 따라서, 위 예시에서 FOO에는 "1 4"가 최종적으로 저장된다.

 

조건적 변수 할당

OVERRIDES

OVERRIDES = "linux:arm:x86" # 콜론(:)으로 조건에 해당하는 문자열을 구분

A = "value"
A:arm = "armValue" # 1. armValue
A:append:x86 = " x86Value" # 2. armValue x86Value
A:append:non = " nonValue" # 3. armValue x86Value
  • 비트베이크는 파싱을 수행할 때 조건에 따른 변수 할당이 가능하며, 이때에는 OVERRIDES라는 변수를 참조한다.
  • 위 1.~3. 예시와 같이 :<condition> 형식으로 조건적으로 값을 할당 가능하다.
  • 조건이 맞을 경우에는 위 예시의 1.과 같이 A 변수가 변경되는 모습을 확인 가능하다.
  • 조건이 맞을 때 문자열을 추가하고 싶다면 2.와 같이 :append와 :<condition>을 함께 사용하면 된다.
  • 당연히 조건이 맞지 않을 때에는 3.과 같은 결과를 확인 가능하다.

 

파일 포함

include, require

# hello.inc

DESCRIPTION = "Hello application"
LICENSE = "MIT"
SRC_URI = "file://hello.c"

-----------------------------------

# hello.bb

include hello.inc
require hello.inc

include hello_tmp.inc # 1. Warning
require hello_tmp.inc # 2. Parse Error
  • 클래스와 레시피에는 .inc 파일의 내용을 포함시킬 수 있으며, 이를 위해 include와 require 키워드를 사용한다.
  • include는 가져오려는 .inc 파일이 존재하지 않으면 Warning을 발생시키지만 빌드는 종료되지 않는다.
  • require는 가져오려는 .inc 파일이 존재하지 않으면 Parse Error를 발생시키고 빌드가 종료된다.
  • 비트베이크에서 클래스와 레시피에 .inc 파일을 포함할 때에는 .inc 파일의 내용을 그대로 복사/붙여넣기 한다.
  • 레시피에서 특정 클래스를 상속할 때에는 include나 require을 사용하지 않고 inherit 키워드를 사용한다.

 

파이썬 변수

${@<python-command>}

A = "${@time.strftime('%Y%m%d', time.gmtime())}"
  • 변수 할당을 수행할 때에는 ${@<python-command>}와 같은 형식으로 파이썬 함수를 사용가능하다.
A = "${@d.getVar('MACHINE')}"
  • 파이썬 함수에서는 비트베이크의 Bitbake Datastore Object로 접근할 수 있으며, 이때에는 d 객체를 활용한다.

 

함수 정의

Dash 셸(/bin/sh) 함수

do_hello() {
    echo "hello, world"
    echo "${MACHINE}"
}

addtask hello before do_fetch

Python 함수

python do_hello {
    print("hello, world")
    print(d.getVar("MACHINE")
}

addtask hello before do_fetch
  • 태스크를 정의할 때에는 Dash Shell과 Python3 기반으로 작성가능하다.
  • Python으로 태스크를 정의할 때에는 함수명 앞에 python을 붙여준다.
  • 새롭게 정의된 태스크는 addtask 명령을 통해 비트베이크에 등록가능하다.
  • (여기서 addtask 명령의 문법은 다루지 않는다.)

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기