auto.conf、 auto.conf.cmd、autoconf.h
- 1. 前言
- 2. 背景
- 3. 分析
- 3.1 陳述句 $ (Q) $(MAKE) -f $(srctree)/Makefile silentoldconfig
- 3.2 陳述句 $ (Q) $(MAKE) -f $(srctree)/scripts/Makefile.autoconf
- 4. 總結
1. 前言
UBOOT版本:uboot2018.03,開發板myimx8mmek240,
2. 背景
在編譯構建目標時(如 make xxx),頂層 Makefile 的 dot-config 變數值設定為 1 , 如下:
#note: 頂層Makefile dot-config := 1
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
dot-config := 0
endif
endi
在頂層 Makefile 中:
#note: 頂層Makefile KCONFIG_CONFIG ?= .config export KCONFIG_CONFIGifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf (1)# Read in dependencies to all Kconfig* files, make sure to run
# oldconfig if changes are detected.
-include include/config/auto.conf.cmd (2)# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
@# If the following part fails, include/config/auto.conf should be
@# deleted so "make silentoldconfig" will be re-run on the next build.
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf ||
{ rm -f include/config/auto.conf; false; }
@# include/config.h has been updated after "make silentoldconfig".
@# We need to touch include/config/auto.conf so it gets newer
@# than include/config.h.
@# Otherwise, 'make silentoldconfig' would be invoked twice.
$(Q)touch include/config/auto.conf
#endif
其中(1)(2)兩行嘗試包含 auto.conf 和 auto.conf.cmd 這兩個檔案,由于使用 -include 進行宣告,所以即使這兩個檔案不存在也不會報錯退出,比如在第 1 次編譯uboot,且已經配置好 .config 檔案時,這兩個檔案還未生成,
假如我們已經編譯好了xxx_deconfig 這個目標,那么我們會在 include/config 這個目錄下看到 auto.conf 和 auto.conf.cmd 這兩個檔案,

