mstar 开发环境搭建

mstar 开发环境搭建:

repo init --repo-url ssh://gerrit@10.225.6.16:29418/msd358_1102/repo -u ssh://gerrit@10.225.6.16:29418/msd358/manifest

repo start modify --all

repo init --repo-url ssh://gerrit@10.225.6.16:29418/msd358_1102/repo -u ssh://gerrit@10.225.6.16:29418/msd358/manifest -m msd358_cg.xml

repo init --repo-url ssh://gerrit@10.225.6.16:29418/msd358_1102/repo -u ssh://gerrit@10.225.6.16:29418/msd358/manifest -m msd358_hifi.xml

CPU:358 Version:Android 8(O)
1、 环境配置:
1、 下载并配置JDK1.8以上
#set java environment begin
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export JRE_HOME= J A V A H O M E / j r e e x p o r t C L A S S P A T H = . : {JAVA_HOME}/jre export CLASSPATH=.: JAVAHOME/jreexportCLASSPATH=.:{JAVA_HOME}/lib: J R E H O M E / l i b : {JRE_HOME}/lib: JREHOME/lib:{CLASSPATH}
export PATH= J A V A H O M E / b i n : {JAVA_HOME}/bin: JAVAHOME/bin:{PATH}
#set java environment end
2、 下载或获取工具链并放置于固定路径下
例:/home/cfj/workspace/AN_msd348/tools/

set ARM Toolchain begin

export PATH=/home/boe/workspace/AN_msd348/tools/arm-2012.09/bin:/home/cfj/workspace/AN_msd348/tools/arm_eabi-2011.03/bin: P A T H e x p o r t P A T H = / h o m e / c f j / w o r k s p a c e / A N m s d 348 / t o o l s / l i n a r o a a r c h 6 4 l i n u x − 2014.0 9 r 20170413 / b i n : PATH export PATH=/home/cfj/workspace/AN_msd348/tools/linaro_aarch64_linux-2014.09_r20170413/bin: PATHexportPATH=/home/cfj/workspace/ANmsd348/tools/linaroaarch64linux2014.09r20170413/bin:PATH
export PATH=/home/cfj/workspace/AN_msd348/tools/Linaro/4.9.3/gcc-linaro-4.9-2015.02-3-x86_64_arrch64-linux-gnu/bin/: P A T H e x p o r t P A T H = / h o m e / c f j / w o r k s p a c e / A N m s d 348 / t o o l s / L i n a r o / 4.9.3 / g c c − l i n a r o − 4.9 − 2015.02 − 3 − x 8 6 6 4 a r m − l i n u x − g n u e a b i / b i n / : PATH export PATH=/home/cfj/workspace/AN_msd348/tools/Linaro/4.9.3/gcc-linaro-4.9-2015.02-3-x86_64_arm-linux-gnueabi/bin/: PATHexportPATH=/home/cfj/workspace/ANmsd348/tools/Linaro/4.9.3/gcclinaro4.92015.023x8664armlinuxgnueabi/bin/:PATH
export PATH=/home/cfj/workspace/AN_msd348/tools/Linaro/4.9.3/gcc-linaro-4.9-2015.02-3-x86_64_arm-linux-gnueabihf/bin/: P A T H e x p o r t P A T H = / h o m e / c f j / w o r k s p a c e / A N m s d 348 / t o o l s / L i n a r o / g c c − l i n a r o − a a r c h 64 − n o n e − e l f − 4.9 − 2014.0 9 l i n u x / b i n / : PATH export PATH=/home/cfj/workspace/AN_msd348/tools/Linaro/gcc-linaro-aarch64-none-elf-4.9-2014.09_linux/bin/: PATHexportPATH=/home/cfj/workspace/ANmsd348/tools/Linaro/gcclinaroaarch64noneelf4.92014.09linux/bin/:PATH
#export PATH=/home/cfj/workspace/AN_msd348/tools/Linaro/gcc-linaro-aarch64-none-elf-4.9-2014.07_linux/bin/: P A T H e x p o r t P A T H = / h o m e / c f j / w o r k s p a c e / A N m s d 348 / t o o l s / r 2 − e l f − l i n u x − 1.3.5.14 / b i n / : PATH export PATH=/home/cfj/workspace/AN_msd348/tools/r2-elf-linux-1.3.5.14/bin/: PATHexportPATH=/home/cfj/workspace/ANmsd348/tools/r2elflinux1.3.5.14/bin/:PATH

