클래스와 레시피
- 비트베이크는 클래스(.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 명령의 문법은 다루지 않는다.)