Files
player/Project/make.py
2025-09-24 00:03:16 +08:00

384 lines
9.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import sys
import time
import shutil
import dataclasses
import subprocess
from pathlib import Path
from multiprocessing import Process,Queue,Value,cpu_count
os.environ["PATH"]+=";D:/Program Files/arm-gnu-toolchain/bin"
os.environ["LANG"]="zh_CN.GBK"
CC="arm-none-eabi-gcc"
AS = CC + ' -x assembler-with-cpp'
OBJCPY="arm-none-eabi-objcopy"
OBJDUMP="arm-none-eabi-objdump"
SIZE="arm-none-eabi-size"
CFLAG=[
'-mcpu=cortex-m4',
'-mthumb',
'-mfpu=fpv4-sp-d16',
'-mfloat-abi=hard',
'-O3',
'-Wall',
'-fdata-sections',
'-ffunction-sections',
# '-u _printf_float', # 使用这个选项会导致调用exit
'-specs=nano.specs', # 使用nano-newlib
# debug
'-g -gdwarf-2'
]
DEF=[
'-DUSE_STDPERIPH_DRIVER',
'-DSTM32F429_439xx',
'-DARM_MATH_CM4',
'-D__FPU_PRESENT=1',
# '-D__GNUC__',
'-D__packed=__attribute__((__packed__))',
'-D__weak=__attribute__((weak))',
'-D__RTTHREAD__',
# 使用usb时打开这个宏 系统时钟会被设置为168MHz USB时钟为48MHz
# 如果不打开这个宏 系统时钟会被设置为180MHz USB会通信异常
'-D__USB_USB__',
]
INC=[
'-ISrc/MJPEG',
'-ISrc/MJPEG/JPEG',
'-ISrc/STM32/CMSIS/Device/ST/STM32F4xx/Include',
'-ISrc/STM32/CMSIS/Include',
'-ISrc/STM32/DSP/Include',
'-ISrc/STM32/STM32F4xx_StdPeriph_Driver/inc',
'-ISrc/Drive/Include',
'-ISrc/FATS',
'-ISrc/FreeType',
# '-ISrc/FreeType/devel',
'-ISrc/FreeType/include',
'-ISrc/JPEG',
'-ISrc/lib',
'-ISrc/lpng1637',
'-ISrc/lua-5.4.2',
'-ISrc/lua-5.4.2/src',
'-ISrc/MP3',
'-ISrc/MP3/helix',
'-ISrc/MY',
'-ISrc/MyApp',
'-ISrc/MyWin',
'-ISrc/MyWin/MyWinCore',
'-ISrc/MyWin/Window',
'-ISrc/MyWinApp',
'-ISrc/rt-thread',
'-ISrc/rt-thread/include',
# '-ISrc/sqlite3',
'-ISrc/zlib',
'-ISrc/NES',
# '-ISrc/TinyUSB/lib/rt-thread',
'-ISrc/TinyUSB/examples/device/cdc_dual_ports/src',
'-ISrc/TinyUSB/src/class/cdc',
'-ISrc/TinyUSB/src/common',
'-ISrc/TinyUSB/src/device',
'-ISrc/TinyUSB/src/portable/synopsys/dwc2',
'-ISrc/TinyUSB/src',
'-ISrc/TinyUSB/src/osal',
'-ISrc/TinyUSB/hw',
]
SRC_DIR=[
'Src/MJPEG',
'Src/STM32/STM32F4xx_StdPeriph_Driver/src',
'Src/Drive/Source',
'Src/FreeType/src',
'Src/JPEG',
'Src/lpng1637',
# 'Src/lua-5.4.2/src',
'Src/MP3',
'Src/MyApp',
'Src/MyWin',
'Src/MyWinApp',
'Src/rt-thread/src',
# 'Src/sqlite3',
'Src/TinyUSB/src/class/cdc',
'Src/TinyUSB/src/common',
'Src/TinyUSB/src/device',
'Src/TinyUSB/src/portable/synopsys/dwc2',
# 'Src/TinyUSB/src',
]
SRC=[
# 'Src/MY/startup_stm32f429_439xx.s',
'Src/MY/startup_stm32f429xx.s',
'Src/STM32/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c',
"Src/MY/bsp_init.c",
"Src/MY/main_my.c",
"Src/MY/stm32f4xx_it.c",
"Src/MY/sys_api.c",
"Src/MY/test.c",
'Src/FATS/diskio.c',
'Src/FATS/ff.c',
'Src/FATS/ffsystem.c',
'Src/FATS/mycc936.c',
"Src/lib/buff.c",
'Src/rt-thread/board.c',
# 'Src/rt-thread/core_delay.c',
'Src/rt-thread/ports/context_gcc.S',
'Src/rt-thread/ports/cpuport.c',
'Src/FreeType/ftdebug.c',
'Src/FreeType/ftfile.c',
'Src/zlib/adler32.c',
'Src/zlib/compress.c',
'Src/zlib/crc32.c',
'Src/zlib/deflate.c',
# 'Src/zlib/gzclose.c',
# 'Src/zlib/gzlib.c',
# 'Src/zlib/gzread.c',
# 'Src/zlib/gzwrite.c',
'Src/zlib/infback.c',
'Src/zlib/inffast.c',
'Src/zlib/inflate.c',
'Src/zlib/inftrees.c',
'Src/zlib/trees.c',
'Src/zlib/uncompr.c',
'Src/zlib/zutil.c',
'Src/MP3/helix/arm/asmmisc_gcc.s',
'Src/MP3/helix/arm/asmpoly_thumb2_gcc.s',
'Src/MY/syscalls.c',
'Src/NES/6502_gcc.S',
'Src/NES/6502cart_gcc.S',
'Src/NES/nes_apu.c',
'Src/NES/nes_main.c',
'Src/NES/nes_ppu.c',
'Src/NES/nes_mapper.c',
'Src/TinyUSB/src/tusb.c',
'Src/TinyUSB/lib/rt-thread/tusb_rt_thread_port.c',
'Src/TinyUSB/examples/device/cdc_dual_ports/src/usb_descriptors.c',
'Src/TinyUSB/hw/bsp/board.c'
]
LD_FILE="stm32f429ighx_flash.ld"
TARGET="stm32"
OUTPUT="output"
# 找到目录下的所有指定类型的文件
def find_type(path: str, fix: str):
root = Path(path)
file_list=[]
for file in root.rglob(f"*{fix}"):
if file.is_file():
file_list.append(f"{file}")
return file_list
def tran_path(path:str):
path=os.path.normpath(os.path.join(OUTPUT,path))
base_path=os.path.dirname(path)
if not os.path.exists(base_path):
os.makedirs(base_path)
return path
# 判断是否需要重新生成
def check_rebuild(dst:str,src:list):
if(not os.path.exists(dst)):
return True
dst_time=os.path.getmtime(dst)
src_time=[]
for i in src:
src_time.append(os.path.getmtime(i))
src_time.sort()
if(src_time[-1]>dst_time):
return True
return False
# 读取.d文件返回依赖文件列表
def read_depend_files(name:str):
with open(name) as f:
lines=f.readlines()
t=''
for line in lines:
line=line.strip()
if(line[-1]=='\\'):
t+=line[:-1]
else:
t+=line
t=t.split(':')[-1].strip()
t=t.split(' ')
return t
@dataclasses.dataclass
class cmd_item_t:
cmd:str
info:str
def run_cmd(cmd_queue:Queue,cpu_index:int,return_list:Queue,failed_num):
ack=True
while(not cmd_queue.empty()):
if(failed_num.value>0):
break
try:
cmd=cmd_queue.get_nowait()
except Exception:
break
print(f"[{cpu_index}] {cmd.info}")
# ret=os.system(cmd.cmd)
try:
ret = subprocess.run(cmd.cmd, shell=True, timeout=60).returncode
except subprocess.TimeoutExpired:
print("命令执行超时!")
failed_num.value += 1
ret = -1
if(ret!=0):
print(f"[{cpu_index}] ret={ret}")
ack=False
failed_num.value+=1
break
return_list.put((cpu_index,ack))
def run_cmd_queue(cmd_queue:Queue,cpu_num:int=8):
if(cmd_queue.empty()):
return True
process_list = []
return_list=Queue()
failed_num=Value('i',0)
for i in range(cpu_num):
p = Process(target=run_cmd,args=(cmd_queue,i,return_list,failed_num,))
p.daemon=True
p.start()
process_list.append(p)
for i in process_list:
i.join()
ret=True
while not return_list.empty():
i=return_list.get()
if(not i[1]):
ret=False
print(f"子进程 [{i[0]}] 运行失败")
return_list.cancel_join_thread()
# 消耗掉所有数据防止进程无法退出
while not cmd_queue.empty():
cmd_queue.get()
cmd_queue.cancel_join_thread()
return ret
# 保证目标都存在
def check_exists(src:list):
for item in src:
for i in range(10):
if(os.path.exists(item)):
break
time.sleep(0.1)
# 生成依赖关系
def build_depend(src:list):
CmdQueue=Queue()
dst_list=[]
flags=f"{' '.join(INC)} {' '.join(DEF)} {' '.join(CFLAG)}"
for i in src:
name_t=os.path.splitext(tran_path(i))
name=name_t[0]
file_type=name_t[-1]
if(not file_type in ['.c','.C','.cpp']):
continue
dst='.'.join([name,'d'])
if(check_rebuild(dst,[i])):
cmd=f"{CC} -MM {i} -o {dst} {flags}"
CmdQueue.put(cmd_item_t(cmd,f"更新 {dst}"))
dst_list.append(dst)
return run_cmd_queue(CmdQueue)
# 生成中间文件
def build_object(src:list):
CmdQueue=Queue()
dst_list=[]
flags=f"{' '.join(INC)} {' '.join(DEF)} {' '.join(CFLAG)}"
for i in src:
name_t=os.path.splitext(tran_path(i))
name=name_t[0]
file_type=name_t[-1]
dst='.'.join([name,'o'])
cd='.'.join([name,'d'])
cmd = ''
if(file_type in ['.c','.C']):
if(check_rebuild(dst,read_depend_files(cd))):
cmd=f"{CC} -c {i} -o {dst} {flags}"
elif(file_type in ['.s','.S','.asm','.ASM']):
if(check_rebuild(dst,[i])):
cmd=f"{AS} -c {i} -o {dst} {flags}"
if(len(cmd)>0):
CmdQueue.put(cmd_item_t(cmd,f"编译 {dst}"))
dst_list.append(dst)
return run_cmd_queue(CmdQueue)
# 生成可执行文件
def build_target(src:list):
flags=f"{' '.join(INC)} {' '.join(DEF)} {' '.join(CFLAG)}"
obj_list=[]
for i in src:
name=os.path.splitext(tran_path(i))[0]
obj_list.append('.'.join([name,'o']))
dst=os.path.join(OUTPUT,TARGET)+".elf"
if(check_rebuild(dst,obj_list)):
rsp=f"{' '.join(obj_list)} -o {dst} {flags} \
-T{LD_FILE} -lc -lm -lnosys -Wl,-Map={OUTPUT}/{TARGET}.map,--cref -Wl,--gc-sections \
-Wl,-print-memory-usage"
print(f"链接 {dst}")
with open(f"{OUTPUT}/{TARGET}.rsp",'w+') as f:
f.write(rsp.replace('\\','/'))
ret=os.system(f"{CC} @{OUTPUT}/{TARGET}.rsp")
return ret==0
return False
def main():
global SRC
if not os.path.exists(OUTPUT):
os.mkdir(OUTPUT)
for item in SRC_DIR:
SRC += find_type(item,'.c')
if len(sys.argv) > 1:
l=[]
if sys.argv[1] == 'show_inc':
l=INC
elif sys.argv[1] == 'show_src':
l=SRC
l.sort()
for item in l:
t=item.replace('\\','/')
print(f"\"Project/{t}\",")
return
if build_depend(SRC):
if build_object(SRC):
if build_target(SRC):
os.system(f"{OBJCPY} -O binary -S {OUTPUT}/{TARGET}.elf {OUTPUT}/{TARGET}.bin")
os.system(f"{OBJCPY} -O ihex {OUTPUT}/{TARGET}.elf {OUTPUT}/{TARGET}.hex")
os.system(f"{OBJDUMP} -D {OUTPUT}/{TARGET}.elf > {OUTPUT}/{TARGET}.lst")
if __name__ == "__main__":
tick_start=time.time()
main()
tick_end=time.time()
print(f"cost: {tick_end-tick_start}")
# for item in find_type('Src/zlib',".c"):
# print(f"'{item}',".replace('\\','/'))