當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀] 當(dāng)我們編譯u-boot的時(shí)候,大家鍵入make smdk2410_config,make的時(shí)候都作了那些動(dòng)作呢,這里我先大概介紹一下Makefile的內(nèi)容,然后在大概理解一下命令執(zhí)行的流程。如果有錯(cuò)的地方,希望大家指正,謝謝。

當(dāng)我們編譯u-boot的時(shí)候,大家鍵入make smdk2410_config,make的時(shí)候都作了那些動(dòng)作呢,這里我先大概介紹一下Makefile的內(nèi)容,然后在大概理解一下命令執(zhí)行的流程。如果有錯(cuò)的地方,希望大家指正,謝謝。

1.u-boot頂層目錄的Makefile分析:

31 HOSTARCH := $(shell uname -m |

32 sed -e s/i.86/i386/

33 -e s/sun4u/sparc64/

34 -e s/arm.*/arm/

35 -e s/sa110/arm/

36 -e s/powerpc/ppc/

37 -e s/macppc/ppc/)

首先執(zhí)行uname -m查看機(jī)器硬件名,得到i686,然后sed將i686替換成i386,最后HOSTARCH=i386

39 HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' |

40 sed -e 's/(cygwin).*/cygwin/')

首先執(zhí)行uname -s查看開發(fā)平臺(tái)的內(nèi)核,結(jié)果為Linux,然后tr將大寫符串轉(zhuǎn)化為小寫字符linux ,最后的結(jié)果是HOSTOS=linux

export HOSTARCH HOSTOS

export是Makefile的語法關(guān)鍵詞,將這些變量傳遞給下一層的Makefile.總控Makefile的變量可以傳遞到下級的Makefile中(如果你顯示的聲明),但是不會(huì)覆蓋下層的Makefile中所定義的變量,除非指定了“-e”參數(shù)。

如果你要傳遞變量到下級Makefile中,那么你可以使用這樣的聲明:
export ;


如果你不想讓某些變量傳遞到下級Makefile中,那么你可以這樣聲明:
unexport ;


69 ifdef O

70 ifeq ("$(origin O)", "command line")

71 BUILD_DIR := $(O)

72 endif

73 endif

上面意思是:如果在make命令中有O選項(xiàng)內(nèi)把BUILD_DIR設(shè)為O的指定的值

這里主要說明origin的語法:

origin函數(shù)不像其它的函數(shù),他并不操作變量的值,他只是告訴你你的這個(gè)變量是哪里來的?其語法是:$(origin ;)
注意,;是變量的名字,不應(yīng)該是引用。所以你最好不要在;中使用“$”字符。Origin函數(shù)會(huì)以其返回值來告訴你這個(gè)變量的“出生情況”,下面,是origin函數(shù)的返回值:

“undefined”:如果;從來沒有定義過,origin函數(shù)返回這個(gè)值“undefined”。
“default”: 如果;是一個(gè)默認(rèn)的定義
“environment” :如果;是一個(gè)環(huán)境變量,并且當(dāng)Makefile被執(zhí)行時(shí),“-e”參數(shù)沒有被打開。
“file”: 如果;這個(gè)變量被定義在Makefile中。
“command line” : 如果;這個(gè)變量是被命令行定義的。
“override” : 如果;是被override指示符重新定義的。
“automatic” : 如果;是一個(gè)命令運(yùn)行中的自動(dòng)化變量。

75 ifneq ($(BUILD_DIR),)

76 saved-output := $(BUILD_DIR)

ifneq如果BUILD_DIR不為空,則把saved-output設(shè)為BUILD_DIR

79 $(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})

-d檢查BUILD_DIR文件夾是否存在,不存在則創(chuàng)建

82 BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)

83 $(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))

84 endif # ifneq ($(BUILD_DIR),)

確認(rèn)BUILD_DIR是否己經(jīng)創(chuàng)建.假設(shè)BUILD_DIR不存在,cd $(BUILD_DIR)為假不執(zhí)行后面/bin/pwd,$(shell cd $(BUILD_DIR) && /bin/pwd)返回值為空, 下面的if為假則會(huì)打印outpud directory … does not exist, 同時(shí)make退出。

這里主要說明if的語法:

$(if ,,)

如果為真(非空字符串) ,那個(gè)會(huì)是整個(gè)函數(shù)的返回值,如果為假(空字符串) ,那么會(huì)是整個(gè)函數(shù)的返回值,此時(shí)如果沒有被定義,那么,整個(gè)函數(shù)返回空字串。

