Kernel Module for 2.6

Dec 16, 2013
4 min read
May 31, 2023 18:15 EEST

With Normal Makefile

The hello world program. With normal Makefile, the Makefile:

ARCH		:= i386
CROSS_COMPILE	:= 
#CROSS_COMPILE	:= ppc_6xxx-
INSTALL		:= install -c

INSTALL_DATA	:= $(INSTALL) -m 644
KERNELVERSION	:= $(shell uname -r)
# KERNELVERSION	:= 2.6.16-mpc52xx-gc92bc8e3
EXTRA_CFLAGS 	:= -g -I/usr/realtime/include -I/usr/include/ -ffast-math -mhard-float

KDIR		:= /lib/modules/$(KERNELVERSION)/build
PWD		:= $(shell pwd)

obj-m		:= hello_world.o

all:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
#	gcc -o scope scope.c
clean:
	rm -f *.o *.ko *.mod.o *.mod.c .*.{cmd,flags} Modules.symvers
	rm -rf config.status config.log autom4te*.cache .tmp_versions

The hello_world.c:

#include <linux/module.h>
#include <asm/io.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_fifos.h>

MODULE_LICENSE("GPL");


int init_module(void)
{
   printk("in init_module\n");
   return 0;
}

void cleanup_module(void)
{
   printk("in cleanup_module\n");
   return;
}

With Automake and Autoconf

create the directory structure:

mkdir test
cd test
mkdir src
mkdir m4
touch NEWS
touch README
touch AUTHORS
touch ChangeLog

Now we create the Makefile.am:

ACLOCAL_AMFLAGS = -I m4

SUBDIRS = src
EXTRA_DIST = autogen.sh
  • ACLOCAL_AMFLAGS says aclocal where to look for additional m4 macros
  • SUBDIRS are processed
  • EXTRA_DIST says to include the autogen.sh in our distribution tar

Now we create a m4 script to get the kernel-source named m4/acinclude.m4:

dnl check for kernel source

AC_DEFUN([AC_PATH_KERNEL_SOURCE_SEARCH],
[
  kerneldir=missing
  kernelext=ko
  no_kernel=yes

  if test `uname` != "Linux"; then
    kerneldir="not running Linux"
  else
    for dir in /usr/src/kernel-source-`uname -r` /usr/src/linux-`uname -r` /usr/src/linux /lib/modules/`uname -r`/build ${ac_kerneldir}; do
      if test -d $dir; then
        kerneldir=`dirname $dir/Makefile`/
        no_kernel=no
      fi;
    done
  fi

  if test x${no_kernel} != xyes; then
    if test -f ${kerneldir}/Makefile; then
      if test "${ac_pkss_mktemp}" = "yes"; then
        ac_pkss_makefile=`mktemp /tmp/LIRCMF.XXXXXX`
      else
        ac_pkss_makefile=/tmp/LIRCMF.XXXXXX
      fi
      cat ${kerneldir}/Makefile >${ac_pkss_makefile}
      echo "lirc_tell_me_what_cc_is:" >>${ac_pkss_makefile}
      echo "	echo \$(CC)" >>${ac_pkss_makefile}

      kernelcc=`make -s -C ${kerneldir} -f ${ac_pkss_makefile} lirc_tell_me_what_cc_is`

      echo "lirc_tell_me_what_version_is:" >>${ac_pkss_makefile}
      echo "	echo \$(VERSION)" >>${ac_pkss_makefile}
      echo "lirc_tell_me_what_patchlevel_is:" >>${ac_pkss_makefile}
      echo "	echo \$(PATCHLEVEL)" >>${ac_pkss_makefile}
      version=`make -s -C ${kerneldir} -f ${ac_pkss_makefile} lirc_tell_me_what_version_is`
      patchlevel=`make -s -C ${kerneldir} -f ${ac_pkss_makefile} lirc_tell_me_what_patchlevel_is`
      if test ${version} -eq 2; then
        if test ${patchlevel} -lt 5; then
          kernelext=o
        fi
      fi
      rm -f ${ac_pkss_makefile}
    else
      kerneldir="no Makefile found"
      no_kernel=yes
    fi
  fi
  ac_cv_have_kernel="no_kernel=${no_kernel} \
		kerneldir=\"${kerneldir}\" \
		kernelext=\"${kernelext}\" \
		kernelcc=\"${kernelcc}\""
]
)

AC_DEFUN([AC_PATH_KERNEL_SOURCE],
[
  AC_CHECK_PROG(ac_pkss_mktemp,mktemp,yes,no)
  AC_PROVIDE([AC_PATH_KERNEL_SOURCE])
  AC_MSG_CHECKING(for Linux kernel sources)

  AC_ARG_WITH(kerneldir,
    [  --with-kerneldir=DIR    kernel sources in DIR], 

    ac_kerneldir=${withval}
    AC_PATH_KERNEL_SOURCE_SEARCH,

    ac_kerneldir=""
    AC_CACHE_VAL(ac_cv_have_kernel,AC_PATH_KERNEL_SOURCE_SEARCH)
  )
  
  eval "$ac_cv_have_kernel"

  AC_SUBST(kerneldir)
  AC_SUBST(kernelcc)
  AC_SUBST(kernelext)
  AC_MSG_RESULT(${kerneldir})
]
)

