2010年9月12日 星期日

DKMS和KERNELRELEASE變數

當 Makefile 是從 kernel build system 被呼叫執行時,KERNELRELEASE 變數會被 kbuild 定義。

這是一個常見的 Makefile 小技巧,判斷 KERNELRELEASE 是否定義來執行不同的設定。

如下列是compat-wireless的Makefile,就用到這樣的技巧:

  1. (SKIP)

  2. ifneq ($(KERNELRELEASE),)

  3. NOSTDINC_FLAGS := -I$(M)/include/ \
  4. -include $(M)/include/linux/compat-2.6.h \
  5. $(CFLAGS)

  6. obj-y := compat/

  7. obj-$(CONFIG_COMPAT_RFKILL) += net/rfkill/

  8. ifeq ($(BT),)
  9. obj-$(CONFIG_COMPAT_WIRELESS) += net/wireless/ net/mac80211/
  10. obj-$(CONFIG_COMPAT_WIRELESS_MODULES) += drivers/net/wireless/


  11. endif


  12. else

  13. export PWD := $(shell pwd)
  14. CFLAGS += \
  15. -DCOMPAT_BASE_TREE="\"$(shell cat compat_base_tree)\"" \
  16. -DCOMPAT_BASE_TREE_VERSION="\"$(shell cat compat_base_tree_version)\"" \
  17. -DCOMPAT_PROJECT="\"Compat-wireless\"" \
  18. -DCOMPAT_VERSION="\"$(shell cat compat_version)\""

  19. # These exported as they are used by the scripts
  20. # to check config and compat autoconf
  21. export COMPAT_CONFIG=config.mk
  22. export CONFIG_CHECK=.$(COMPAT_CONFIG)_md5sum.txt
  23. export COMPAT_AUTOCONF=include/linux/compat_autoconf.h
  24. export CREL=$(shell cat $(PWD)/compat_version)
  25. export CREL_PRE:=.compat_autoconf_
  26. export CREL_CHECK:=$(CREL_PRE)$(CREL)

  27. include $(PWD)/$(COMPAT_CONFIG)

  28. all: modules

  29. modules: $(CREL_CHECK)
  30. @./scripts/check_config.sh
  31. $(MAKE) -C $(KLIB_BUILD) M=$(PWD) modules
  32. @touch $@

  33. (SKIP)

  34. endif


當從 shell 執行 make 時,因為 KERNELRELEASE 沒有定義,所以第23行到第39行之間的一些變數和 CFLAGS 會被設定,然後第45行會呼叫 kbuild 的 Makefile:
$(MAKE) -C $(KLIB_BUILD) M=$(PWD) modules

之後 compat-wireless 的 Makefile 又會被呼叫一次,此時 KERNELRELEASE 已經被 kbuild 所定義,所以第5行到第18行會被執行。而做的事情就如同一般的 module Makefile 將 driver 的路徑加入 obj-$CONFIG_* 中,如第15行:
obj-$(CONFIG_COMPAT_WIRELESS_MODULES) += drivers/net/wireless/




不過,DKMS 在 build module 時會自己傳入 KERNELRELEASE 這個參數,如在 /usr/sbin/dkms:function do_build():
local the_make_command=`echo $make_command | sed "s/^make/make KERNELRELEASE=${kernelver_array[0]}/"`


我們可以看到,在 compat-wireless 的 Makefile 中,當 KERNELRELEASE 變數已被設值時,並沒有 target 可以 build,必須是經由 kbuild 的 Makefile 來 make 才可以。

所以一個 workaround 是在 dkms.conf 中將 MAKE[0] 寫成 make -C /lib/modules/`uname -r`/build M=`pwd` modules。但是在這個例子中我們還必須先在 CLFAGS 中加入一些 define。直接呼叫kbuild的話,這些 CFLAGS 都沒設定,這樣並無法正確的 build 出 module。

所以,一個可行的辦法是將 Makefile 拆開,然後在 dkms.conf:MAKE[0] 中自行指定 Makefile,如:
make -f dkms.mk


雖然必須更改原始的 Makefile,但是卻可讓 DKMS 正確運作。

沒有留言: