:= or += when compiling Linux kernel modules? - linux-kernel

Tutorials for compiling the kernel module for Linux, use different syntax for the Makefile.
Example 1
obj-m += rpi-pwm.o
Example 2
obj-m := nothing.o
What are the differences, and is there a preferred way?

:= would set the variable obj-m to nothing.o. This implies that if obj-m was previously set then it would be replaced by nothing.o.
+= would add rpi-pwm.o to the variable obj-m. If obj-m was previously set to nothing.o, then it'd become nothing.o rpi-pwm.o.
Saying
obj-m += rpi-pwm.o
is equivalent to saying
obj-m := $(obj-m) rpi-pwm.o

Related

How to add multiple Headers files path in a Makefile?

I am trying to compile uleds.c driver and this driver includes multiple files existing under this path :
/opt/poky-atmel/2.5.3/sysroots/cortexa5hf-neon-poky-linux-gnueabi/usr/src/kernel/include/linux
I want now to modify my Makefile and add this path so I can compile correctly uleds.c
This is my Makefile :
#CC=arm-poky-linux-gnueabi-gcc -march=armv7-a -marm -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a5 --sysroot=/opt/poky-atmel/2.5.3/sysroots/cortexa5hf-neon-poky-linux-gnueabi
#CC="gcc"
obj-m += uleds.o
KERNEL_SOURCE := /opt/poky-atmel/2.5.3/sysroots/cortexa5hf-neon-poky-linux-gnueabi/lib/modules/4.14.73-linux4sam-6.0-dirty
default:
${CC} ${KERNEL_SOURCE} uleds.c
clean:
${CC} $(INC) ${KERNEL_SOURCE} clean
Any suggestions for that ? Thank you
This appears to be an attempt at a kbuild file,.
You should not be manually compiling the file yourself using your default rule. Instead, you should be running the kernel's makefile, and have it compile the driver based on obj-m and friends.
Your makefile would look like so:
ifneq ($(KERNELRELEASE),)
ccflags-y += -I some/other/dir
obj-m += uleds.o
else
# default to build against running kernel if KDIR not
# specified:
KDIR ?= /lib/modules/`uname -r`/build
default:
$(MAKE) -C $(KDIR) M=$$PWD
endif
If you call make from the driver's directory, it will in turn call make from your kernel directory, which will know everything about the kernel and will be able to properly build your module.
Notice that by default, the built-in kernel's clean target will remove all generated *.[oas] files, so no need for a special clean target. Also, by default, the kernel's makefile will include its own include directories, so you likely don't need to do anything special for that. In case you do need to include from somewhere else, you can add a -I directive to the ccflags-y as shown in the example.
See Linux Kernel Makefiles and Building External Modules for details.
Simplest is:
${CC} -I/opt/poky-atmel/2.5.3/sysroots/cortexa5hf-neon-poky-linux-gnueabi/usr/src/kernel/include/linux uleds.c
Try reading the following to get familiar with other GCC (compiler) options: https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html#Directory-Options

gnu make - how to define variables in foreach based on some condition

I want to assign variables in foreach loop based on some condition.
For example in practice I want to use it for going through all required tools (gcc g++ as ld) check if they are found on system path. If yes then keep it, if not then try to add user provided path prefix and if it can be found there then modify variable to use full path else report early error to the user.
In general answer I come up with:
TEST_ARRAY = AA BB
K := $(foreach myTest,$(TEST_ARRAY),\
$(if $(filter AA,$(myTest)),\
$(eval $(myTest) := match),\
$(eval $(myTest) := mismatch)))
$(info "AA: ${AA}")
$(info "BB: ${BB}")
the output is:
"AA: match"
"BB: mismatch"
answer to my more specific question is quite longer - the working code snippet is like this:
#on widows
DEVNUL := NUL
WHICH := where
#on linux
#DEVNUL := /dev/null
#WHICH := which
# set path to be searched when command is not found in system PATH
GNU_PATH := c:\NSS\GNU_Tools_ARM_Embedded\5.4 2016q3\bin2
# optionally set command prefix - for example all your tools are not called "gcc" but "arm-gcc" so you would fill here "arm-"
GNU_PREFIX := arm-none-eabi-
# set command suffix - for example on windows all executable files have suffix ".exe"
GNU_SUFFIX := .exe
# escape spaces in path because make $(wildcard ) can not handle them :(
empty :=
space := $(empty) $(empty)
GNU_PATH_ESCAPED := $(subst $(space),\ ,$(GNU_PATH))
# define used tool-chain commands
CC := gccx
AS := as
AR := ar
LD := ld
NM := nm
OBJDUMP := objdump
OBJCOPY := objcopy
SIZE := size
# detect if tool-chain commands are installed and fill correct path (prefer system PATH, then try to find them in suggested GNU_PATH)
# if not found on neither system path nor on user provided GNU_PATH then early error is reported to user
EXECUTABLES = CC AS AR LD NM OBJDUMP OBJCOPY SIZE
$(foreach myTestCommand,$(EXECUTABLES),\
$(if $(shell ${WHICH} ${GNU_PREFIX}$($(myTestCommand)) 2>${DEVNUL} ),\
$(eval $(myTestCommand) := ${GNU_PREFIX}$($(myTestCommand))),\
$(if $(wildcard $(GNU_PATH_ESCAPED)\${GNU_PREFIX}$($(myTestCommand))$(GNU_SUFFIX)),\
$(eval $(myTestCommand) := '$(GNU_PATH)/${GNU_PREFIX}$($(myTestCommand))$(GNU_SUFFIX)'),\
$(error "Can not find tool ${GNU_PREFIX}$($(myTestCommand))$(GNU_SUFFIX), either make in in your system PATH or provide correct path in variable GNU_PATH"))))
# just print what tools will be used
$(foreach myTestCommand,$(EXECUTABLES),\
$(info found tool $($(myTestCommand))))
default:
#$(CC) --version
in my test case I have all tools on my path except gccx which is located in my user folder provided in GNU_PATH.
found tool 'c:\NSS\GNU_Tools_ARM_Embedded\5.4 2016q3\bin2/arm-none-eabi-gccx.exe'
found tool arm-none-eabi-as
found tool arm-none-eabi-ar
found tool arm-none-eabi-ld
found tool arm-none-eabi-nm
found tool arm-none-eabi-objdump
found tool arm-none-eabi-objcopy
found tool arm-none-eabi-size

