1

I organized the kernel modules as different sub-component, so I can easily insert/remove existing sub-module to try or integrating stuff.

The directory layout is shown as below:

foo --+-- Makefile
      |
      +-- main.c
      |
      +-- include --+-- foo1.h
      |             |
      |             +-- ... (other headers)
      |
      |
      +-- src ------+-- foo1.c
                    |
                    +-- ... (other sources)

Here's my Makefile,

MODULE_NAME = foo
obj-m += $(MODULE_NAME).o

# [approach 1-1]
# SRCS := main.c src/foo1.c

# [approach 1-2]
SRCS := main.c $(wildcard src/*.c)

$(MODULE_NAME)-objs += main.o $(SRCS:.c=.o)

all:
        # [2] echo to check if foo-objs values changes
        echo $($(MODULE_NAME)-objs)
        KCFLAGS="-I$(PWD)/include" \
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

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

I got warning shown as below when I tried to replace approach [1-1] with [1-2] in my Makefile above.

WARNING: "InitFoo1" [.../foo/foo.ko] undefined!
WARNING: "CleanuptFoo1" [.../foo/foo.ko] undefined!

From the console output, I don't see the src/foo1.c got compiled as if I am using approach [1-1] in Makefile.

# [2] echo to check if foo-objs values changes
echo main.o main.o src/foo1.o
main.o main.o src/foo1.o
KCFLAGS="-I/home/cyng93/experiment/issues/so_kbuild_wildcard/include" \
make -C /lib/modules/4.4.23-PT-ProbeOn-AuditOn+/build M=/home/cyng93/experiment/issues/so_kbuild_wildcard modules
make[1]: Entering directory '/linux'
  CC [M]  /home/cyng93/experiment/issues/so_kbuild_wildcard/main.o
  LD [M]  /home/cyng93/experiment/issues/so_kbuild_wildcard/foo.o
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "InitFoo1" [/home/cyng93/experiment/issues/so_kbuild_wildcard/foo.ko] undefined!
WARNING: "CleanupFoo1" [/home/cyng93/experiment/issues/so_kbuild_wildcard/foo.ko] undefined!
  CC      /home/cyng93/experiment/issues/so_kbuild_wildcard/foo.mod.o
  LD [M]  /home/cyng93/experiment/issues/so_kbuild_wildcard/foo.ko
make[1]: Leaving directory '/linux'

I try to echo foo-objs(check [2] in Makefile) and found out that the value are the same for both approach [1-1] & [1-2].

Does anyone on SO has came up with similar issues can help to shade some light on ?

(I prefer [1-2] because it can save my effort from updating the Makefile when new sub-component is added)

Below I also attached the source code of main.c, foo1.c & foo1.h. You can also check the github repo for this issue for easier access to those code.


main.c

#include <linux/module.h>
#include "foo1.h"


static int myinit(void)
{
    printk("Module inserted!\n");
    InitFoo1();

    return 0;
}

static void myexit(void)
{
    CleanupFoo1();
    printk("Module removed!\n");
}

module_init(myinit);
module_exit(myexit);

MODULE_LICENSE("GPL v2");

Here, foo1 is a sub-component, where simply print out some stuff during its intialization and cleanup:

./include/foo1.h

#ifndef FOO1_H
#define FOO1_H

int InitFoo1(void);
void CleanupFoo1(void);

#endif

./src/foo1.c

#include <linux/module.h>
#include "foo1.h"


int InitFoo1(void)
{
    printk("Init Foo1\n");
    return 0;
}


void CleanupTest(void)
{
    printk("Cleanup Foo1\n");
}

update_2018/01/15

According to Tsyvarev answer below, one can correct the Makefile by modifying Makefile as below:

MODULE_NAME = foo
obj-m += $(MODULE_NAME).o

# [approach 1-1]
# SRCS := main.c src/foo1.c

# [approach 1-2 (not working)]
# SRCS := main.c $(wildcard src/*.c)

# [approach 1-2 (working)]
MISC := $($(src)/wildcard src/*.c)
SRCS := main.c $(MISC:$(src)%/=%)

$(MODULE_NAME)-objs += main.o $(SRCS:.c=.o)

all:
        # [2] echo to check if foo-objs values changes
        echo $($(MODULE_NAME)-objs)
        KCFLAGS="-I$(PWD)/include" \
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
cyng93
  • 13
  • 3
  • Based on what you've shown here I can't explain this behavior. You should invoke make with the `-p` option to have it dump its internal rules and make sure that the `src/foo1.o` files are listed as prerequisites where you'd expect them, and invoke make with the `-d` option to see what it does and why it's not building `foo1.o`. – MadScientist Jan 12 '18 at 18:51
  • Thanks for pointing out these tricks that can help to have better understanding on stuff happen behind the make process. :) But I believe the main reason I struggled in this issues in due to lack of the understanding in KBuild flow. :( – cyng93 Jan 15 '18 at 10:07

1 Answers1

0

When build the kernel module your Makefile is processed twice:

  1. When you type make from your module's directory.
  2. Inside Kbuild process, because you pass M=$(PWD) option to it.

First time the Makefile is processed with current directory equal to the module's directory. So wildcard works as expected, which is confirmed by printing from all receipt.

But the second time the Makefile is processed with current directory equal to kernel's build directory (/lib/modules/4.4.23-PT-ProbeOn-AuditOn+/build in your case). In that mode

$(wildcard src/*.c)

attempts to find a file in kernel's build directory, which obviously fails.


At the time of second processing one may refer to module's build directory with $(src).

Such way one may use wildcard() for collect module's sources. But note, that Kernel build system expects path to source file (more precisely, to object file) to be relative to module's build directory. So, one need to strip $(src) component of every file obtained with wildcard().

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • Thanks for pointing this critical point on kbuild flow! By the way, is it a good practice to use $(src) instead of $(PWD) when referring to *module's build directory*, or they are not likely to make any difference? – cyng93 Jan 15 '18 at 10:02
  • `is it a good practice to use $(src) instead of $(PWD) when referring to module's build directory` - I am not sure, but at the second Makefile's processing `$(PWD)` would refer to *kernel's build directory*, so you have no choice other than use `$(src)`. – Tsyvarev Jan 15 '18 at 20:17