0

I am trying to learn linux kernel module building and kbuild by following https://www.tldp.org/LDP/lkmpg/2.6/lkmpg.pdf and reading GNU make manual.

Here is the Makefile of the first example, Hello-1, on The Linux Kernel Module Programming Guide:

obj-m += hello-1.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

AFAIK, obj-m should be read by kbuild. However according to GNU Make manual, I understand that obj-m shouldn't be exported.

Except by explicit request, make exports a variable only if it is either defined in the environment initially or set on the command line, and if its name consists only of letters, numbers, and underscores. Some shells cannot cope with environment variable names consisting of characters other than letters, numbers, and underscores.

https://www.gnu.org/software/make/manual/html_node/Variables_002fRecursion.html

obj-m is neither defined in the environment initially nor set on command line. So I expect that it shouldn't exported to recipe of target all. How does kbuild access obj-m?

ayazar
  • 145
  • 1
  • 11
  • That's a bad example. You should _always_ invoke a recursive make using the variable `$(MAKE)` and _never_ with a hardcoded `make` command as shown above. – MadScientist Jun 07 '18 at 16:55
  • @MadScientist Yep, you are right. We also discussed this issue under answer post. This was the example Makefile given in The Linux Kernel Module Programming Guide – ayazar Jun 08 '18 at 06:01
  • I know, that's what I was trying to say: the example given in that guide is a bad example. – MadScientist Jun 08 '18 at 11:28

1 Answers1

1

Your makefile calls a submake and passes it the make variable M that points to the current directory. The submake is invoked with the -C option such that it is run as if it was invoked from the specified directory, that is the kernel source directory. It is thus the kernel build system with its own makefiles that is used. Thanks to the M variable the kernel makefiles know where they can find your makefile and include it with its obj-m definition.

Note: the makefile you show should probably be modified a bit with conditionals such that only the obj-m variable definition is visible from the Linux build system. Else, there is a risk of collision between the all and clean targets of your makefile and targets with the same names in the kernel makefiles. And, as noted by MadScientist, using make is not a good idea; $(MAKE) is preferable. You should probably use something like:

ifeq ($(KERNELRELEASE),)
all:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
else
obj-m += hello-1.o
endif
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • Inclusion of Makefile makes sense. Now I understand why authors of LDD3 keep saying that Makefile is read twice. Your improvement with if statement is very similar to LDD3 recommended way and I understand now. Maybe, it would be better if I switch make with $(MAKE) too. Thank you. – ayazar Jun 07 '18 at 14:42
  • @Alper Absolutely, `$(MAKE)` must be preferred. Note: if you are curious and want to know which makefile of the kernel build system includes yours, just change the name of your makefile and use the `-f` option when invoking make. You should get an error about `Makefile not found` and the error message should tell you which kernel makefile encountered the problem and at which line. – Renaud Pacalet Jun 07 '18 at 14:45
  • Wow! Subtle way of debugging. I checked and saw that scripts/Makefile.build:44 gave error which corresponds to Makefile.bulid code snippet that is written at first revision of your message. – ayazar Jun 07 '18 at 14:54