Linux Kernel Programming – Part 3, Multi File Modules

Reading Time: 2 minutes

When you’re developing software, it makes sense to logically structure your code so it’s easier to maintain later on. The same is true with Linux kernel modules. You wouldn’t want to do everything in a single file so there should be a way to make things a bit more organised. 

In this tutorial we’ll take a look at multi file modules. This is a simple fast forward intro to the Kbuild system.

About our multi file module

We’re going to create a kernel module with two source files. Each file can have it’s own sets of conditional compilation attributes and we would like to be able to set or unset those during module compilation.

  • File 1 calls a function which is defined in File 2.
  • Both File 1 and File 2 include one or more common headers including the one which declares the function.

helper.h

#ifndef __HELPER_H__
#define __HELPER_H__
void func_from_2(void);
#endif /*__HELPER_H__*/
 

hello_world_module_2.c

#include <common.h>
#include <linux/module.h>
#include "helper.h"
#ifdef __HELLO_DEBUG__
#define NAME "HELLO_DEBUG_DEFINED"
#else
#define NAME "HELLO_DEBUG_UNDEFINED"
#endif

void func_from_2()
{
	pr_debug("From file %s, NAME = %s\n",
			__FILE__, NAME);
}
 

The hello_world_module_2.c file implements the function declared in helper.h . As can be seen there is conditional compilation for the NAME. We’ll see how to define or undefine this macro within Kbuild file later.

hello_world_module_1.c

#include <common.h>
#include <linux/module.h>
#include "helper.h"

#ifdef __HELLO_DEBUG__
#define NAME "DEFINED"
#else
#define NAME "UNDEFINED"
#endif

static int __init load_module(void)
{
	struct module *__this_mod = THIS_MODULE;
	func_from_2();
	pr_debug("Loading module name %s\n", __this_mod->name);
	pr_debug("In file %s, NAME = %s\n", __FILE__, NAME);
	return 0; /*Extremely important!*/
}

static void __exit unload_module(void)
{
	struct module *__this_mod = THIS_MODULE;

	pr_debug("UnLoading module name %s\n", __this_mod->name);
}

module_init(load_module);
module_exit(unload_module);
 

The file above also consists of a conditional code which is also dependent on the same macro NAME. We can always use -DNAME or -UNAME to define or un define the macro NAME but that would be applied to all the files being compiled

Is it possible to do this on a per file basis? The answer is yes.

Kbuild file for the module

obj-m := hello_world_mod.o
CFLAGS_hello_world_module_2.o := -U__HELLO_DEBUG__
hello_world_mod-objs := hello_world_module_1.o  hello_world_module_2.o
DEBUG_FLAGS := -DDEBUG
ccflags-y := -I$(src)/../common $(DEBUG_FLAGS)
ccflags-y += -D__HELLO_DEBUG__ 

The following are the meanings of the variables used in the above Kbuild file

  • obj-m this is the name of our module. The module would be named hello_world_mod.ko post compilation.
  • hello_world_mod-objs are the object files which make this module. You’ll want to typically list all your real object files. In this case we list our two object files.
  • CFLAGS_hello_world_module_2.o these flags are applied only to this source file. Thus __HELLO_DEBUG__ would be undefined in THIS file only.
  • ccflags-y these are applied to all source files being compiled. Since we’ve defined __HELLO_DEBUG__ for all other files but we want it to be undefined for hello_world_module_2.c file we used the per file CFLAGS.

Note: format is CFLAGS_<file_name.0> for per file CFLAGS.

Output - dmesg

[714888.373462] From file /home/pranay/all_pks_modules/multi_file_module/hello_world_module_2.c, NAME = HELLO_DEBUG_UNDEFINED
[714888.373469] Loading module name hello_world_mod
[714888.373472] In file /home/pranay/all_pks_modules/multi_file_module/hello_world_module_1.c, NAME = DEFINED
 

Get the complete code

You can get the complete code at Github Repository.

Leave a Reply