How does kbuild actually work?

前端 未结 1 986
孤独总比滥情好
孤独总比滥情好 2021-01-31 19:23

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

1条回答
  •  伪装坚强ぢ
    2021-01-31 20:03

    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)= 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.

    0 讨论(0)
提交回复
热议问题