web-dev-qa-db-ja.com

kbuildは実際にどのように機能しますか?

私がLinuxドライバーを開発しているとき、私はこれを通してlinux kbuild makefileを書く方法について読みました document

Kbuildシステムがobj-yobj-mなどのmakefile変数を使用して、何をビルドするか、どのようにビルドするかを決定することを知っています。

しかし、私が混乱しているのは、kbuildシステムが実際にビルドプロセスを実行する場所です。つまり、obj-m = a.o、kbuildシステムはどこで解析しますかobj-mそして実行gcc a.c

18
demonguy

KbuildのMakefileは読みやすいものではありませんが、高レベルのもつれを解く方法は次のとおりです(4.0-rc3カーネルを使用)。

  1. トップレベルのMakefileは

    _include $(srctree)/scripts/Kbuild.include
    _

    、ここで、$(srctree)は最上位のカーネルディレクトリです。

  2. _Kbuild.include_は、さまざまな一般的なものとヘルパーを定義します。これらの中にはbuildがあります。

    _###
    # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
    # Usage:
    # $(Q)$(MAKE) $(build)=dir
    build := -f $(srctree)/scripts/Makefile.build obj
    _

    buildは、$(MAKE) $(build)=dirのようなコマンドとともに使用され、ディレクトリdirのビルドを実行します。 _scripts/Makefile.build_を利用します。

  3. トップレベルのMakefileに戻ると、次のようになります。

    _$(vmlinux-dirs): prepare scripts
            $(Q)$(MAKE) $(build)=$@
    _

    _vmlinux-dirs_には、構築するサブディレクトリのリストが含まれています(initsrkernelなど)。 $(Q)$(MAKE) $(build)=<subdirectory>はサブディレクトリごとに実行されます。

    上記のルールは、カーネルイメージとモジュールの両方のオブジェクトファイルをコンパイルします。トップレベルのMakefileのさらに下には、モジュール固有のものがいくつか追加されています。

    _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. ここで_scripts/Makefile.build_($(build)によって使用されるMakefile)を調べると、_obj-*_リストおよびその他のさまざまなリストを初期化することから始まります。

    _# 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 :=
    _

    もう少し下に、_obj-y_、_obj-m_などが設定されているKbuildファイルにロードされます。

    _include $(kbuild-file)
    _

    さらに下にあるのはデフォルトのルールで、前提条件として$(obj-y)リストと$(obj-m)リストがあります。

    ___build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
             $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
             $(subdir-ym) $(always)
            @:
    _

    $(obj-y)の前提条件は$(builtin-target)から取得され、次のように定義されます。

    _builtin-target := $(obj)/built-in.o
    ...
    $(builtin-target): $(obj-y) FORCE
            $(call if_changed,link_o_target)
    _

    実際の建物は、次のルールで実行されているようです。

    _# 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_は_Kbuild.include_からのものです。ルールは、_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)は実際のコンパイルコマンドのようです。通常の定義(_Makefile.build_、AFAICSには2つの可能性があります)は次のように思われます。

    _cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
    _

    たとえばを使用して明示的に設定されていない限り_make CC=clang_、CCのデフォルトはgccです。これは、トップレベルのMakefileで確認できます。

    _ifneq ($(CC),)
    ifeq ($(Shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
    COMPILER := clang
    else
    COMPILER := gcc
    endif
    export COMPILER
    endif
    _

私がこれを解く方法は、 CTRL-C カーネルのビルド中に、makeがエラーを報告した場所を確認します。もう1つの便利なmakeデバッグ手法は、$(warning $(variable))を使用してvariableの値を出力することです。

28
Ulfalizer