Create now the file configure.ac:

dnl Proccess this file with autoconf to produce a configure script.
AC_INIT(hello_world, 0.1)
AC_PREREQ(2.5)
AC_CONFIG_SRCDIR(src/hello_world.c)
AC_CONFIG_AUX_DIR(config)

AM_INIT_AUTOMAKE(1.8)

dnl Checks for programms
AC_PROG_CC

AC_PATH_KERNEL_SOURCE

default_moduledir=/lib/modules/`uname -r`/misc
AC_ARG_WITH(moduledir,
[  --with-moduledir=DIR    kernel modules in DIR (/lib/modules/`uname -r`/misc)],
moduledir=${withval},
moduledir=${default_moduledir})

AC_SUBST(moduledir)

AC_OUTPUT(Makefile src/Makefile)
  • AC_INIT init the file with project name, version and email address
  • AC_CONFIG_AUX_DIR says autoconf to store tmp file in the dir config to keep the main dir clean
  • AC_CONFIG_SRCDIR where is the program to compile
  • AM_INIT_AUTOMAKE directive to generate the Makefile
  • AC_PROC_CC check for gcc
  • AC_OUTPUT generate the following files from the *.in or *.am files

Now generate the src/Makefile.am:

EXTRA_DIST = Makefile.kernel Makefile.common
EXTRA_PROGRAMS = automake_dummy
automake_dummy_SOURCES = hello_world.c

module_DATA = hello_world.o

include ./Makefile.common
  • “PROGRAMS” is called a primary. Other primaries include:
    • LIBRARIES for static libraries (.a)
    • LTLIBRARIES for Libtool-based shared libraries (.la)
    • HEADERS
  • The prefix “bin_” tells Automake where to copy the resulting program when the user runs make install. Known directory prefixes include:
    • bin_ - for programs, e.g., /usr/local/bin
    • lib_ - where libraries are placed, e.g., /usr/local/lib
    • include_ - where header files are placed, e.g., /usr/local/include
    • pkginclude_ - e.g., /usr/local/include/foobar
    • noinst_ - files that will not be copied anywhere by make install
      Note: The user can specify the locations of these directories when running the configure script. For more info, run configure --help.
  • “SOURCES” is a variable that lists the source files of the program. For programs and libraries, possible variables include:
    • CFLAGS, CPPFLAGS, CXXFLAGS - extra arguments passed to the compiler/preprocessor
    • LIBADD - extra objects for a library
    • LDADD - extra objects for a program
    • LDFLAGS - extra arguments passed to the linker

Create the Makefile.common:

KERNEL_LOCATION=@kerneldir@
KBUILD_VERBOSE = 1

ARCH		:= i386
CROSS_COMPILE	:= 
#CROSS_COMPILE	:= ppc_6xxx-

#KERNELVERSION	:= $(shell uname -r)
# KERNELVERSION	:= 2.6.16-mpc52xx-gc92bc8e3
HELLO_WORLD_EXTRA_CFLAGS = -g -I/usr/realtime/include -I/usr/include/ -ffast-math -mhard-float

PWD		:= $(shell pwd)


export HELLO_WORLD_EXTRA_CFLAGS module_DATA

$(module_DATA): $(automake_dummy_SOURCES)
	mv Makefile Makefile.automake
	cp Makefile.kernel Makefile
	$(MAKE) -C $(KERNEL_LOCATION) SUBDIRS=$(PWD) modules \
		KBUILD_VERBOSE=$(KBUILD_VERBOSE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
	mv Makefile.automake Makefile

CLEANFILES = $(module_DATA) .$(module_DATA).{cmd,flags} .$(module_DATA:.o=.@kernelext@).cmd \
	$(module_DATA:.o=.mod.c) .$(module_DATA:.o=.mod.o.cmd) $(module_DATA:.o=.@kernelext@) \
	Modules.symvers *~

clean:
	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
	rm -rf .tmp_versions 

Create Makefile.kernel:

EXTRA_CFLAGS += $(HELLO_WORLD_EXTRA_CFLAGS)

obj-m=$(module_DATA)
MI_OBJS = $(module_DATA)

all clean:
	$(warning **************************************************)
	$(warning *** Makefile trick not undone, trying to recover *)
	$(warning **************************************************)
	mv Makefile.automake Makefile
	$(MAKE) $@

# The following is needed for 2.5 kernels and also let's the makefile work
# when things get screwed.
ifneq (,$(wildcard $(KERNEL_LOCATION)/Rules.make))
include $(KERNEL_LOCATION)/Rules.make
endif

Related Posts