Kernel Module for 2.6
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