3 분 소요

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를 추가할 때

  1. arch/arm/boot/dts/에 .dts 파일을 만든다
  2. 같은 폴더 Makefile의 dtb-$(CONFIG_ARCH_STM32) += 블록에 .dtb 이름을 넣는다
  3. make 이름.dtb로 빌드한다

새 드라이버를 켤 때

  1. 드라이버 폴더의 Makefile에서 obj-$(CONFIG_XXX) 줄을 찾아 어떤 설정 이름인지 확인한다
  2. .config에서 그 설정을 =m(모듈) 또는 =y(내장)로 바꾼다
  3. =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, 드라이버, 모듈을 모두 관통하고 있었다.

댓글남기기