從 include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd 這條規則可以知道,auto.conf 檔案依賴于 $(KCONFIG_CONFIG) 和 include/config/auto.conf.cmd ,其中 $(KCONFIG_CONFIG) 變數的值就是 .config 這個組態檔,
3. 分析
# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
現在仍然假設 auto.conf 和 auto.conf.cmd 還沒有生成,那么由上面這條陳述句可以知道,該陳述句中的目標沒有依賴,也沒有生成它的規則命令,所以可想 GNU Make 本身無法生成 auto.conf.cmd 的,然后該條陳述句后面的一個分號表明,這兩個目標被強制是最新的,所以下面標注的這幾條命令得以執行:
#note: 頂層Makefile
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig (1)
@# If the following part fails, include/config/auto.conf should be
@# deleted so "make silentoldconfig" will be re-run on the next build.
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
{ rm -f include/config/auto.conf; false; } (2)
@# include/config.h has been updated after "make silentoldconfig".
@# We need to touch include/config/auto.conf so it gets newer
@# than include/config.h.
@# Otherwise, 'make silentoldconfig' would be invoked twice.
$(Q)touch include/config/auto.conf (3)
3.1 陳述句 $ (Q) $(MAKE) -f $(srctree)/Makefile silentoldconfig
這里我們看到要生成一個目標 silentoldconfig ,這個目標定義在 scripts/kconfig/Makefile 中,因為這里使用 -f 選項重新指定了頂層 Makefile,而目標又是 silentoldconfig ,所以該命令最侄訓在頂層 Makefile 里執行:
#note: 頂層Makefile
# We need some generic definitions (do not try to remake the file).
scripts/Kbuild.include: ;
include scripts/Kbuild.include //注意這個參考
......
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
在scripts/kconfig/Makefile中(至于為什么會參考scripts/kconfig/Makefile,參見UBOOT編譯— make xxx_deconfig程序詳解(一)4.1.4.3 小節)
# note:scripts/kconfig/Makefile
ifdef KBUILD_KCONFIG
Kconfig := $(KBUILD_KCONFIG)
else
Kconfig := Kconfig
endif
......
silentoldconfig: $(obj)/conf
$(Q)mkdir -p include/config include/generated
$(Q)test -e include/generated/autoksyms.h || \
touch include/generated/autoksyms.h
$< $(silent) --$@ $(Kconfig)
從上面看到,silentoldconfig 目標需要依賴 conf 這個程式,該程式也在 scripts/kconfig 目錄下生成,
$ < $ (silent) --$ @ $ (Kconfig)該條命令相當于 scripts/kconfig/conf -s --myimx8mmek240-8mm-2g_defconfig .config ,
其中scripts/kconfig/conf的生成:參見UBOOT編譯— make xxx_deconfig程序詳解(一)4.4小節,
conf 程式的源代碼的主函式在同目錄的 conf.c 檔案中,在 main() 函式中看到:
#note:/scripts/kconfig/conf.c enum input_mode { oldaskconfig, silentoldconfig, //1 oldconfig, allnoconfig, allyesconfig, allmodconfig, alldefconfig, randconfig, defconfig, savedefconfig, listnewconfig, olddefconfig, } input_mode = oldaskconfig;
......
while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
if (opt == 's') {
conf_set_message_callback(NULL);
continue;
}
input_mode = (enum input_mode)opt;
switch (opt) {
case silentoldconfig:
sync_kconfig = 1;
break;
所以,
(1) 在使用 s 引數時,message的回呼函式被注冊為空,即conf_message函式無輸出列印;
(2) 同時引數opt被賦值為1,等價于silentoldconfig;sync_kconfig = 1;
(3) input_mode = silentoldconfig;
同樣在 main() 函式還看到:
#note:/scripts/kconfig/confdata.c const char *conf_get_configname(void) { char *name = getenv("KCONFIG_CONFIG");<span >return</span> name <span >?</span> name <span >:</span> <span >".config"</span><span >;</span>}
#note:/scripts/kconfig/conf.c
if (sync_kconfig) {
name = conf_get_configname();
if (stat(name, &tmpstat)) {
fprintf(stderr, _("\n"
" Configuration file "%s" not found!\n"
"\n"
" Please run some configurator (e.g. "make oldconfig" or\n"
"*** "make menuconfig" or "make xconfig").\n"
"***\n"), name);
exit(1);
}
}
上面代碼中,如果我們從未配置過UBOOT,那么就會列印出錯誤資訊,然后退出,這里假設已經配置過UBOOT(參見UBOOT編譯— make xxx_deconfig程序詳解(一)),并生成了 .config 檔案,那么在 main() 函式中會來到:
#note:/scripts/kconfig/conf.c
switch (input_mode) {
case defconfig:
if (!defconfig_file)
defconfig_file = conf_get_default_confname();
if (conf_read(defconfig_file)) {
printf(_("***\n"
"*** Can't find default configuration \"%s\"!\n"
"***\n"), defconfig_file);
exit(1);
}
break;
case savedefconfig:
case silentoldconfig:
case oldaskconfig:
case oldconfig:
case listnewconfig:
case olddefconfig:
conf_read(NULL);
break;
前面已經講過由于使用 -s 選項,則 input_mode 為silentoldconfig,所以這里會執行 conf_read(NULL)函式,
conf_read(NULL) 函式用來讀取 .config 檔案,讀取的各種相關內容主要存放在一個 struct symbol 結構鏈表里,而各個結構的相關指標則放在一個 symbol_hash[] 的陣列中,對于陣列中元素的尋找通過 fnv32 哈希演算法進行定位,
最后會來到 conf.c 中的底部:
#note:/scripts/kconfig/conf.c
if (sync_kconfig) {
/* silentoldconfig is used during the build so we shall update autoconf.
* All other commands are only used to generate a config.
*/
if (conf_get_changed() && conf_write(NULL)) {
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
exit(1);
}
if (conf_write_autoconf()) {
fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
return 1;
}
} else if (input_mode == savedefconfig) {
if (conf_write_defconfig(defconfig_file)) {
fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
defconfig_file);
return 1;
}
} else if (input_mode != listnewconfig) {
if (conf_write(NULL)) {
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
exit(1);
}
}
實際上也只有當處理 silentoldconfig 目標時 sync_kconfig 變數才會為 1 ,
(1)在 if (conf_get_changed() && conf_write(NULL)) 這個判斷里,conf_get_changed() 函式判斷 .config 檔案是否做過變動,如果是,那么會呼叫 conf_write(NULL) 來重新寫 .config 檔案,實際上,對于 defconfig, oldconfig,menuconfig,***xxx_deconfig 等目標來說,conf 程式最終也是呼叫 conf_write() 函式將配置結果寫入 .config 檔案中,
(2)確保了 .config 已經最新后,那么呼叫 conf_write_autoconf() 生成 auto.conf,auto.conf.cmd 以及 autoconf.h 這 3 個檔案,
來到 conf_write_autoconf() 函式:
#note:/scripts/kconfig/confdata.c int conf_write_autoconf(void) { struct symbol *sym; const char *name; FILE *out, *tristate, *out_h; int i;<span >sym_clear_all_valid</span><span >(</span><span >)</span><span >;</span> <span >file_write_dep</span><span >(</span><span >"include/config/auto.conf.cmd"</span><span >)</span><span >;</span> <span >if</span> <span >(</span><span >conf_split_config</span><span >(</span><span >)</span><span >)</span> <span >return</span> <span >1</span><span >;</span>
......
在 conf_write_autoconf() 里,呼叫 file_write_dep(“include/config/auto.conf.cmd”); 函式將相關內容寫入 auto.conf.cmd 檔案,在生成的 auto.conf.cmd 檔案中可以看到:
deps_config := \ test/overlay/Kconfig \ test/env/Kconfig \ test/dm/Kconfig \<span >.</span><span >.</span><span >.</span><span >.</span><span >.</span><span >.</span> board<span >/</span>abilis<span >/</span>tb100<span >/</span>Kconfig \ arch<span >/</span>arc<span >/</span>Kconfig \ arch<span >/</span>Kconfig \ Kconfiginclude/config/auto.conf:
$(deps_config)ifneq "$(UBOOTVERSION)" "2018.03"
include/config/auto.conf: FORCE
endif
$(deps_config): ;
可以看到 auto.conf 檔案中的內容依賴于 $(deps_config) 變數里定義的東西,這些東西基本上是各個目錄下的 Kconfig 以及其它一些相關檔案,
仍然在 conf_write_autoconf() 里,分別建立了 .tmpconfig,.tmpconfig_tristate 和 .tmpconfig.h 這 3 個臨時檔案,然后將檔案頭的注釋部分分別寫入到這幾個臨時檔案中,接著在 for_all_symbols(i, sym) 這個回圈里(是一個宏)里將相關內容分別寫入到這幾個檔案中,
#note:/scripts/kconfig/confdata.c out = fopen(".tmpconfig", "w"); if (!out) return 1;tristate <span >=</span> <span >fopen</span><span >(</span><span >".tmpconfig_tristate"</span><span >,</span> <span >"w"</span><span >)</span><span >;</span> <span >if</span> <span >(</span><span >!</span>tristate<span >)</span> <span >{<!-- --></span> <span >fclose</span><span >(</span>out<span >)</span><span >;</span> <span >return</span> <span >1</span><span >;</span> <span >}</span> out_h <span >=</span> <span >fopen</span><span >(</span><span >".tmpconfig.h"</span><span >,</span> <span >"w"</span><span >)</span><span >;</span> <span >if</span> <span >(</span><span >!</span>out_h<span >)</span> <span >{<!-- --></span> <span >fclose</span><span >(</span>out<span >)</span><span >;</span> <span >fclose</span><span >(</span>tristate<span >)</span><span >;</span> <span >return</span> <span >1</span><span >;</span> <span >}</span> <span >conf_write_heading</span><span >(</span>out<span >,</span> <span >&</span>kconfig_printer_cb<span >,</span> <span >NULL</span><span >)</span><span >;</span> <span >conf_write_heading</span><span >(</span>tristate<span >,</span> <span >&</span>tristate_printer_cb<span >,</span> <span >NULL</span><span >)</span><span >;</span> <span >conf_write_heading</span><span >(</span>out_h<span >,</span> <span >&</span>header_printer_cb<span >,</span> <span >NULL</span><span >)</span><span >;</span> <span >for_all_symbols</span><span >(</span>i<span >,</span> sym<span >)</span> <span >{<!-- --></span> <span >sym_calc_value</span><span >(</span>sym<span >)</span><span >;</span> <span >if</span> <span >(</span><span >!</span><span >(</span>sym<span >-></span>flags <span >&</span> SYMBOL_WRITE<span >)</span> <span >||</span> <span >!</span>sym<span >-></span>name<span >)</span> <span >continue</span><span >;</span> <span >/* write symbol to auto.conf, tristate and header files */</span> <span >conf_write_symbol</span><span >(</span>out<span >,</span> sym<span >,</span> <span >&</span>kconfig_printer_cb<span >,</span> <span >(</span><span >void</span> <span >*</span><span >)</span><span >1</span><span >)</span><span >;</span> <span >conf_write_symbol</span><span >(</span>tristate<span >,</span> sym<span >,</span> <span >&</span>tristate_printer_cb<span >,</span> <span >(</span><span >void</span> <span >*</span><span >)</span><span >1</span><span >)</span><span >;</span> <span >conf_write_symbol</span><span >(</span>out_h<span >,</span> sym<span >,</span> <span >&</span>header_printer_cb<span >,</span> <span >NULL</span><span >)</span><span >;</span> <span >}</span> <span >fclose</span><span >(</span>out<span >)</span><span >;</span> <span >fclose</span><span >(</span>tristate<span >)</span><span >;</span> <span >fclose</span><span >(</span>out_h<span >)</span><span >;</span>

在最后一段代碼中,將這幾個臨時檔案進行改名:
#note:/scripts/kconfig/confdata.c const char *conf_get_autoconfig_name(void) { char *name = getenv("KCONFIG_AUTOCONFIG");<span >return</span> name <span >?</span> name <span >:</span> <span >"include/config/auto.conf"</span><span >;</span>}
......
name <span >=</span> <span >getenv</span><span >(</span><span >"KCONFIG_AUTOHEADER"</span><span >)</span><span >;</span> <span >if</span> <span >(</span><span >!</span>name<span >)</span> name <span >=</span> <span >"include/generated/autoconf.h"</span><span >;</span> <span >if</span> <span >(</span><span >rename</span><span >(</span><span >".tmpconfig.h"</span><span >,</span> name<span >)</span><span >)</span> <span >return</span> <span >1</span><span >;</span> name <span >=</span> <span >getenv</span><span >(</span><span >"KCONFIG_TRISTATE"</span><span >)</span><span >;</span> <span >if</span> <span >(</span><span >!</span>name<span >)</span> name <span >=</span> <span >"include/config/tristate.conf"</span><span >;</span> <span >if</span> <span >(</span><span >rename</span><span >(</span><span >".tmpconfig_tristate"</span><span >,</span> name<span >)</span><span >)</span> <span >return</span> <span >1</span><span >;</span> name <span >=</span> <span >conf_get_autoconfig_name</span><span >(</span><span >)</span><span >;</span> <span >/* * This must be the last step, kbuild has a dependency on auto.conf * and this marks the successful completion of the previous steps. */</span> <span >if</span> <span >(</span><span >rename</span><span >(</span><span >".tmpconfig"</span><span >,</span> name<span >)</span><span >)</span> <span >return</span> <span >1</span><span >;</span>
從上面可以看到,分別生成了以下幾個檔案:
include/generated/autoconf.h
include/config/tristate.conf
include/config/auto.conf
3.2 陳述句 $ (Q) $(MAKE) -f $(srctree)/scripts/Makefile.autoconf
由于篇幅的原因,放在下一講,
4. 總結
(1)auto.conf 和 .config 的差別是:auto.conf 里去掉了 .config 中的注釋專案以及空格行,其它的都一樣,
(2) include/generated/autoconf.h 頭檔案由UBOOT本身使用,主要用來預處理 C 代碼,把auto.conf中的定義轉換成C語言的宏定義,,
(1)在 .config 或 auto.conf 中后接"=y"的項,如:
CONFIG_OF_LIBFDT=y
在 autoconfig.h 中會被定義為:
#define CONFIG_OF_LIBFDT 1
(2)在 .config 或 auto.conf 中后接字串值的項,如:
CONFIG_DEFAULT_FDT_FILE="myimx8mmek240-8mm.dtb"
在 autoconfig.h 中會被定義為:
#define CONFIG_DEFAULT_FDT_FILE "myimx8mmek240-8mm.dtb"
(3)在 .config 或 auto.conf 中后接數值的項,如:
CONFIG_SDP_LOADADDR=0x40400000
在 autoconfig.h 中會被定義為:
#define CONFIG_SDP_LOADADDR 0x40400000
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/526755.html
標籤:嵌入式
上一篇:Docker基礎和常用命令
下一篇:開源網路協議堆疊onps誕生記
