10

I'm confronting the Linux kernel build system (Kbuild, kernel ≥2.6.28) with the directory structure and build system for a larger project. Our project contains an out-of-tree Linux kernel module, and our directory structure looks like this (simplified, obviously):

checkout/src/common/*.c           source files (common to Linux and other platforms)
checkout/src/linux-driver/*.c     source files (for the Linux kernel driver)
checkout/build/linux/Kbuild       Kbuild
tmp/linux-2.6.xx/                 where the Linux kernel is unpacked and configured
output/linux-arm-debug/           where object files must end up

The build process must not modify anything under checkout, and building the module must not modify anything under tmp/linux-2.6.xx. All output files must end up under output/linux-arm-debug (or whatever architecture and debug variant was selected at build time).

I've read kbuild/modules.txt, and started to write my Kbuild file:

MOD_OUTPUT_DIR = ../../../output/linux-$(ARCH)-$(DEBUG)
obj-m += $(MOD_OUTPUT_DIR)/foo_mod.o
$(MOD_OUTPUT_DIR)/our_module-objs := $(MOD_OUTPUT_DIR)/foo_common.o $(MOD_OUTPUT_DIR)/foo_linux.o

This handles storing the object files in a different directory from where Kbuild lives. Now how can I specify that foo_common.o needs to be compiled from …/checkout/src/common/foo_common.c and foo_linux.o from …/checkout/src/linux-driver/foo_linux.c?

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254

6 Answers6

12

Here is a Makefile which does out of source-tree builds for out of kernel-tree modules (adapted from @Mark's comment)...

KDIR ?= /lib/modules/$(shell uname -r)/build
BUILD_DIR ?= $(PWD)/build
BUILD_DIR_MAKEFILE ?= $(PWD)/build/Makefile

default: $(BUILD_DIR_MAKEFILE)
    make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) modules

$(BUILD_DIR):
    mkdir -p "$@"

$(BUILD_DIR_MAKEFILE): $(BUILD_DIR)
    touch "$@"

clean:
    make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) clean

Note: You still need a Kbuild file...

obj-m += my_driver.o
Sandeep Datta
  • 28,607
  • 15
  • 70
  • 90
  • I didnot understand why we still need a Kbuild file `obj-m += my_driver.o` – GShaik Aug 23 '16 at 12:06
  • It is just a matter of preference. If you want you can add this line to the Makefile. Putting it in the Kbuild file simplifies the Makefile by removing the `ifneq ($(KERNELRELEASE),)` test used to guard this statement in the Makefile. See: http://www.makelinux.net/ldd3/chp-2-sect-4.shtml – Sandeep Datta Aug 24 '16 at 15:55
  • This is so very close to what I need, but sadly it assumes that the module `Makefile` is in the `src` directory, which is not the case for me (it's being built by autoconf, so `Makefile.in` is in the source and `Makefile` in the build/M dir, and likewise for the Kbuild files). – Miral Apr 27 '17 at 03:44
  • 1
    I would feel better about this if `src=` were documented in `modules.txt` :-( – Ciro Santilli OurBigBook.com Sep 30 '18 at 17:27
  • Yes, I know this is several years old, but the issue of what `src=` is doing I feel is an important one. – Benjamin Crawford Ctrl-Alt-Tut Jun 15 '20 at 12:14
3

I had a similar problem. I modified linux_2_6_34/scripts/Makefile.build as follows.

ifdef SRCDIR
src := $(SRCDIR)
else
src := $(obj)
endif

SRCDIR is the directory source.

To compile the module, run

make -c $(KDIR) M=$(Your_output_dir) SRCDIR=$(your source directory)`
Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Jegan
  • 188
  • 3
  • 15
  • So close - the c-files compiled, but it refuses to take the final step to generate the `.ko` (version 3.14.0) – Greg Apr 21 '15 at 12:03
  • Sorry - pebcak - had a bug in my Kbuild - this does the trick - with the proviso that it gets a little confused about which directory and at one stage requires the Kbuild file to be in both directories. That's a small price to pay to get it going – Greg Apr 21 '15 at 13:01
  • This seems to work but for some reason I need to have an empty Makefile in the output directory for this to work (linux-4.1.6) – Kenny Ho Aug 21 '15 at 20:37
  • 3
    I got it to work without modifying `Makefile.build` or any other files: `make -C /path/to/linux-3.16.1/build M=/path/to/module/build src=/path/to/module`. I don't know whether this will work with any other versions of the kernel, but perhaps it will. I did still need `touch Makefile` in the build dir. – Mark Oct 15 '15 at 21:37
  • @Mark for cross compilation, can I write the `Makefile` same as above specified. If so, where I need to specify the cross compiler options. BTW I want to cross compile with arm-eabi-gcc – GShaik Aug 24 '16 at 05:28
  • @AbdulGafoor Not sure what you're referring to "...as above specified". Jegan is modifying a kernel makefile. If you're going to do that, not much reason to do what I did. If you don't want to modify kernel makefiles, create `Makefile` and `Kbuild` as in Example 2, Section 3.2, https://www.kernel.org/doc/Documentation/kbuild/modules.txt - this is what I did. Then (IIRC) you'd specify cross-compile opts when invoking make on `Makefile`, and it would pass them on so Kbuild would see them. Hopefully that works, but I'm rusty on cross-compiling. – Mark Sep 07 '16 at 23:11
2

My inelegant but effective solution is to copy the source files into the output tree.

FOO_SOURCES_DIR = $(src)/../../../checkout/src
FOO_MOD_OUTPUT_DIR = ../../../output/linux-$(ARCH)-$(DEBUG)

# Specify the object files
obj-m += $(FOO_MOD_OUTPUT_DIR)/foo_mod.o
FOO_MODULE_OBJS := $(FOO_MOD_OUTPUT_DIR)/foo_common.o $(FOO_MOD_OUTPUT_DIR)/foo_linux.o
$(FOO_MOD_OUTPUT_DIR)/foo_mod-objs := $(FOO_MODULE_OBJS)

# Where to find the sources
$(src)/$(FOO_MOD_OUTPUT_DIR)/foo_common.c: $(FOO_SOURCES_DIR)/common/foo_common.c
$(src)/$(FOO_MOD_OUTPUT_DIR)/foo_linux.c: $(FOO_SOURCES_DIR)/linux-driver/foo_linux.c

# Rules to copy the sources
FOO_COPIED_SOURCES = $(patsubst %.o,$(src)/%.c,$(FOO_MODULE_OBJS))
$(FOO_COPIED_SOURCES):
        $(Q)mkdir -p $(@D)
        cp -f $< $@
clean-files += $(FOO_COPIED_SOURCES)
clean-dirs += $(FOO_MOD_OUTPUT_DIR)
Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
  • Copy? At least make symbolic links _once_ and then leave it be! – Shahbaz Mar 27 '13 at 17:49
  • 2
    @Shahbaz Symbolic links don't always work in build trees. They tend to be included as symlinks in archivers. I even had to work on Samba exports at some point (ugh). Copying a handful of source files in a Linux kernel build tree is peanuts. – Gilles 'SO- stop being evil' Mar 27 '13 at 18:14
1

While you haven't mentioned what you've tried so far (or whether you found a solution already), it looks like you just need to continue further down the modules.txt file a bit -- to Section 4.3:

--- 4.3 Several Subdirectories

kbuild can handle files that are spread over several directories.
Consider the following example:

.
|__ src
|   |__ complex_main.c
|   |__ hal
|   |__ hardwareif.c
|   |__ include
|       |__ hardwareif.h
|__ include
    |__ complex.h

To build the module complex.ko, we then need the following
kbuild file:

    --> filename: Kbuild
    obj-m := complex.o
    complex-y := src/complex_main.o
    complex-y += src/hal/hardwareif.o

    ccflags-y := -I$(src)/include
    ccflags-y += -I$(src)/src/hal/include

As you can see, kbuild knows how to handle object files located
in other directories. The trick is to specify the directory
relative to the kbuild file's location. That being said, this
is NOT recommended practice.

For the header files, kbuild must be explicitly told where to
look. When kbuild executes, the current directory is always the
root of the kernel tree (the argument to "-C") and therefore an
absolute path is needed. $(src) provides the absolute path by
pointing to the directory where the currently executing kbuild
file is located.
jpihl
  • 7,941
  • 3
  • 37
  • 50
Joe Friedrichsen
  • 1,976
  • 14
  • 14
  • 4
    I've read that part, and I'm at a loss as to how this helps me. In that example, `complex_main.c` and `complex_main.o` are in the same directory. In my build tree, sources and build products are completely separate. – Gilles 'SO- stop being evil' Apr 28 '11 at 19:49
0

A bit late, but it looks like O= flag is what you need.

dimba
  • 26,717
  • 34
  • 141
  • 196
  • It does look right. I'd be surprised if I hadn't tried it, but it's been a while and I've moved on to other projects, so I can't honestly be sure. Thanks for your suggestion, I'll try to find the opportunity to try it. – Gilles 'SO- stop being evil' Jun 01 '12 at 20:29
  • 7
    Not working for me - it seems like `O=` and `KBUILD_OUTPUT` both need to be applied at the point where you build the kernel itself, not just the external modules. What I see is errors finding generated files within the source tree - for example `linux/version.h` - its looking for them in the O= location. – Greg Apr 21 '15 at 11:57
-1

You can set the environment variable KBUILD_OUTPUT. This functions similar to the O= option; however, since it's an environment variable, it can span multiple makefiles where O= can't be passed or an out-of-directory module needs to be built. I was having this same issue with trying to build a set of compat-wireless modules and I needed to use O= for the actual kernel image build.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
kcstrom
  • 422
  • 3
  • 10