Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
— |
programming:kernel_module_26 [2013/12/16 13:57] (aktuell) idefix angelegt |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | |||
+ | ====== Kernel Module for 2.6 ====== | ||
+ | ===== With Normal Makefile ===== | ||
+ | The hello world program. With normal Makefile, the Makefile: | ||
+ | <code> | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | The hello_world.c: | ||
+ | <code> | ||
+ | #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; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ===== With Automake and Autoconf ===== | ||
+ | |||
+ | create the directory structure: | ||
+ | <code> | ||
+ | mkdir test | ||
+ | cd test | ||
+ | mkdir src | ||
+ | mkdir m4 | ||
+ | touch NEWS | ||
+ | touch README | ||
+ | touch AUTHORS | ||
+ | touch ChangeLog | ||
+ | </code> | ||
+ | |||
+ | Now we create the Makefile.am: | ||
+ | <code> | ||
+ | ACLOCAL_AMFLAGS = -I m4 | ||
+ | |||
+ | SUBDIRS = src | ||
+ | EXTRA_DIST = autogen.sh | ||
+ | </code> | ||
+ | * 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: | ||
+ | <code> | ||
+ | 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}) | ||
+ | ] | ||
+ | ) | ||
+ | </code> | ||
+ | |||
+ | Create now the file configure.ac: | ||
+ | <code> | ||
+ | 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) | ||
+ | </code> | ||
+ | * 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: | ||
+ | <code> | ||
+ | EXTRA_DIST = Makefile.kernel Makefile.common | ||
+ | EXTRA_PROGRAMS = automake_dummy | ||
+ | automake_dummy_SOURCES = hello_world.c | ||
+ | |||
+ | module_DATA = hello_world.o | ||
+ | |||
+ | include ./Makefile.common | ||
+ | </code> | ||
+ | * "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 | ||
+ | * ... | ||
+ | |||
+ | <code> | ||
+ | Note: The user can specify the locations of these directories when running the configure script. For more info, run configure --help.</code> | ||
+ | |||
+ | * "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: | ||
+ | <code> | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | Create Makefile.kernel: | ||
+ | <code> | ||
+ | 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 | ||
+ | </code> | ||