I have a question for those of you who may have a copy of the O'Reilly
book "Linux Device Drivers, Third Edition" and are reasonably familiar
with it.

If you don't have it, it's available in PDF form at
http://lwn.net/Kernel/LDD3.

Starting on page 16 there is a sample "Hello World" kernel module that
looks like this:

#include
#include

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}

static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

A bare-bones simple makefile to compile that looks like this:

obj-m := hello.o

.... which is used with the following command line:

make -C /usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.i686kernel-2.6
M=`pwd` modules

....where /usr/src/... is the path to the kernel source tree.

So far that works, and I am able to build, insert, and remove the module
hello.ko, getting the "Hello, world" and "Goodbye,cruel world" messages at
the proper times.

Now on page 24 of the book it shows a slightly more complex makefile that
can be used by simply typing "make" instead of "make -C ~/kernel-2.6
M=`pwd` modules". That makefile looks like this:

# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

The text goes on to explain the above makefile thus:

"Once again, we are seeing the extended GNU make syntax in action. This
makefile is read twice on a typical build. When the makefile is invoked
from the command line, it notices that the KERNELRELEASE variable has not
been set. It locates the kernel source directory by taking advantage of
the fact that the symbolic link build in the installed modules directory
points back at the kernel build tree. If you are not actually running
the kernel that you are building for, you can supply a KERNELDIR= option
on the command line, set the KERNELDIR environment variable, or rewrite
the line that sets KERNELDIR in the makefile. Once the kernel source tree
has been found, the makefile invokes the default: target, which runs a
second make command (parameterized in the makefile as $(MAKE)) to invoke
the kernel build system as described previously. On the second reading,
the makefile sets obj-m, and the kernel makefiles take care of actually
building the module."

Here is where things stop working... I type "make" and I get "Nothing to
do for target default".

"/lib/modules/$(shell uname -r)/build" does point to the target source.

I said "export MAKE=/usr/bin/make" to create a MAKE environment variable,
which didn't exist before.

I tried plugging in a hard path in place of the PWD line and also revised
KERNELDIR as suggested in the explanatory text from the book.

Nothing works... still can't get the module to build.

Have any of you who may have learned device driver programming from this
book run across this and do you have a solution?