set ARM Toolchain end

Source 对应的配置文件
可用gcc –v(工具链名称 -v) 查看工具链版本信息
用which 可查看工具命令路径
3、 特殊工具链的申请
4、 屏蔽Makefile中工具链版检查(kernel和supernova所需gcc版本不一致)此处选择修改supernova Makefile 文件:
348_358_AN8.0_0801/vendor/mstar/supernova/optee/Makefile

add GCC check for aarch64-linux-gnu-gcc

##GCC_VERSION = gcc version 4.9.4

##log_gccver:

[ ‘$(wildcard .GCCver.log)’ ] && rm .GCCver.log

@arm-linux-gnueabi-gcc -v > .GCCver.log 2>&1

##check_gccver: log_gccver

@echo “$(GCC_VERSION)”

@[ ‘ ( s h e l l g r e p " (shell grep " (shellgrep"(GCC_VERSION)" .GCCver.log)’ ] || ( echo “GCC version should be $(GCC_VERSION). please check it!!” ;exit 99 )

@rm .GCCver.log

end of add GCC check for aarch64-linux-gnu-gcc

#all: check_gccver UNTAR_TEE_ACTION
all: UNTAR_TEE_ACTION

5、 由于现在一般操作系统是64位而现在358和3288(RK) 都是采用32位的工具链,因此最好根据编译错误下载对应的缺失库。
2、 编译(SourceCode)->资源代码目录:
1、 PM编译(编译工具采用keil uvision5):
PM SourceCode Path
Step 1: cd SourceCode/vendor/mstar/pm/Project/Mstar/Mainz/
Step 2: Open project PM51_Mainz.Uv2
Step 3: Rebuild all project
Step 4:cp 生成的PM51_Mainz.bin到supernova目录下
生成的PM.bin 在pm/Project/Mstar/Mainz/Output/PM51_Mainz_tmp.bin
SourceCode/vendor/mstar/supernova/ project/board/mainz/bin/prebuilt/pm51/
名字:PM.bin STR_PM.bin
2、 mboot 编译
Step 1:cd ./SourceCode/vendor/mstar/mboot/MBoot/sboot/
Step 2: ## Please check your board use DDR
Step3:
cp configs/mainz/.config.mainz.android.142b.rom_emmc.64bit.kernel.optee .config (11月代码编译)
(DTMB)cp configs/mainz/.config.mainz.android.142b.rom_emmc.64bit.kernel.optee.20x20.dtmb
.config
(DVB)cp configs/mainz/.config.mainz.android.142b.rom_emmc.64bit.kernel.optee.20x20.dvb
.config
(ISDB)cp configs/mainz/.config.mainz.android.142b.rom_emmc.64bit.kernel.optee.20x20.isdb
.config
Step 4: make menuconfig
Step 5: ## Exit & Save
Step 6: make clean && make
Step 7: ## Get mboot.bin in MBoot/sboot/out/
cp out/mboot.bin …/…/…/supernova/projects/board/mainz/bin/mboot/mainz.142B.emmc.64bit.optee.dvb/

cp out/rom_emmc_boot.bin …/…/…/supernova/projects/board/mainz/bin/mboot/mainz.142B.emmc.64bit.optee.dvb/

copy to 下面目录里面

If DTMB supernova\projects\board\mainz\bin\mboot\mainz.142B.emmc.64bit.optee.dtmb\

if DVB supernova\projects\board\mainz\bin\mboot\mainz.142B.emmc.64bit.optee.dvb\

if ISDB supernova\projects\board\mainz\bin\mboot\mainz.142B.emmc.64bit.optee.isdb\

3、 Kernel 编译:
为kernel source特点的gcc,这里还未做区分
export PATH=/home/boe/tools/linaro_aarch64_linux-2014.09_r20170413/bin/: P A T H e x p o r t P A T H = / h o m e / b o e / t o o l s / a r m / a r m − 2012.09 / b i n / : PATH export PATH=/home/boe/tools/arm/arm-2012.09/bin/: PATHexportPATH=/home/boe/tools/arm/arm2012.09/bin/:PATH(可省)
Step 1: cd SourceCode/vendor/mstar/kernel/linaro/
Step 2: ./genlink.sh
Step 3: cp .config_mainz_SMP_arm64_andorid_emmc_nand_optee .config
Step 4: make menuconfig
Step 5: ## Exit & Save
Step 6: make clean && make -j32
Step 7: mkdir -p …/kernel_ko/module
Step 8: find -L ./ -name ".ko" -exec cp {} …/kernel_ko/module ;
Step 9: cp arch/arm64/boot/Image …/kernel_ko/kernel
将Image文件拷贝成kernel文件。
Step 10: cp -rf …/kernel_ko/
…/…/…/…/device/mstar/bennet-kernel/
4、 Android 编译
Step 1:cd SoueceCode/
Step 2: source build/envsetup.sh
Step 3: lunch
(
(DTMB) lunch bennet-userdebug
(DVB) lunch bennet_dvb-userdebug
(ISDB) lunch bennet_isdb-userdebug
)
#Step 4: setup_jack_server.sh #仅在第一次 build Android Oreo 案子时执行一次
Step 5: make -j32 (根据计算机性能和需求选择)
Step 6: Get images in …/images/oreo/bennet/
5、 Supernova编译
Step 1: cd SourceCode/vendor/mstar/supernova/ project
Step 2: source
(
(DTMB 142B)
source board/mainz/buildsettings/build_Mainz_142B_ROM_EMMC_TVOS_DTMB_OREO_CMA_OPTEE.sh
(DVB 142B)
source board/mainz/buildsettings/build_Mainz_142B_ROM_EMMC_TVOS_DVB_OREO_CMA_OPTEE.sh
(ISDB 142B)
source board/mainz/buildsettings/build_Mainz_142B_ROM_EMMC_TVOS_ISDB_OREO_CMA_OPTEE.sh
)
Step 3: 放入 hash key 到 project/customerinfo/inc/Customer_Info.h
#Step 4: make rebuild_all -j16 && make image_all 新代码不需要
#Step 5: Get images in target/dvb.mainz/images/ext4
#Step 6:cp target/dvb.mainz/images/ext4/* SourceCode/out//target/product/bennet
#Step4 Step5 Step6 这三步都可以不要
6、 综合编译生产USB升级文件
进入代码总目录
Step 0:source build/envsetup.sh
lunch 21
Step 1: releaseimage.sh
Step 2: ./vendor/mstar/common/scripts/make_usb_upgrade.sh
Step 3: Get images in …/images/oreo/bennet/MstarUpgrade.bin
7、 综合编译第二中
Step 0:source build/envsetup.sh
lunch 21
Step1:make clean
Step2:make –j12
Step3:releaseimage.sh
Step 4: ./vendor/mstar/common/scripts/make_usb_upgrade.sh

3、 整体架构层次:
Mstar Android 网络机的组成部分:Mboot,PM,Kernel,Supernova,Android OS,TvAPP(TVplay,TVSetting,Hotkey…),Local MM APP

4、 Mboot:
Mboot用于系统的启动引导,硬件初始化,从NAND flash加载Linux内核和应用程序到DRAM;Mboot一般存储在spi falsh,它由Sboot和Uboot组成。

SBoot:
Sboot是Mboot启动系统的入口,用于初始化CPU,cache,寄存器等,随后跳转到Uboot入口。
Sboot的启动入口地址是在sboot.lds文件里描述(lds文件是决定一个可执行程序的各个段的存储位置,以及入口地址,起到链接定位的作用)。
./src/mainz/sboot.lds
OUTPUT_ARCH(arm)
OUTPUT_FORMAT(“elf32-littlearm”, “elf32-littlearm”, “elf32-littlearm”)
ENTRY(_vector)
MEMORY
{
boot : ORIGIN = 0x1fc00000, LENGTH = 14K
boot2 : ORIGIN = 0x1fc00000 + 7K, LENGTH = 7K
boot3 : ORIGIN = 0x1fc00000 + 7K, LENGTH = 7K
boot4 : ORIGIN = 0x1fc00000 + 7K, LENGTH = 7K
ram : ORIGIN = 0x20100000, LENGTH = 26K
}
SECTIONS
{
.text1 :
{
boot.o (.text)
. = ALIGN(16);
_ld_bootrom_start = ABSOLUTE(.);
bootrom.o (.text)
bootrom_cache.o (.text)
drvRIU.o (.text)
drvAESDMA.o (.text)
代码入口点:ENTRY(_vector)
./src/mainz/boot.S(汇编)
最终编译生成boot.o;进行寄存器设置。
随后执行./src/mainz/bootrom.S进一步进行寄存器设置并进行UART初始化工作,具体实现是在./src/mainz/include/drv_uart.inc文件

随后执行./src/mainz/bootram.S,从这里会跳转到uboot执行
BOOT_CopyBootRAM->BOOTRAM_Entry->UBoot entry
Sboot执行流程图

UBoot:
基于u-boot-2011.06,Uboot自带CLI(Command Line Interface)进入此处后就可以通过串口命令与用户进行交互了。
Uboot主要是做如下事情:
通过CLI设置环境变量执行操作
初始化系统
加载kernel到DRAM
烧录kernel和application到FLASH
设置kernel参数
解压kernel
传递启动参数到kernel
Uboot启动入口地址在u-boot.lds描述
./u-boot.lds
通过该文件得知会指向到./arch/arm/cpu/armv7/start.S最终在start.S描述入口地址
OUTPUT_FORMAT(“elf32-littlearm”, “elf32-littlearm”, “elf32-littlearm”)
OUTPUT_ARCH(arm)
ENTRY(_start)
STACK_SIZE = 0x20000;
__assert_func = 0;
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
__config_text_start = .;
arch/arm/cpu/armv7/start.o (.text)
(.text)
*(COMMON)
. = ALIGN(4);
__config_text_end = .;
}
.rodata :
{
__config_rodata_start = .;
(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata)))
. = ALIGN(4);

u-boot.lds描述的信息

UBoot启动过程:

.u_boot_cmd :
{
__config_uboot_cmd_start = .;
__u_boot_cmd_start = .;
*(.u_boot_cmd)
. = ALIGN(4);
__u_boot_cmd_end = .;
__config_uboot_cmd_end = .;
}

获取所有被U_BOOT_CMD定义的结构体变量将其放入.u_boot_cmd中。
获取所有U_BOOT_CMD命令的API
cmd_tbl_t *find_cmd (const char *cmd)
{
#ifdef CONFIG_MSTAR_STR_MINISIZE
int len = u_boot_cmd_tbl_end - u_boot_cmd_tbl_start;
return find_cmd_tbl(cmd, u_boot_cmd_tbl_start, len);
#else
int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
#endif
}
cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
{
cmd_tbl_t *cmdtp;
cmd_tbl_t *cmdtp_temp = table; /*Init value */
const char *p;
int len;
int n_found = 0;

if (!cmd)
return NULL;
/*
* Some commands allow length modifiers (like “cp.b”);
* compare command name only until first dot.
*/
len = ((p = strchr(cmd, ‘.’)) == NULL) ? strlen (cmd) : (p - cmd);

for (cmdtp = table;
cmdtp != table + table_len;
cmdtp++) {
if (strncmp (cmd, cmdtp->name, len) == 0) {
if (len == strlen (cmdtp->name))

}
运行U_BOOT_CMD定义的CMD的API
./common/main.c
int run_command (const char *cmd, int flag) /*const关键字常量指针,指针指向的内容不能改变
{
cmd_tbl_t cmdtp;
char cmdbuf[CONFIG_SYS_CBSIZE]={0}; /
working copy of cmd */
char token; / start of token in cmdbuf */
char sep; / end of token (separator) in cmdbuf */
char finaltoken[CONFIG_SYS_CBSIZE]={0};
char *str = cmdbuf;
char argv[CONFIG_SYS_MAXARGS + 1]; / NULL terminated */
int argc, inquotes;
int repeatable = 1;
int rc = 0;

#ifdef DEBUG_PARSER
printf (“[RUN_COMMAND] cmd[%p]=”“, cmd);
puts (cmd ? cmd : “NULL”); /* use puts - string may be loooong */
puts (”“\n”);
#endif

clear_ctrlc(); /* forget any previous Control C */
…}
Uboot环境变量:
是一种很有效的全局变量,一般存储在SPI flash中可以使用printenv,setenv,saveenv,cleanallenv来查看、修改、保存和清楚环境变量,当前环境变量的存储介质修改
./include/configs/uboot_module_config.h
#define ENABLE_MODULE_ENV_IN_SERIAL 0
#define ENABLE_MODULE_ENV_IN_MMC 1
#define ENABLE_MODULE_ENV_IN_UFS 0
#define ENABLE_MODULE_ENV_IN_NAND 0
5、 PM
PM即(power manager)为待机控制管理模块,待机时会有一颗C51的MCU在跑,复制电源管理、IR(power)和按键等操作的处理。
PM 的进入可以从mboot进入和supernova进入
Mboot To PM:
执行Command
Main_Loop()->MstarProcess()->App_Register_Process()、run_command(do_if_boot_to_pm)->If_Boot_To_PM()->msAPI_Power_PowerDown_EXEC()->MDrv_PM_PowerDown(&PmPowerDownCfg);
通过调用If_Boot_To_PM()根据环境变量“factory_poweron_mode”判断是否进入PM,可以在mboot命令行设置“setenv factory_poweron_mode direct”,也可以在工厂菜单设置,也可以通过调用代码修改。
./mboot/MBoot/MstarCustomer/MSTAR/src/CusPM.c
static int If_Boot_To_PM(void)
{
EN_POWER_ON_MODE ePowerMode=EN_POWER_DC_BOOT;
UBOOT_TRACE(“IN\n”);

#if (WDT_STANDBY_MODE==1)
MDrv_WDT_Init(E_WDT_DBGLV_ALL);

if(MDrv_WDT_IsReset() && get_poweroff_flag())
{

MDrv_WDT_ClearRstFlag();
return 0;
}
#endif
ePowerMode=msAPI_Power_QueryPowerOnMode();

if ( EN_POWER_AC_BOOT == ePowerMode)
{

if(getenv(“factory_poweron_mode”) == NULL) //first boot on has no data
{
setenv(“factory_poweron_mode”, “direct”);//default is direct mode (never standby)
saveenv();
}
if(getenv(“burnmode_poweron”) == NULL)
{
setenv(“burnmode_poweron”, “false”);
saveenv();
}
if(getenv(“dc_poweroff”) == NULL)
{
setenv(“dc_poweroff”, “0”);
saveenv();
}
…}
Supernova To PM
当有Power off的指令下达或者因为timer out进入待机,此时将从Supernova进入PM
Msrv_Control_common:EnterSleepMode()->void mapi_system::PowerDown()->MDrv_PM_PowerDown();后进入到PM
6、 Kernel:
Linux内核编译链接生成的ELF镜像文件是vmlinux,由顶层的Makefile可知

Externally visible symbols (used by link-vmlinux.sh)

export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) ( v i r t − y ) e x p o r t K B U I L D L D S : = a r c h / (virt-y) export KBUILD_LDS := arch/ (virty)exportKBUILDLDS:=arch/(SRCARCH)/kernel/vmlinux.lds
export LDFLAGS_vmlinux

used by scripts/pacmage/Makefile

export KBUILD_ALLDIRS := $(sort ( f i l t e r − o u t a r c h / (filter-out arch/%, (filteroutarch/(vmlinux-alldirs)) arch Documentation include samples scripts tools)

vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) KaTeX parse error: Expected 'EOF', got '#' at position 45: …rm/Makefile 可知 #̲Default value h…(MMUEXT).o

defines filename extension depending memory management type.

ifeq ($(CONFIG_MMU),)
MMUEXT := -nommu
对于有MMU的处理器,MMUEXT为空白字符,因此./arch/arm/kernel/head.o为第一个链接进入的文件,因此非压缩的Linux入口函数为./arch/arm/kernel/head.S中
#include “head-common.S”
因为head.S最后包含head-common.S
./arch/arm/kernel/head-common.S

最终找到C入口函数为start_kernel()
./init/main.c中实现的
extern void early_putstr(const char *fmt, …);
asmlinkage __visible void __init start_kernel(void)
{
char *command_line;
char *after_dashes;

set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();

rest_init();
}
start_kernel函数是内存初始化的主体函数,最终他会调到rest_init()函数;
./init/main.c
static noinline void __ref rest_init(void)
{
int pid;
#if (MP_CACHE_DROP==1)
int pid_kthre_drop_cache;
struct sched_param para;
struct task_struct *p;
int srch_retval;
#endif

rcu_scheduler_starting();
/*

  • We need to spawn init first so that it obtains pid 1, however
  • the init task will end up wanting to create kthreads, which, if
  • we schedule it before we create kthreadd, will OOPS.
    */
    //创建第一个内核线程,入口函数是kernel_init()
    kernel_thread(kernel_init, NULL, CLONE_FS);
    numa_default_policy();
    //创建出第二个内核线程,入口函数是kthreadd()
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
    …}

./init/main.c
static int __ref kernel_init(void *unused)
{
#if (MP_CHECKPT_BOOT == 1)
unsigned int PiuTick;
unsigned int PiuTime;
#endif
int ret;

kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
#if !defined(CONFIG_MP_MSTAR_STR_BASE)
…}
./init/main.c
static noinline void __init kernel_init_freeable(void)
{

do_basic_setup();

}
./init/main.c
static void __init do_basic_setup(void)
{
cpuset_init_smp();
shmem_init();
driver_init();
init_irq_proc();
do_ctors();
usermodehelper_enable();
do_initcalls();
}
do_basic_setup()函数先调用 driver_init()函数完成驱动程序的初始化,又通过do_initcalls()函数依次调用了系统中所有的初始化函数。
7、 Android:
安卓启动流程(后续补充)

Zygote后即启动了第一个Java程序
8、 Supernova:
Init.rc里面会配置tvos的启动服务
./tvos/main/main.cpp
int main(int argc, char **argv)
{

MSrv_Control::Build();
MAPI_BOOL bEnable_4k2k_Nikeu = MAPI_FALSE, bEnable_4k2k_Napoli = MAPI_FALSE;
int eUrsaType = E_URSA_NONE;
SystemInfo::GetInstance()->GetModuleParameter_int(“M_URSA:F_URSA_URSA_TYPE”, &eUrsaType, 0);
SystemInfo::GetInstance()->GetModuleParameter_bool(“M_BACKEND:F_BACKEND_ENABLE_4K2K_NIKEU”, &bEnable_4k2k_Nikeu);
SystemInfo::GetInstance()->GetModuleParameter_bool(“M_BACKEND:F_BACKEND_ENABLE_4K2K_NAPOLI”, &bEnable_4k2k_Napoli);

}
MSrv_Control::Build()主要是初始化硬件配置
创建一个mapi_system类的实例,mapi_system负责
Class mapi_system : public mapi_base
加载外部配置文件,主要是INI文件,包括EDID,HDCP,PQ,Volume Curve等;
加载客制化配置
初始化I2C,GPIO,keypad,这里可以结合SN_board_XX.h里面定义的配置
通过mapi_interface::build()创建信号处理相关类的实例
pPcb = new (std::nothrow) device_pcb: 定义device_pcb类的实例,主要负责Tuner,Demod,AudioAmp,DTMB Demod的选择与初始化

adb logcat -v -time 2>&1 |tee logcat.log

编译环境jack-server配置
比如在home/cfj/.jack-server/config-properties文件和/home/cfj/.jack-settings文件
两个的端口号要对应

/home/cfj/.jack-settings

home/cfj/.jack-server/config-properties

QQ 交流群:712288614

相关推荐

  1. mstar 开发环境

    2024-07-19 03:46:02       23 阅读
  2. golang开发环境

    2024-07-19 03:46:02       62 阅读
  3. Dockerr开发环境

    2024-07-19 03:46:02       49 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-19 03:46:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-19 03:46:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-19 03:46:02       58 阅读
  4. Python语言-面向对象

    2024-07-19 03:46:02       69 阅读

热门阅读

  1. Jupyter Notebook: 是一个强大的交互式计算

    2024-07-19 03:46:02       26 阅读
  2. String、StringBuilder 和 StringBuffer 有什么区别?

    2024-07-19 03:46:02       25 阅读
  3. Windows图形界面(GUI)-DLG-C/C++ - 树形视图(TreeView)

    2024-07-19 03:46:02       25 阅读
  4. 正则表达式

    2024-07-19 03:46:02       23 阅读
  5. 网络同步学习(状态同步,帧同步)

    2024-07-19 03:46:02       24 阅读
  6. RNN模型

    2024-07-19 03:46:02       22 阅读
  7. 如何解决 CentOS 7 官方 yum 仓库无法使用

    2024-07-19 03:46:02       25 阅读
  8. 嵌入式linux相机 转换模块

    2024-07-19 03:46:02       23 阅读
  9. 定制 Linux 内核的意义

    2024-07-19 03:46:02       19 阅读