Files
player/Project/make.py

361 lines
8.3 KiB
Python
Raw Normal View History

2025-06-28 18:16:25 +08:00
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"
2025-06-28 18:16:25 +08:00
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',
2025-07-10 00:08:56 +08:00
'-O3',
2025-07-05 19:05:35 +08:00
'-Wall',
'-fdata-sections',
2025-06-28 18:16:25 +08:00
'-ffunction-sections',
# '-u _printf_float', # 使用这个选项会导致调用exit
'-specs=nano.specs', # 使用nano-newlib
2025-06-28 18:16:25 +08:00
# debug
2025-06-29 11:20:46 +08:00
'-g -gdwarf-2'
2025-06-28 18:16:25 +08:00
]
DEF=[
'-DUSE_STDPERIPH_DRIVER',
'-DSTM32F429_439xx',
'-DARM_MATH_CM4',
'-D__FPU_PRESENT=1',
# '-D__GNUC__',
'-D__packed=__attribute__((__packed__))',
'-D__weak=__attribute__((weak))'
]
INC=[
2025-06-28 22:15:49 +08:00
'-ISrc/MJPEG',
'-ISrc/MJPEG/JPEG',
2025-06-28 18:16:25 +08:00
'-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'
2025-06-28 18:16:25 +08:00
]
SRC_DIR=[
2025-06-28 22:15:49 +08:00
'Src/MJPEG',
2025-06-28 18:16:25 +08:00
'Src/STM32/STM32F4xx_StdPeriph_Driver/src',
'Src/Drive/Source',
'Src/FreeType/src',
'Src/JPEG',
'Src/lpng1637',
2025-06-28 22:15:49 +08:00
# 'Src/lua-5.4.2/src',
2025-06-28 18:16:25 +08:00
'Src/MP3',
'Src/MyApp',
'Src/MyWin',
'Src/MyWinApp',
'Src/rt-thread/src',
# 'Src/sqlite3',
]
SRC=[
2025-06-29 11:20:46 +08:00
# 'Src/MY/startup_stm32f429_439xx.s',
'Src/MY/startup_stm32f429xx.s',
2025-06-28 22:15:49 +08:00
'Src/STM32/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c',
2025-06-28 18:16:25 +08:00
"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',
2025-06-28 22:15:49 +08:00
"Src/lib/buff.c",
2025-06-28 18:16:25 +08:00
'Src/rt-thread/board.c',
# 'Src/rt-thread/core_delay.c',
'Src/rt-thread/ports/context_gcc.S',
2025-06-28 18:16:25 +08:00
'Src/rt-thread/ports/cpuport.c',
2025-06-28 22:15:49 +08:00
'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',
2025-06-28 18:16:25 +08:00
]
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:
2025-06-28 22:15:49 +08:00
ret = subprocess.run(cmd.cmd, shell=True, timeout=60).returncode
2025-06-28 18:16:25 +08:00
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))
2025-06-28 22:15:49 +08:00
def run_cmd_queue(cmd_queue:Queue,cpu_num:int=8):
2025-06-28 18:16:25 +08:00
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} \
2025-06-28 18:16:25 +08:00
-T{LD_FILE} -lc -lm -lnosys -Wl,-Map={OUTPUT}/{TARGET}.map,--cref -Wl,--gc-sections \
-Wl,-print-memory-usage"
2025-06-28 18:16:25 +08:00
print(f"链接 {dst}")
2025-06-28 22:15:49 +08:00
with open(f"{OUTPUT}/{TARGET}.rsp",'w+') as f:
f.write(rsp.replace('\\','/'))
ret=os.system(f"{CC} @{OUTPUT}/{TARGET}.rsp")
2025-06-28 18:16:25 +08:00
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
2025-06-28 18:16:25 +08:00
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")
2025-07-10 00:08:56 +08:00
os.system(f"{OBJDUMP} -D {OUTPUT}/{TARGET}.elf > {OUTPUT}/{TARGET}.lst")
2025-06-28 18:16:25 +08:00
if __name__ == "__main__":
tick_start=time.time()
main()
tick_end=time.time()
print(f"cost: {tick_end-tick_start}")
2025-06-28 22:15:49 +08:00
# for item in find_type('Src/zlib',".c"):
# print(f"'{item}',".replace('\\','/'))