Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does kbuild actually work?

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 ?

like image 645
demonguy Avatar asked Mar 24 '15 11:03

demonguy


People also ask

How kbuild works?

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.

What is Kbuild?

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.

How build procedure works explain KConfig in brief?

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.

What is a Kbuild file?

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.


1 Answers

Kbuild's Makefiles aren't the easiest to read, but here's a high-level untangling (using the 4.0-rc3 kernel):

  1. The top-level Makefile does

    include $(srctree)/scripts/Kbuild.include
    

    , where $(srctree) is the top-level kernel directory.

  2. 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.

  3. 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
    
  4. 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.

like image 156
Ulfalizer Avatar answered Oct 16 '22 12:10

Ulfalizer