86 OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))

87 SRCTREE := $(CURDIR)

88 TOPDIR := $(SRCTREE)

89 LNDIR := $(OBJTREE)

90 export TOPDIR SRCTREE OBJTREE

91

92 MKCONFIG := $(SRCTREE)/mkconfig

93 export MKCONFIG

CURDIR是makefile中的一個(gè)關(guān)鍵字,指明當(dāng)前路徑。

最后TOPDIR SRCTREE OBJTREE這三個(gè)變量一樣,都是u-boot源碼目錄的根目錄路徑。然后設(shè)置MKCONFIG腳本的路徑。
95 ifneq ($(OBJTREE),$(SRCTREE))

96 REMOTE_BUILD := 1

97 export REMOTE_BUILD

98 endif

如果當(dāng)前路徑和生成OBJ目錄路徑不一樣,則會(huì)設(shè)置REMOTE_BUILD為1

103 ifneq ($(OBJTREE),$(SRCTREE))

104 obj := $(OBJTREE)/

105 src := $(SRCTREE)/

106 else

107 obj :=

108 src :=

109 endif

110 export obj src

如果當(dāng)前路徑和生成OBJ目錄路徑不一樣,則設(shè)置src與obj變量的值,代表了最終src與obj的路徑

114 ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))

//通過wildcard文件名函數(shù)判斷是否有include/config.mk文件,也就是執(zhí)行make smdk2410_config以后產(chǎn)生的文件.

$(wildcard pattern)
參數(shù)pattern是一個(gè)文件名格式,包含有通配符。函數(shù)wildcard的結(jié)果是一列和格式匹配且真實(shí)存在的文件的名稱,文件名之間用一個(gè)空格隔開。
比如當(dāng)前目錄下有文件1.c,2.c,1.h,2.h則
c_src := $(wildcard *.c)
結(jié)果為:1.c 2.c

# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk//包含這個(gè)文件.這里obj為空

export ARCH CPU BOARD VENDOR SOC//將include/config.mk里的變量申明給其他的Makefile使用.

# load other configuration
include $(TOPDIR)/config.mk//然后包含根目錄的config.mk文件.

這些config.mk將在以后介紹

ifndef CROSS_COMPILE//確實(shí)沒有定義CROSS_COMPILE變量
ifeq ($(HOSTARCH),ppc)//HOSTARCH為i386,CROSS_COMPILE所以不為空
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = powerpc-linux-
endif
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
endif
......

首先沒有定義CROSS_COMPILE,然后我們的HOSTARCH=i386,然后在判斷ARCH,由于在前面已經(jīng)指定ARCH=arm.所以CROSS_COMPILE=arm-linux-.通過這個(gè)可以選擇不同平臺(tái)下的交叉編譯器.

include $(TOPDIR)/config.mk//包含根目錄下的config.mk文件,這個(gè)文件以后會(huì)分析到。

OBJS = cpu/$(CPU)/start.o
ifeq ($(CPU),i386)
OBJS = cpu/$(CPU)/start16.o
OBJS = cpu/$(CPU)/reset.o
endif ........

OBJS := $(addprefix $(obj),$(OBJS)) //將OBJS賦值給OBJ
$(addprefix src/,foo bar)
結(jié)果:src/foo src/bar

由于start.S是我們啟動(dòng)代碼,所以首先編譯.OBJ=cpu/arm920t/start.o

LIBS = lib_generic/libgeneric.a
LIBS = board/$(BOARDDIR)/lib$(BOARD).a
LIBS = cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS = cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
LIBS = lib_$(ARCH)/lib$(ARCH).a
........

.PHONY : $(LIBS)

添加相應(yīng)的靜態(tài)庫.

__OBJS := $(subst $(obj),,$(OBJS)
__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))

(1) $(subst from,to,text).
在文本“text”中使用to替換每一處的from。
比如:
$(subst ee,EE,feet on the street)
結(jié)果為:fEET on the strEET

ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) //這個(gè)是最后要生成的文件。$(U_BOOT_NAND) $(U_BOOT_ONENAND)要添加相應(yīng)的宏定義即可。

$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@將u-bootELF格式文件生成16進(jìn)制格式的文件
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@將u-bootELF格式文件生成另一種S-Record格式的文件

unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep
//刪除以前的配置文件
以上是一些Makefile的大概信息,這里就說到這里。感興趣的可以再深入了解。

