dtb-$(CONFIG_…) += 한 줄로 이해하는 커널 Makefile
SC6_0 보드용 DTS 파일을 처음 만들었을 때, 빌드 명령이 거부됐다. make stm32mp157a-sc6-v1.dtb를 실행하자 No rule to make target, 즉 “그걸 만드는 규칙이 없다”며 멈췄다.
파일은 분명히 있는데 규칙이 없다고 했다. arch/arm/boot/dts/Makefile에 파일 이름을 한 줄 넣으니 해결됐고, 그 뒤로는 새 DTB를 만들 때마다 같은 일을 반복했다. 최근 블루투스 진단용 DTB를 하나 더 만들면서 이 한 줄이 정확히 무슨 일을 하는지 들여다봤다.
1. 그 한 줄
우리 DTB 이름을 넣은 곳은 이런 블록 안이다.
dtb-$(CONFIG_ARCH_STM32) += \
stm32f429-disco.dtb \
...
stm32mp157c-ya157c-v2.dtb \
stm32mp157a-sc6-v1.dtb \ ← 우리 보드
stm32mp157a-sc6-v1-bttest.dtb \ ← 블루투스 진단용
...
조금 내려가면 같은 모양의 블록이 다른 칩 제조사마다 반복된다.
dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-ast2500-evb.dtb \
...
기호를 하나씩 풀면 이렇다.
| 부분 | 뜻 |
|---|---|
$(CONFIG_ARCH_STM32) |
.config에서 이 설정값을 꺼내 그 자리에 넣는다 |
+= |
목록 뒤에 이어 붙인다 |
\ |
다음 줄과 한 줄로 이어진다 |
2. 변수 이름 자체가 바뀐다
이 문법의 핵심은 첫 번째 줄이다. $(CONFIG_ARCH_STM32)가 값으로 치환되면서 변수 이름이 달라진다.
.config 에 CONFIG_ARCH_STM32=y → dtb-y += ... ← 빌드 목록
.config 에 설정이 없음 → dtb- += ... ← 아무도 안 보는 변수
if문이 하나도 없는데 “설정을 켜면 포함, 끄면 제외”가 된다. 설정이 꺼져 있으면 목록이 dtb-라는 쓸데없는 변수에 모이고, 그 변수는 어디서도 쓰이지 않으니 자연스럽게 버려진다.
3. 그 목록을 누가 쓰나
커널 빌드 시스템(Kbuild)의 공통 규칙 파일에 답이 있다.
# scripts/Makefile.lib
extra-y += $(dtb-y)
dtb-y에 모인 이름들을 “이 폴더에서 만들어야 할 대상”(extra-y)으로 등록한다. 그래서 두 가지가 정해진다.
make dtbs를 하면dtb-y에 있는 것을 전부 빌드한다make 이름.dtb처럼 하나만 빌드하려면, 그 이름이 목록에 등록돼 있어야 한다
처음에 본 No rule to make target이 두 번째 경우다. DTS 파일이 있어도 목록에 이름이 없으면 Kbuild는 그 DTB를 만드는 방법을 모른다.
4. 우리 .config에서 본 것
.config를 확인해보니 예상 밖의 값이 있었다.
CONFIG_ARCH_STM32=y
CONFIG_ARCH_ASPEED=y
벤더 커널 설정이 여러 회사의 칩을 함께 지원하는 범용 설정이라, 우리와 상관없는 ASPEED 칩 지원까지 켜져 있다. 다른 칩 제조사 항목도 비슷할 것이다.
그러면 make dtbs는 STM32뿐 아니라 켜진 모든 칩의 DTB를 만든다. 우리 보드 DTB 하나가 필요할 때 그럴 이유가 없다. 그래서 빌드 스크립트에서는 항상 이름을 지정한다.
~/work/kbuild.sh stm32mp157a-sc6-v1.dtb
이름을 지정하는 방식이 빠르기도 하지만, 그렇게 하려면 결국 목록 등록이 필수라는 점에서 앞의 이야기와 연결된다.
5. 같은 문법이 드라이버에도 쓰인다
이 패턴은 DTB만의 것이 아니다. 커널 전체 Makefile이 같은 방식으로 짜여 있다. QCA7005 PLC 모뎀 드라이버를 켤 때 바꾼 설정이 바로 이 방식으로 동작했다.
# drivers/net/ethernet/qualcomm/Makefile
obj-$(CONFIG_QCA7000) += qca_7k_common.o
obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
드라이버 쪽은 값이 하나 더 있다.
.config 값 |
바뀐 변수 | 결과 |
|---|---|---|
=y |
obj-y |
커널 이미지 안에 들어간다 |
=m |
obj-m |
별도 모듈(.ko)로 만든다 |
| 없음 | obj- |
빌드하지 않는다 |
우리는 이렇게 바꿨다.
- # CONFIG_QCA7000_SPI is not set
+ CONFIG_QCA7000=m
+ CONFIG_QCA7000_SPI=m
=m이었기 때문에 obj-m으로 들어갔고, qcaspi.ko 파일이 따로 만들어졌다. 덕분에 커널 이미지는 다시 빌드하지 않고 모듈 파일 두 개만 보드에 넣을 수 있었다. =y였다면 커널 이미지 전체를 다시 만들어 교체해야 했다.
세 번째 줄 qcaspi-objs도 같이 봐둘 만하다. qcaspi.ko 모듈 하나가 소스 파일 세 개(qca_7k.c, qca_debug.c, qca_spi.c)를 묶어서 만들어진다는 뜻이다. 모듈 이름과 소스 파일 이름이 달라도 되는 이유다.
6. 실전 체크리스트
이 원리를 알고 나니, 무언가를 추가할 때 손댈 곳이 명확해졌다.
새 DTB를 추가할 때
arch/arm/boot/dts/에.dts파일을 만든다- 같은 폴더
Makefile의dtb-$(CONFIG_ARCH_STM32) +=블록에.dtb이름을 넣는다 make 이름.dtb로 빌드한다
새 드라이버를 켤 때
- 드라이버 폴더의
Makefile에서obj-$(CONFIG_XXX)줄을 찾아 어떤 설정 이름인지 확인한다 .config에서 그 설정을=m(모듈) 또는=y(내장)로 바꾼다=m이면 모듈만 빌드해서 보드의/lib/modules/아래에 넣는다
드라이버 설정 이름을 모를 때는 Makefile부터 보면 된다. obj-$(CONFIG_...) 줄이 “이 파일을 켜는 스위치가 무엇인지”를 그대로 알려준다.
정리
.config 의 설정값 (y / m / 없음)
│ $(CONFIG_...) 치환
▼
변수 이름이 dtb-y / obj-y / obj-m / dtb- 로 바뀜
│
▼
Kbuild 는 dtb-y, obj-y, obj-m 목록만 골라서 빌드
No rule to make target을 처음 봤을 때는 Makefile에 이름을 넣으면 된다는 것만 알고 넘어갔다. 원리를 보고 나니 “목록에 없으면 존재하지 않는 것과 같다”는 한 문장으로 정리된다. 그리고 같은 원리가 DTB, 드라이버, 모듈을 모두 관통하고 있었다.
댓글남기기