Search code examples
clinuxmakefilelinux-kernelkbuild

Linux Kernel Makefile.build strange behavior when building external modules


I need some KBuild implementation details advice related to building of external modules.

Linux Kernel 5.0.0-32

Here is my LKM Makefile:

obj-m += pfsw.o
pfsw-objs := src/init.o

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

Looking at the implementation of scripts/Makefile.build and printing the debug output with -d option I found that the target of this makefile being executed is __build:

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
     $(subdir-ym) $(always)
    @:

Since I'm building External LKM the only prerequisites are $(obj-m) and $(modorder-target). I got their values from the database:

obj-m := /home/memyself/lkm/procfs_write_perm/pfsw.o
modorder-target := /home/memyself/lkm/procfs_write_perm/modules.order

So to execute __build the prerequisite /home/memyself/lkm/procfs_write_perm/pfsw.o have to be built first. There is the following $(obj)/%.o: pattern rule defined in Makefile.build:

$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
    $(call cmd,force_checksrc)
    $(call if_changed_rule,cc_o_c)

I added debug output to print the name of the target automatic variable:

$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
    @echo "$@"
    $(call cmd,force_checksrc)
    $(call cmd,force_check_kmsg)
    $(call if_changed_rule,cc_o_c)

and expected /home/memyself/lkm/procfs_write_perm/pfsw.o to be printed, but actually /home/memyself/lkm/procfs_write_perm/src/init.o was printed. This looks like some magic...

QUESTION: Why is building the target /home/memyself/lkm/procfs_write_perm/pfsw.o causes building /home/memyself/lkm/procfs_write_perm/src/init.o? Where does it specified in the code?

I understand that there is the real-obj-m variable containing exactly the value, but greping the code base I did not find it depending on something...


Solution

  • As @Tsyvarev hinted in the comments there is a rule to build obj-m from its -objs.

    When analyzing the behavior I mistakenly considered an implicit pattern rule to build the obj-m which in my case is expanded to /home/memyself/lkm/procfs_write_perm/pfsw.o. Running the build with make -p it is possible to notice the following entry in the output:

    /home/memyself/lkm/procfs_write_perm/pfsw.o: FORCE /home/memyself/lkm/procfs_write_perm/src/init.o
    #  Implicit rule search has not been done.
    #  Implicit/static pattern stem: ''
    #  File is an intermediate prerequisite.
    #  Last modified 2019-12-18 21:13:48.337755924
    #  File has been updated.
    #  Successfully updated.
    # automatic
    # @ := /home/memyself/lkm/procfs_write_perm/pfsw.o
    # automatic
    # % := 
    # automatic
    # * := 
    # automatic
    # + := FORCE /home/memyself/lkm/procfs_write_perm/src/init.o
    # automatic
    # | := 
    # automatic
    # < := FORCE
    # automatic
    # ^ := FORCE /home/memyself/lkm/procfs_write_perm/src/init.o
    # automatic
    # ? := FORCE /home/memyself/lkm/procfs_write_perm/src/init.o
    # variable set hash-table stats:
    # Load=8/32=25%, Rehash=0, Collisions=13/382=3%
    #  recipe to execute (from 'scripts/Makefile.build', line 474):
        $(call if_changed,link_multi-m)
        @{ echo $(@:.o=.ko); echo $(filter %.o,$^); \
           $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod)
    

    So there is a not-implicit rule specifying a recipe to build /home/memyself/lkm/procfs_write_perm/pfsw.o implying that the implicit rule $(obj)/%.o: should not be considered for that specific case.

    The make database entry specified above also contains a line number of the recipe to execute and a file it came from. In this case it is

    recipe to execute (from 'scripts/Makefile.build', line 474):
    

    pointing to the scripts/Makefile.build entry which in my case is

    $(multi-used-m): FORCE
        $(call if_changed,link_multi-m) # <------ This is the line the database points to
        @{ echo $(@:.o=.ko); echo $(filter %.o,$^); \
           $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod)
    $(call multi_depend, $(multi-used-m), .o, -objs -y -m)