Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!)

like image 281
Shahbaz Avatar asked Feb 21 '23 22:02

Shahbaz


1 Answers

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
like image 177
alexander Avatar answered Mar 05 '23 16:03

alexander