When i'm developing a linux driver, i've read about how to write linux kbuild makefile through this document
I know kbuild system use makefile variables such as obj-y obj-m to determine what to build and how to build.
But what i'm confused about is where does kbuild system really execute build process.In a word, if i have obj-m = a.o
, then where does kbuild system parse obj-m
and execute gcc a.c
?
Kbuild is a good example of recursive make. By dividing source files into different modules/components, each component is managed by its own makefile. When you start building, a top makefile invokes each component's makefile in the proper order, builds the components, and collects them into the final executive.
kbuild is an assortment of scripts that are built-in inside the kernel's sources, and the kernel build process does not depend on anything named kmk. The kernel build system depends only on the standard GNU make, and it takes care of compiling its own helper programs, most of which are located under scripts/ directory.
Most users interact with KConfig via a curses or graphical menu interface, usually invoked by running make menuconfig . In this interface, the user selects the options and features desired, and saves a configuration file, which is then used as an input to the build process.
The kbuild Makefile specifies object files for vmlinux in the $(obj-y) lists. These lists depend on the kernel configuration. Kbuild compiles all the $(obj-y) files. It then calls “$(AR) rcSTP” to merge these files into one built-in.a file. This is a thin archive without a symbol table.
Kbuild's Makefiles aren't the easiest to read, but here's a high-level untangling (using the 4.0-rc3 kernel):
The top-level Makefile does
include $(srctree)/scripts/Kbuild.include
, where $(srctree)
is the top-level kernel directory.
Kbuild.include
defines various common stuff and helpers. Among these is build
:
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
build
is used with a command like $(MAKE) $(build)=dir
to perform the build for the directory dir
. It makes use of scripts/Makefile.build
.
Returning to the top-level Makefile, there's the following:
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
vmlinux-dirs
contains a list of subdirectories to build (init, usr, kernel, etc.). $(Q)$(MAKE) $(build)=<subdirectory>
will be run for each subdirectory.
The rule above compiles object files for both the kernel image and modules. Further down in the top-level Makefile, there's some additional module-specific stuff:
ifdef CONFIG_MODULES
...
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
# Do additional module-specific stuff using
# scripts/Makefile.modpost among other things
# (my comment).
...
...
endif # CONFIG_MODULES
Looking into scripts/Makefile.build
(the Makefile used by $(build)
) now, it begins by initializing the obj-*
lists and various other lists:
# Init all relevant variables used in kbuild files so
# 1) they have correct type
# 2) they do not inherit any value from the environment
obj-y :=
obj-m :=
lib-y :=
lib-m :=
A bit further down, it loads in the Kbuild file where obj-y
, obj-m
, etc., are set:
include $(kbuild-file)
Further down is the default rule, which has the $(obj-y)
and $(obj-m)
lists as prerequisites:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
The $(obj-y)
prerequisites come from $(builtin-target)
, which is defined as follows:
builtin-target := $(obj)/built-in.o
...
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
The actual building seems to be performed by the following rule:
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
if_changed_rule
is from Kbuild.include
. The rule ends up running the following commands in Makefile.build
:
define rule_cc_o_c
$(call echo-cmd,checksrc) $(cmd_checksrc) \
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
...
endef
$(cmd_cc_o_c)
seems to be the actual compilation command. The usual definition (there are two possibilities in Makefile.build
, AFAICS) seems to be the following:
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
Unless set explicitly using e.g. make CC=clang
, CC
defaults to gcc
, as can be seen here in the top-level Makefile:
ifneq ($(CC),)
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
COMPILER := clang
else
COMPILER := gcc
endif
export COMPILER
endif
The way I untangled this was by doing a CTRL-C during a kernel build and seeing where make
reported the error. Another handy make
debugging technique is to use $(warning $(variable))
to print the value of variable
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With