Search code examples
linuxvariablesmakefilekbuild

Makefile variable substitution apparently not done even though := is used in declaration


I have a main kernel module with which other kernel modules communicate. I have structured the modules like this (conceptually):

main module/
           |
            \drivers/
                    |
                    |\driver1
                    |\driver2
                     \driver3

Since these are kernel modules, I need to compile them like this:

make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules

However, since the Makefile of drivers can be called from previous directories, I need to do the $(shell pwd) before calling the other make (linux's make). So the Makefile now looks like this:

CURRENT_DIR := $(shell pwd)

.PHONY: all
all:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(CURRENT_DIR) modules

So far it is fine and it works perfectly. The problem is this: I have a file that the drivers need to include, so I have to give the include path to make. I first tried

EXTRA_CFLAGS += -I../..

and immediately understood why it doesn't work (relative path would be to /lib/module/... not to current directory). So I changed it to:

MAIN_MODULE_HOME := $(CURRENT_DIR)/../..
EXTRA_CFLAGS += -I$(MAIN_MODULE_HOME)

Oddly enough, this doesn't work! If I write

EXTRA_CFLAGS += -Ipath/I/get/from/pwd/../..

manually, it compiles! Can someone explain what I am doing wrong? Before calling make, I echoed $(CURRENT_DIR) and $(MAIN_MODULE_HOME) and the variables are meaningful.

I know that EXTRA_CFLAGS is not immediately evaluated, but since CURRENT_DIR and MAIN_MODULE_HOME are declared with := I don't understand how things are getting messed up.

(If anyone can phrase the question title better, please do!)


Solution

  • You should pass EXTRA_CFLAGS to make like this:

    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(CURRENT_DIR) \
               EXTRA_CFLAGS="$(EXTRA_CFLAGS)" modules
    

    Update:

    The content of driver1/Makefile is read twice: first - when you run make inside driver1 directory, second - by Kbuild system.

    First, CURRENT_DIR := $(shell pwd) is evaluated to something like /home/users/.../main module/drivers/driver1. Second, Kbuild evaluates CURRENT_DIR := $(shell pwd) to something like /usr/src/linux-headers-2.6.32-33-generic/

    That situation described in LDD3, ch2, p24

    The trick is to write your makefile as follows:

    # If KERNELRELEASE is defined, we've been invoked from the
    # kernel build system and can use its language.
    ifneq ($(KERNELRELEASE),)
        obj-m := hello.o
    # Otherwise we were called directly from the command
    # line; invoke the kernel build system.
    else
        KERNELDIR ?= /lib/modules/$(shell uname -r)/build
        PWD  := $(shell pwd)
    default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    #endif