No rule to make target based on parameter use

I am using a makefile to control the compilation of my project. At the start of my Makefile, I have:
ifdef PIXEL
CFLAGS += -DBY_PIXEL
else
ifdef LINE
CFLAGS += -DBY_LINE
else
ifdef BLOCK
CFLAGS += -DBY_BLOCK
else
CFLAGS += -DBY_PIXEL (HERE)
endif
endif
endif
I have the error "No rule to make target XXX" where XXX is PIXEL, LINE or BLOCK. However when I don't write any parameter, it finds the target in the last else (where I put (HERE).
I dont fully understand why but I don't often write Makefile. Do you guys have an idea about it?
To specify a variable for make, set it to a value after the make command. For example, make PIXEL=foo build

Understanding Makefile += operator

I have a line in my kernel make file:
obj-y += sample.o adc.o trigger.o send.o
I don't understand the above line. Is it same as the following?
obj-y +=sample.o
obj-y +=adc.o
obj-y +=trigger.o
obj-y +=send.o
According to the GNU make manual, += is used to append strings to variables. So yes.

Unknown symbol when compiling kernel module from multiple files

I am writing a kernel module that is comprised of several source files,
One of these source files has a function that needs to be used by the other objects in the same module.
It is defined in my file named ModemAPI.c
static void LogMessage ( char *format, ...)
This c file should be (together with other files) compiled into one kernel module, its makefile looks like this:
obj-m += ModemAPI.o
ModemAPI-objs := ../Common/StateMachine.o ../Common/ElementsPool.o
When I compile this kernel module, I get a warning during linking that the above function "LogMessage" is undefined and when I try to load the module I get an error saying it has an unknown symbol in it (of course LogMessage).
EDIT: Just to make clear, the function "LogMessage" is declared and implemented in the file ModemAPI.c, moreover it is exported via EXPORT_SYMBOL
EXPORT_SYMBOL(LogMessage);
In the files that use the function (such as StateMachine.c), it is declared via extern
extern void LogMessage ( char *format, ...);
The module compiles, the problem is in the linking stage.
Does anyone have any idea what could be the problem with this?
Thanks,
Roy.
In the Makefile try
obj-m += Module.o
Module-objs := ../Common/StateMachine.o ../Common/ElementsPool.o ../Common/ModemAPI.o
some times the order of the .o files are important
Answer for : moreover it is exported via EXPORT_SYMBOL
EXPORT_SYMBOL() makes LogMessage() is accessible to loadable kernel modules.
For eample, vmalloc() is exported to use in kernel modules http://lxr.free-electrons.com/source/mm/vmalloc.c#L1708
But still you have to include the vmalloc.h in loadable kernel module source.so do not confuse with extern and EXPORT_SYMBOL.
Solution
In your Makefile, modify as below
obj-m += ModemAPI.c StateMachine.c
i.e ModemAPI.c which has LogMessage() should be compiled first.
Change proposed to Makefile
obj-m += Mymodule.o
Mymodule-objs := ../Common/ModemAPI.o ../Common/StateMachine.o ../Common/ElementsPool.o
EDIT : 2
static in static void LogMessage ( char *format, ...) restricts the use of LogMessage() in other files. This concept is called static functions.
I believe the issue is that ModemAPI.c is not getting compiled.
obj-m += ModemAPI.o
ModemAPI-objs := ../Common/StateMachine.o ../Common/ElementsPool.o
Normally obj-m += ModemAPI.o tells make to use ModemAPI.c (I think that is the default for the linux make system), but adding the ModemAPI-objs tells make that ModemAPI.o is built using the objects ../Common/StateMachine.o ../Common/ElementsPool.o instead.
Try renaming the object or your ModemAPI.c file:
obj-m += modem.o #something not named ModemAPI.o
ModemAPI-objs := ModemAPI.o ../Common/StateMachine.o ../Common/ElementsPool.o
or
obj-m += ModemAPI.o
ModemAPI-objs := main.o ../Common/StateMachine.o ../Common/ElementsPool.o
where ModemAPI.c has been renamed to main.c
Make sure, that your kernel is compiled with support for module loading (e.g., if /proc/modules exists, you can be sure, it is)
Make sure, you are compiling against the same kernel, where you are trying to load the module
define obj-m += ... and [my-module-ko]-objs := [all xx.o object list]

Resources