//當(dāng)我們執(zhí)行make smdk2410_config的時(shí)候,要作的事情如下:
Makefile文件里面可以看出支持好多種體系結(jié)構(gòu),并有相應(yīng)開發(fā)板的配置信息。這里主要研究的是ARM,開發(fā)板是smdk2410.
當(dāng)我們執(zhí)行:make smdk2410_config的時(shí)候,首先執(zhí)行:
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
首先執(zhí)行unconfig這個(gè)標(biāo)簽,主要是刪除以前的配置信息。
然后執(zhí)行$(MKCONFIG),也就是mkconfig腳本,并傳遞6個(gè)參數(shù)。
$(@:_config=)他的作用就是將smdk2410_config中的_config設(shè)置為空,結(jié)果為smdk2410.
這個(gè)命令也就是:./mkconfigsmdk2410 arm arm920t smdk2410 NULL s3c24x0.
$0 $1 $2 $3 $4 $5 $6
接下來看看mkconfig的源代碼:
1.確定開發(fā)板的名稱
11 APPEND=no # Default: Create new config file

12 BOARD_NAME="" # Name to print in make output

13

14 while [ $# -gt 0 ] ; do

15 case "$1" in

16 --) shift ; break ;;

17 -a) shift ; APPEND=yes ;;

18 -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;

19 *) break ;;

20 esac

21 done
由于參數(shù)里沒有-- -a -n等參數(shù),所以這個(gè)while沒有執(zhí)行。然后APPEND BOARD_NAME沒有改變。
23 [ "${BOARD_NAME}" ] || BOARD_NAME="$1"
這個(gè)時(shí)候BOARD_NAME的值就等于"smdk2410".

