Search code examples
linux-kernelkbuild

How to add a dependency on a generated source file in Kbuild?


Let generate_testapi.py be a script in my Linux kernel module's source tree, that ingests mymod_test.h and generates a interface source file toward userland (ioctl, debugfs, you name it), and lets name this $(obj)/mymod_test_interfaces.gen.c.

In the Kbuild makefile let mymod-y be the variable containing the list of object files that form the module, i.e.

How does a Kbuild-ish rule look like, that adds the object file compiles from the generates source as a dependency of mymod and describes the generation process.

The following, my first naive attempt on such a rule set does not work.

obj-m := mymod.o

mymod-y := \
    mymod_kmod.o \
    $(obj)/mymod_test_interfaces.gen.o

$(obj)/mymod_test_interfaces.gen.o: $(src)/mymod_test.h $(src)/generate_testapi.py
    $(src)/generate_testapi.py < $(src)/mymod_test.h > $<

Trying to make with that, the resulting error is, that there is no rule to make mymod_test_interfaces.gen.o.

Update (due to comment by Alexandre Belloni)

Yes, I also tried a generator rule of the form

$(obj)/mymod_test_interfaces.gen.c: $(src)/mymod_test.h $(src)/generate_testapi.py
    $(src)/generate_testapi.py < $(src)/mymod_test.h > $<

with the same result, which is, that it does not work.


Solution

  • There is another issue: you can't have a C file that has the same name as the module when trying to build a multiple file module. Rename mymod.c to mymod-core.c

    Then, the following should work:

    obj-m := mymod.o
    
    mymod-objs := mymod-core.o mymod_test_interfaces.gen.o
    
    $(obj)/mymod_test_interfaces.gen.c: $(src)/mymod_test.h $(src)/generate_testapi.py
        $(src)/generate_testapi.py < $(src)/mymod_test.h > $@
    

    I've actually tested the following:

    diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
    index 4387ccb79e64..47fdc3a73c75 100644
    --- a/drivers/misc/Makefile
    +++ b/drivers/misc/Makefile
    @@ -71,3 +71,8 @@ OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \
                            --rename-section .text=.rodata
     $(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o
            $(call if_changed,objcopy)
    +
    +obj-m := mymod.o
    +mymod-objs := mymod-core.o mymod_test_interfaces.gen.o
    +$(obj)/mymod_test_interfaces.gen.c:
    +       echo "int variable;" > $@
    diff --git a/drivers/misc/mymod-core.c b/drivers/misc/mymod-core.c
    new file mode 100644
    index 000000000000..b39aa4b9ae8d
    --- /dev/null
    +++ b/drivers/misc/mymod-core.c
    @@ -0,0 +1,19 @@
    +#include <linux/module.h>
    +#include <linux/platform_device.h>
    +
    +extern int mymod_variable;
    +
    +static int mymod_probe(struct platform_device *pdev)
    +{
    +       mymod_variable = 2;
    +
    +       return 0;
    +}
    +
    +static struct platform_driver mymod_driver = {
    +       .driver = {
    +               .name = "mymod",
    +       },
    +       .probe = mymod_probe,
    +};
    +module_platform_driver(mymod_driver);
    

    It properly results in:

    $ make
      CHK     include/config/kernel.release
      CHK     include/generated/uapi/linux/version.h
      CHK     include/generated/utsrelease.h
      CHK     include/generated/bounds.h
      CHK     include/generated/timeconst.h
      CHK     include/generated/asm-offsets.h
      CALL    scripts/checksyscalls.sh
      CHK     include/generated/compile.h
      CC [M]  drivers/misc/mymod-core.o
    echo "int variable;" > drivers/misc/mymod_test_interfaces.gen.c
      CC [M]  drivers/misc/mymod_test_interfaces.gen.o
      LD [M]  drivers/misc/mymod.o
      LD      arch/x86/boot/compressed/vmlinux
      ZOFFSET arch/x86/boot/zoffset.h
      AS      arch/x86/boot/header.o
      LD      arch/x86/boot/setup.elf
      OBJCOPY arch/x86/boot/setup.bin
      OBJCOPY arch/x86/boot/vmlinux.bin
      BUILD   arch/x86/boot/bzImage