
import os
import sys
import time
import shutil




CC="riscv64-unknown-elf-gcc"
OBJCPY="riscv64-unknown-elf-objcopy"
OBJDUMP="riscv64-unknown-elf-objdump"

CFLAG=[
  "-march=rv32i",
  "-mabi=ilp32",
  "-ffunction-sections",
  "-fdata-sections",
  "-ffast-math",
  "-fno-common",
  "-fno-builtin-printf",
  "-Wall",
  "-Werror",
  "-g",
  "-O0",
  "-fno-omit-frame-pointer",
  "-msave-restore"
]

DEF=[]

INC=[
  "-I./riscv/rtthread/libcpu/risc-v/common",
  "-I./riscv/rtthread/include",
  "-I./riscv/startup",
  "-I./riscv/rtthread/components/drivers/include"
]

SRC=[
  "riscv/startup/main.c",
  "riscv/startup/test.c",
  # "riscv/startup/interrupt.c",
  "riscv/startup/start.S",
  # "riscv/startup/trap.S",
  "riscv/startup/rtthread_irq.c",

  "riscv/rtthread/libcpu/risc-v/common/atomic_riscv.c",
  "riscv/rtthread/libcpu/risc-v/common/context_gcc.S",
  "riscv/rtthread/libcpu/risc-v/common/cpuport.c",
  "riscv/rtthread/libcpu/risc-v/common/interrupt_gcc.S",
  "riscv/rtthread/libcpu/risc-v/common/trap_common.c",

  "riscv/rtthread/src/clock.c",
  "riscv/rtthread/src/components.c",
  "riscv/rtthread/src/cpu.c",
  "riscv/rtthread/src/idle.c",
  "riscv/rtthread/src/ipc.c",
  "riscv/rtthread/src/irq.c",
  "riscv/rtthread/src/kservice.c",
  "riscv/rtthread/src/mem.c",
  "riscv/rtthread/src/memheap.c",
  "riscv/rtthread/src/mempool.c",
  "riscv/rtthread/src/object.c",
  "riscv/rtthread/src/scheduler_comm.c",
  # "riscv/rtthread/src/scheduler_mp.c",
  "riscv/rtthread/src/scheduler_up.c",
  "riscv/rtthread/src/signal.c",
  "riscv/rtthread/src/slab.c",
  "riscv/rtthread/src/thread.c",
  "riscv/rtthread/src/timer.c",

  "riscv/rtthread/src/klibc/kstdio.c",
  "riscv/rtthread/src/klibc/kstring.c",

  "riscv/rtthread/components/drivers/core/device.c"
]

LD_FILE="riscv.ld"

TARGET="riscv"

OUTPUT="output"



def tran_path(path:str):
  p=path.replace('\\','/')
  p=p.replace('/','_')
  if(p[0]=='.'):
    return p[1:]
  else:
    return p


# 判断是否需要重新生成
def check_rebuild(dst:str,src:list):
  # print(f"src:{src}")
  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
  # for item in src_time:
  #   if(item>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(' ')
    # print(f"依赖列表{t}")
    return t


# 生成依赖关系
def build_depend(src:list):
  flags=f"{' '.join(INC)} {' '.join(DEF)} {' '.join(CFLAG)}"
  for i in src:
    name=tran_path(i).split('.')[0]
    dst='.'.join([name,'d'])
    dst=os.path.join(OUTPUT,dst)
    if(check_rebuild(dst,[i])):
      cmd=f"{CC} -MM {i} -o {dst} {flags}"
      print(cmd)
      ret=os.system(cmd)
      if(ret):
        exit()
    else:
      # print(f"{i} 没有更新源文件")
      pass

# 生成中间文件
def build_object(src:list):
  flags=f"{' '.join(INC)} {' '.join(DEF)} {' '.join(CFLAG)}"
  for i in src:
    name_l=tran_path(i).split('.')
    name=name_l[0]
    file_type=name_l[-1]
    dst='.'.join([name,'o'])
    dst=os.path.join(OUTPUT,dst)
    cd='.'.join([name,'d'])
    cmd = ''
    if(file_type in ['c','.C']):
      cd=os.path.join(OUTPUT,cd)
      if(check_rebuild(dst,read_depend_files(cd))):
        cmd=f"{CC} -c {i} -o {dst} {flags}"
      else:
        # print(f"{i} 没有更新依赖关系")
        pass
    elif(file_type in ['s','S','asm','ASM']):
      if(check_rebuild(dst,[i])):
        cmd=f"{CC} -c {i} -o {dst} {flags}"
      else:
        # print(f"{i} 没有更新依赖关系")
        pass
    if(len(cmd)>0):
      print(cmd)
      ret=os.system(cmd)
      if(ret):
        exit()


# 生成可执行文件
def build_target(src:list):
  flags=f"{' '.join(INC)} {' '.join(DEF)} {' '.join(CFLAG)}"
  obj_list=[]
  for i in src:
    name=tran_path(i).split('.')[0]
    obj_list.append(OUTPUT+'/'+'.'.join([name,'o']))
  dst=os.path.join(OUTPUT,TARGET)+".elf"
  if(check_rebuild(dst,obj_list)):
    cmd=f"{CC} {' '.join(obj_list)} -o {dst} {flags} -T{LD_FILE} -Wall -Wextra -nostartfiles -Wl,-Map,\"{OUTPUT}/{TARGET}.map\""
    print(cmd)
    ret=os.system(cmd)
    if(ret):
      exit()
  else:
    # print(f"{dst} 没有更新的链接文件")
    pass



def main():
  global SRC

  if not os.path.exists(OUTPUT):
    os.mkdir(OUTPUT)

  build_depend(SRC)
  build_object(SRC)
  build_target(SRC)
  os.system(f"{OBJCPY} -O binary {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__":
  main()