25 [ $# -lt 4 ] && exit 1//參數(shù)的個(gè)數(shù)小于4退出

26 [ $# -gt 6 ] && exit 1//參數(shù)的個(gè)數(shù)大于6退出

2.創(chuàng)建開發(fā)板相關(guān)的頭文件的連接
//判斷源代碼目錄和目標(biāo)文件目錄是否一樣,由于直接我們都是在源代碼目錄編譯,所以將執(zhí)行else分之的代碼。
33 if [ "$SRCTREE" != "$OBJTREE" ] ; then

34 mkdir -p ${OBJTREE}/include

35 mkdir -p ${OBJTREE}/include2

36 cd ${OBJTREE}/include2

37 rm -f asm

38 ln -s ${SRCTREE}/include/asm-$2 asm

39 LNPREFIX="../../include2/asm/"

40 cd ../include

41 rm -rf asm-$2

42 rm -f asm

43 mkdir asm-$2

44 ln -s asm-$2 asm

45 else

46 cd ./include

47 rm -f asm

48 ln -s asm-$2 asm

49 fi
進(jìn)入include目錄,刪除asm文件(這是上一次的配置時(shí)建立的連接文件),然后再次建立asm文件,并令它連接向asm-$2目錄,也就是asm-arm目錄。

rm -f asm-$2/arch //刪除asm-$2即asm-arm目錄

if [ -z "$6" -o "$6" = "NULL" ] ; then //-z表示:[ -zSTRING ] “STRING”的長度為零則為真。

ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi
//對于$6就是s3c24x0,不為空,也不是NULL,所以將執(zhí)行else分之。LNPREFIX為空,所以連接的命令就是ln -s arch-$6 asm-$2/arch,也就是ln -s arch-s3c24x0 asm-arm/arch

if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
重新建立asm-arm/proc文件,并讓它連接向proc-armv目錄。

3.創(chuàng)建頂層Makefile包含的文件include/config.mk
echo "ARCH = $2" > config.mk //“>”,“>>”如果有config.mk文件,并將ARCH輸入到config.mk文件里。如果沒有首先創(chuàng)建然后將ARCH輸入。
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk

//將ARCH,CPU,BOARD變量重定向到include/config.mk文件里

[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
//將VENDOR,SOC變量重定向到include/config.mk文件里
這樣include/config.mk文件里的內(nèi)容如下:
ARCH = arm
CPU = arm920t
BOARD = smdk2410
SOC = s3c24x0
#
# Create board specific header file
#
if [ "$APPEND" = "yes" ] # Append to existing config file
then
echo >> config.h
else
> config.h # Create new config file //創(chuàng)建include/config.h文件
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include " >>config.h //將#include
exit 0
這樣include/config.h里的內(nèi)容如下:
/* Automatically generated - do not edit */
#include

3.u-boot的編譯和連接過程
首先在Makefile里包含了include/config.mk和根目錄的config.mk兩個(gè)文件。第一個(gè)主要是那6個(gè)參數(shù)。第二個(gè)config.mk文件的內(nèi)容如下:
BOARDDIR = $(BOARD)
endif
ifdef BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules
endif //包含board/smdk2410/config.mk,里面主要定義了TEXT_BASE=0x33f80000
........
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
。。。。
LDFLAGS = -Bstatic -T $(LDSCRIPT) $(PLATFORM_LDFLAGS)//加入連接文件為以后使用。LDFLAGS有“-T board/smdk2410/u-boot.lds -Ttext 0x33f80000”字樣。首先我們的u-boot.lds告訴我們的代碼的分布狀況,而-Ttext 0x33f80000告訴我們text段放在0x33f80000.待會(huì)會(huì)講到u-boot.lds的內(nèi)容。對于OBJS,LIBS的每個(gè)成員,都將進(jìn)入相應(yīng)的子目錄執(zhí)行make命令。當(dāng)所有的OBJS,LIBS所表示的.o,.a文件生成后,就剩下最后的連接了,這對應(yīng)Makefile的如下幾行:
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@

$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot: depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) |
sed -n -e 's/.*($(SYM_PREFIX)__u_boot_cmd_.*)/-u1/p'|sort|uniq`;
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS)
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS)
-Map u-boot.map -o u-boot
首先使用下面的語句連接得到ELF格式的u-boot.最后轉(zhuǎn)化為二進(jìn)制格式的u-boot.bin,S-Record格式的u-boot.srec。LDFLAGS確定了連接的方式,其中“-T board/smdk2410/u-boot.lds -Ttext 0x33f80000”字樣指定了程序的布局和地址。u-boot.lds的文件如下:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
/*指定輸出可執(zhí)行文件是elf格式,32位ARM指令,小端*/
OUTPUT_ARCH(arm)
/*指定輸出可執(zhí)行文件的平臺(tái)為ARM*/
ENTRY(_start)
/*指定輸出可執(zhí)行文件的起始代碼段為_start*/
(.globl _start _start: b start_code//cpu/arm920t/start.S)
SECTIONS
{
/*指定可執(zhí)行image文件的全局入口點(diǎn),通常這個(gè)地址都放在ROM(flash)0x0位置。必須使編譯器知道這個(gè)地址,通常都是修改此處來完成*/
. = 0x00000000; /*;從0x0位置開始*/
. = ALIGN(4);/*代碼以4字節(jié)對齊*/
.text :
{
cpu/arm920t/start.o (.text) /*代碼的第一個(gè)代碼部分*/
*(.text) /*其它代碼部分*/
}
. = ALIGN(4);
.rodata : { *(.rodata) } /*指定只讀數(shù)據(jù)段*/

. = ALIGN(4);
.data : { *(.data) }/*指定讀/寫數(shù)據(jù)段*/

. = ALIGN(4);
.got : { *(.got) } /*指定got段, got段是uboot自定義的一個(gè)段,非標(biāo)準(zhǔn)段*/

. = .;
/*把__u_boot_cmd_start賦值為當(dāng)前位置,即起始位置*/
__u_boot_cmd_start = .;
/*指定u_boot_cmd段, uboot把所有的uboot命令放在該段.*/
.u_boot_cmd : { *(.u_boot_cmd) }
/*把__u_boot_cmd_end賦值為當(dāng)前位置,即結(jié)束位置*/
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .; /*把__bss_start賦值為當(dāng)前位置,即bss段的開始位置*/
.bss (NOLOAD) : { *(.bss) } /*指定bss段,告訴加載器不要加載這個(gè)段*/
_end = .; /*把_end賦值為當(dāng)前位置,即bss段的結(jié)束位置*/

這樣代碼的都是以0x33f80000 0x0為基準(zhǔn)開始,如果你從nandflash啟動(dòng),測試前4K的代碼的地址都是在0x0,那么4K的代碼的實(shí)現(xiàn)可以通過位置無關(guān)指令b來實(shí)現(xiàn)。b指令的程序不依賴代碼存儲(chǔ)的位置-即不管這條代碼放在什么位置,B指令都可以跳轉(zhuǎn)到正確的位置。
bootloader,內(nèi)核等程序剛開始運(yùn)行時(shí)。他們所處的地址通常不等于運(yùn)行地址

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