M option in make command, Makefile
Categories:
Understanding the 'M' Option in Make: Building Linux Kernel Modules

Explore the crucial 'M' option in the make
command, specifically its application in compiling Linux kernel modules and device drivers. This article demystifies its usage, provides practical examples, and explains the underlying mechanisms.
When working with the Linux kernel, especially when developing device drivers or custom modules, you'll frequently encounter the make
command. While make
is a powerful build automation tool, its usage for kernel modules introduces specific nuances, primarily through the -M
option. This option is fundamental for telling the kernel's build system how to compile your external module against the currently running or specified kernel source tree. Understanding -M
is key to successfully building and integrating your kernel code.
The Purpose of 'M' in Kernel Module Builds
The -M
option in make
is not a standard make
option; rather, it's a convention adopted by the Linux kernel's build system. When you invoke make -C <kernel_source_dir> M=$(PWD)
, you are essentially instructing the kernel's top-level Makefile to perform a build operation, but with a critical modification: it should look for the actual build targets and source files in the directory specified by M=$(PWD)
. This mechanism allows you to compile your module outside of the kernel source tree, which is the recommended and safest practice.
flowchart TD A[User executes `make -C /lib/modules/$(uname -r)/build M=$(PWD)`] A --> B{Kernel Makefile in `/lib/modules/$(uname -r)/build` is invoked} B --> C["Kernel Makefile reads `M=$(PWD)`"] C --> D["Kernel Makefile sets `KBUILD_EXTMOD` to `$(PWD)`"] D --> E["Kernel Makefile includes `$(KBUILD_EXTMOD)/Makefile`"] E --> F[Your module's Makefile is processed] F --> G[Module source files compiled using kernel headers/configs] G --> H[Module object files (.o) and .ko file generated] H --> I[Build Complete]
Flowchart illustrating the make -C M=
build process for a Linux kernel module.
This separation is crucial for several reasons:
- Cleanliness: It keeps your module's source code distinct from the kernel's, preventing accidental modifications to the kernel source.
- Maintainability: You can update your kernel without affecting your module's source code.
- Flexibility: It allows you to build modules for different kernel versions by simply changing the
<kernel_source_dir>
.
Constructing Your Module's Makefile
For the -M
option to work, your module's directory must contain its own Makefile
. This Makefile
is typically very simple, as it primarily relies on the kernel's build system to handle the complexities of compilation, linking, and module signing. The most common structure involves defining obj-m
for loadable modules or obj-y
for built-in modules.
obj-m := mymodule.o
# If your module consists of multiple source files:
# mymodule-objs := file1.o file2.o
# obj-m := mymodule.o
# Optional: Clean targets
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module.symvers modules.order
Example Makefile for a simple Linux kernel module.
In this Makefile
:
obj-m := mymodule.o
tells the kernel build system thatmymodule.ko
should be built frommymodule.c
(ormymodule.o
if you have multiple source files that compile into a single module).- The
clean
target is a standard practice to remove generated files, making it easy to start a fresh build.
linux-headers-$(uname -r)
and build-essential
. Without them, the kernel build system won't have the necessary files to compile your module.Executing the Build Command
With your module's Makefile
in place, you can now execute the build command from your module's directory. The standard command format is as follows:
make -C /lib/modules/$(uname -r)/build M=$(PWD) modules
Standard command to build a Linux kernel module.
Let's break down this command:
make
: The GNU Make utility.-C /lib/modules/$(uname -r)/build
: This tellsmake
to change its directory to/lib/modules/$(uname -r)/build
before reading any Makefiles.$(uname -r)
expands to the current kernel version (e.g.,5.15.0-76-generic
). This directory usually contains symlinks to the actual kernel source or build tree for the running kernel.M=$(PWD)
: This is the crucial part. It passes the current working directory ($(PWD)
) as the value for theM
variable to the kernel's Makefile. The kernel's Makefile then uses thisM
value to locate your module'sMakefile
and source files.modules
: This is the target that the kernel's Makefile expects for building external modules.
M=$(PWD)
is critical. If you omit M=$(PWD)
, the kernel's Makefile will attempt to build modules from within its own source tree, which is not what you want for external modules and can lead to errors or unintended behavior.1. Create your module's source file
Write your kernel module's C code (e.g., mymodule.c
) in a dedicated directory.
2. Create your module's Makefile
In the same directory, create a Makefile
similar to the example provided, specifying obj-m := mymodule.o
.
3. Navigate to your module's directory
Open a terminal and cd
into the directory containing mymodule.c
and Makefile
.
4. Execute the build command
Run make -C /lib/modules/$(uname -r)/build M=$(PWD) modules
to compile your module. Ensure you have kernel headers installed.
5. Verify the build
Check for the generated mymodule.ko
file in your current directory. You can then load it using sudo insmod mymodule.ko
.