UBOOT編譯--- include/config/auto.conf、 include/config/auto.conf.cmd、 include/generated/autoconf.h (二)

来源:https://www.cnblogs.com/jianhua1992/archive/2022/11/02/16852774.html
-Advertisement-
Play Games

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-web ...


auto.conf、 auto.conf.cmd、autoconf.h

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_CONFIG

ifeq ($(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 class="token keyword">return</span> name <span class="token operator">?</span> name <span class="token operator">:</span> <span class="token string">".config"</span><span class="token punctuation">;</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 class="token function">sym_clear_all_valid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">file_write_dep</span><span class="token punctuation">(</span><span class="token string">"include/config/auto.conf.cmd"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">conf_split_config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</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 class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

board<span class="token operator">/</span>abilis<span class="token operator">/</span>tb100<span class="token operator">/</span>Kconfig \
arch<span class="token operator">/</span>arc<span class="token operator">/</span>Kconfig \
arch<span class="token operator">/</span>Kconfig \
Kconfig

include/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 class="token operator">=</span> <span class="token function">fopen</span><span class="token punctuation">(</span><span class="token string">".tmpconfig_tristate"</span><span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>tristate<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">fclose</span><span class="token punctuation">(</span>out<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

out_h <span class="token operator">=</span> <span class="token function">fopen</span><span class="token punctuation">(</span><span class="token string">".tmpconfig.h"</span><span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>out_h<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">fclose</span><span class="token punctuation">(</span>out<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">fclose</span><span class="token punctuation">(</span>tristate<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">conf_write_heading</span><span class="token punctuation">(</span>out<span class="token punctuation">,</span> <span class="token operator">&amp;</span>kconfig_printer_cb<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">conf_write_heading</span><span class="token punctuation">(</span>tristate<span class="token punctuation">,</span> <span class="token operator">&amp;</span>tristate_printer_cb<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">conf_write_heading</span><span class="token punctuation">(</span>out_h<span class="token punctuation">,</span> <span class="token operator">&amp;</span>header_printer_cb<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">for_all_symbols</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> sym<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">sym_calc_value</span><span class="token punctuation">(</span>sym<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>sym<span class="token operator">-&gt;</span>flags <span class="token operator">&amp;</span> SYMBOL_WRITE<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token operator">!</span>sym<span class="token operator">-&gt;</span>name<span class="token punctuation">)</span>
		<span class="token keyword">continue</span><span class="token punctuation">;</span>

	<span class="token comment">/* write symbol to auto.conf, tristate and header files */</span>
	<span class="token function">conf_write_symbol</span><span class="token punctuation">(</span>out<span class="token punctuation">,</span> sym<span class="token punctuation">,</span> <span class="token operator">&amp;</span>kconfig_printer_cb<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token function">conf_write_symbol</span><span class="token punctuation">(</span>tristate<span class="token punctuation">,</span> sym<span class="token punctuation">,</span> <span class="token operator">&amp;</span>tristate_printer_cb<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token function">conf_write_symbol</span><span class="token punctuation">(</span>out_h<span class="token punctuation">,</span> sym<span class="token punctuation">,</span> <span class="token operator">&amp;</span>header_printer_cb<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">fclose</span><span class="token punctuation">(</span>out<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">fclose</span><span class="token punctuation">(</span>tristate<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">fclose</span><span class="token punctuation">(</span>out_h<span class="token punctuation">)</span><span class="token punctuation">;</span>	

在這裡插入圖片描述

在最後一段代碼中,將這幾個臨時文件進行改名:

#note/scripts/kconfig/confdata.c
const char *conf_get_autoconfig_name(void)
{
	char *name = getenv("KCONFIG_AUTOCONFIG");
<span class="token keyword">return</span> name <span class="token operator">?</span> name <span class="token operator">:</span> <span class="token string">"include/config/auto.conf"</span><span class="token punctuation">;</span>

}

......

name <span class="token operator">=</span> <span class="token function">getenv</span><span class="token punctuation">(</span><span class="token string">"KCONFIG_AUTOHEADER"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>name<span class="token punctuation">)</span>
	name <span class="token operator">=</span> <span class="token string">"include/generated/autoconf.h"</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">rename</span><span class="token punctuation">(</span><span class="token string">".tmpconfig.h"</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
name <span class="token operator">=</span> <span class="token function">getenv</span><span class="token punctuation">(</span><span class="token string">"KCONFIG_TRISTATE"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>name<span class="token punctuation">)</span>
	name <span class="token operator">=</span> <span class="token string">"include/config/tristate.conf"</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">rename</span><span class="token punctuation">(</span><span class="token string">".tmpconfig_tristate"</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
name <span class="token operator">=</span> <span class="token function">conf_get_autoconfig_name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*
 * 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 class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">rename</span><span class="token punctuation">(</span><span class="token string">".tmpconfig"</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 運行一個.NET Core 項目 報錯:引發的異常:“sqlsugar.sqlsugarexception” 位於 system.private.corelib.dll 中 。 我運行的項目是 : 核心商城系統(CoreShop),本地運行起來項目後,輸入用戶名和密碼進行登錄,登錄後也沒有報錯,但是 ...
  • 一:背景 1.講故事 前段時間有位朋友在微信上找到我,說他對一個商業的 C# 程式用 WinDbg 附加不上去,每次附加之後那個 C# 程式就自動退出了,問一下到底是怎麼回事?是不是哪裡搞錯了,有經驗的朋友應該知道,其實這是 商業程式 的反調試機制搗鬼的,為了保護程式隱私,一般都不希望他人對自己做逆 ...
  • 先上結論 | Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated | | | :| :| :| :| :| :| | JSONConvert | 2,273.02 ns | 43.758 ns | 52.091 ns | 0.6599 | ...
  • 個人主頁:董哥聊技術 我是董哥,嵌入式領域新星創作者 創作理念:專註分享高質量嵌入式文章,讓大家讀有所得! 【所有文章彙總】 1、藍牙基礎概念 藍牙,是一種利用低功率無線電,支持設備短距離通信的無線電技術,能在包括行動電話、PDA、無線耳機、筆記本電腦、相關外設等眾多設備之間進行無線信息交換,藍牙工 ...
  • Docker 使用 Google 公司推出的 Go 語言 進行開發實現,基於 Linux 內核的 cgroup,namespace,以及 OverlayFS 類的 Union FS 等技術,對進程進行封裝隔離,屬於操作系統層面的虛擬化技術。由於隔離的進程獨立於宿主和其它的隔離的進程,因此也稱其為容器... ...
  • 虛擬機和Ubuntu的安裝 修改時間:2022-11-03 一、虛擬機下載鏈接 由於windows11只能安裝VMware Workstation 16的版本,所以我只下載了16的版本,以下是百度網盤鏈接。 鏈接:https://pan.baidu.com/s/1dsIHfVXA4z-M7aVkNl ...
  • 實現步驟: 1.安裝編譯工具 2.創建運行NGINX的轉有程式 3.下載源碼包並解壓 4.使用configure腳本生成makefile文件 5.編譯安裝 6.創建service文件 說明: 源碼安裝需要提前準備標準的編譯器,GCC的全稱是(GNU Compiler collection),其有GN ...
  • 記linux系統(centos7)的IP地址永久性配置實驗開始:網路配置老幾樣:IP地址、子網掩碼、網關、DNS永久性配置步驟一查看並對照網卡我使用的是NAT模式還要註意去虛擬網路編輯器里查看NAT的子網與網關虛擬網路編輯器在VMware的選項里有個編輯里用ip addr查看網卡信息並對照一下上圖, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...