5

Here is my cmake to build linux kernle hello world module.

if ( UNIX )
    # Version number
    set ( DRV_MAJOR 1 )
    set ( DRV_MINOR 0 )
    set ( DRV_PATCH 0 )

    set ( DRV_VERSION ${DRV_MAJOR}.${DRV_MINOR}.${DRV_PATCH} )

    configure_file( drv_config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/drv_config.h )
    execute_process(COMMAND uname -r
                    OUTPUT_VARIABLE os_version
                    OUTPUT_STRIP_TRAILING_WHITESPACE)

    set(module_path /lib/modules/${os_version})
    set(module_build_path ${module_path}/build)

    add_custom_command(OUTPUT drv.ko
                       COMMAND ${CMAKE_MAKE_PROGRAM} -C ${module_build_path} M=${CMAKE_CURRENT_SOURCE_DIR}
                       DEPENDS driver.c Kbuild
                       COMMENT "Building drv.ko"
                      )

    add_custom_target(drv ALL DEPENDS drv.ko)

endif( UNIX )

And my Kbuild :

obj-m += drv.o
drv-objs := driver.o

How can I specify the output directory for all object files and related stuff? For the moment build stuff is generated at the source directory location. And I'd like not to mix source and obj files. Any ideas?

Dmitry
  • 1,912
  • 2
  • 18
  • 29

2 Answers2

9

This answer above helped me, figure it out. If someone is curious upon how.

Check out it out and gitlab: https://gitlab.com/christophacham/cmake-kernel-module

In the end the cmake file looks like the following:

cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)

project(driver VERSION 0.1.0 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

# Find kernel headers
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(KernelHeaders REQUIRED)
include_directories(${KERNELHEADERS_INCLUDE_DIRS})

set(DRIVER_FILE hello.ko)
set(KBUILD_CMD ${CMAKE_MAKE_PROGRAM} -C ${KERNELHEADERS_DIR} modules M=${CMAKE_CURRENT_BINARY_DIR} src=${CMAKE_CURRENT_SOURCE_DIR})

# Generate the Kbuild file through cmake.
FILE(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/Kbuild "obj-m := hello.o")

add_custom_command(OUTPUT ${DRIVER_FILE}
        COMMAND ${KBUILD_CMD}
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        DEPENDS hello.c VERBATIM)

add_custom_target(driver ALL DEPENDS ${DRIVER_FILE})

This together with the FindKernelHeaders.cmake allowed me to build the kernel module with cmake in a build folder. It was never meant to be shared, but was done anyway as there seems to be interest in this question.

Christoph Acham
  • 101
  • 1
  • 3
  • 4
    If anyone wants to use CLion, I found that to stop the editor from complaining about ```MODULE_LICENSE``` and so on, you need to add ```add_definitions(-D__KERNEL__ -DMODULE)``` somewhere in your CMakeLists.txt I also had to add a dummy target: ```add_library(dummy_target hello.c)``` so it would parse the source file in the first place. – MerseyViking Dec 13 '19 at 13:22
  • I had to modify `FindKernelHeaders.cmake` in order to find the header files on Ubuntu. Change line 11 to `PATHS /usr/src/linux-headers-${KERNEL_RELEASE}` (was `PATHS /usr/src/kernels/${KERNEL_RELEASE}` – phip1611 Sep 26 '20 at 15:13
  • I added all information + changes I had to make to fit my needs into a forked project. Thanks to Christoph Acham and MerseyViking for their constributions and ideas! https://gitlab.com/phip1611/cmake-kernel-module – phip1611 Oct 23 '20 at 22:26
0

Referring to this answer: https://stackoverflow.com/a/37858314 it seems that a solution is:

COMMAND ${CMAKE_MAKE_PROGRAM} -C ${module_build_path} 
        M=${CMAKE_CURRENT_BINARY_DIR} src=${CMAKE_CURRENT_SOURCE_DIR}
Lee
  • 11
  • 3
  • Thanks, this almost worked for me, but the modpost stage gives an error saying that it cannot find `${CMAKE_CURRENT_BINARY_DIR}/Makefile` – haggai_e Nov 25 '19 at 19:53