# -*- coding: utf-8 -*- import os import sys import time import dataclasses from multiprocessing import Process,Queue,Value,cpu_count from create_lambda_fun import search_lambda from create_signal_fun import moc_file_create ''' 修改编译脚本之后需要全编译一次 ''' CC = 'gcc' CSRC = ["main.c"] CINC = ['-Isoft',"-Iriscv_cpu", "-I./","-Itest"] CDEF = ["-DTEST","-DLINUX"] ASRC = [] BUILD_DIR = 'build' TARGET = 'hello' # CFLAG = ["-Wall -pedantic -specs=nano.specs -mcpu=cortex-m3 -mthumb -lc -lm -lnosys -Og -Tstm32_boot.ld", # f"-Wl,-Map={BUILD_DIR}/{TARGET}.map,--cref -Wl,--gc-sections"] # -pedantic 这一项是ISO语法检验 CFLAG = ["-Wall -g","-pthread"] # 找到指定后缀的文件 def find_type(path:str,fix:list): dlist=os.listdir(path) file_list=[] for i in dlist: ps=os.path.join(path, i) if os.path.isdir(ps): file_list+=find_type(ps,fix) else: suf=ps.split('.')[-1] if(suf in fix): file_list.append(ps) return file_list ''' 将.c编译为.o文件, 编译脚本需要实现 如果.c文件有修改 则重新编译对应文件的.o文件 gcc -c test.c -o test.o 输出依赖关系到.d文件 gcc -MM main.c -o build/main.d ''' def tran_path(path:str): path=os.path.normpath(os.path.join(BUILD_DIR,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): while(not cmd_queue.empty()): if(failed_num.value>0): return try: cmd=cmd_queue.get_nowait() except Exception: return_list.put((cpu_index,True)) return print(f"[{cpu_index}] {cmd.info}") ret=os.system(cmd.cmd) if(ret): return_list.put((cpu_index,False)) failed_num.value+=1 return return_list.put((cpu_index,True)) def run_cmd_queue(cmd_queue:Queue,cpu_num:int=cpu_count()): if(cmd_queue.empty()): return 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.start() process_list.append(p) for i in process_list: i.join() # 消耗掉所有数据防止进程无法退出 while not cmd_queue.empty(): cmd_queue.get() while not return_list.empty(): i=return_list.get() if(not i[1]): print(f"子进程 [{i[0]}] 运行失败") sys.exit(-1) # 保证目标都存在 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(CINC)} {' '.join(CDEF)} {' '.join(CFLAG)}" for i in src: name=os.path.splitext(tran_path(i))[0] 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) run_cmd_queue(CmdQueue) # 生成中间文件 def build_object(src:list): CmdQueue=Queue() dst_list=[] flags=f"{' '.join(CINC)} {' '.join(CDEF)} {' '.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']) if(file_type in ['.c','.C']): if(check_rebuild(dst,read_depend_files(cd))): cmd=f"{CC} -c {i} -o {dst} {flags}" CmdQueue.put(cmd_item_t(cmd,f"编译 {dst}")) dst_list.append(dst) run_cmd_queue(CmdQueue) # 生成可执行文件 def build_target(src:list): flags=f"{' '.join(CINC)} {' '.join(CDEF)} {' '.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(BUILD_DIR,TARGET) if(check_rebuild(dst,obj_list)): cmd=f"{CC} {' '.join(obj_list)} -o {dst} {flags}" print(f"链接 {dst}") ret=os.system(cmd) if(ret): sys.exit(-1) def main(): global CSRC global ASRC if(not os.path.exists(BUILD_DIR)): os.makedirs(BUILD_DIR) # 在命令行中传入的源文件 CSRC+=sys.argv[1:] CSRC+=find_type('soft',['c','C']) CSRC+=find_type('riscv_cpu',['c','C']) CSRC=search_lambda(CSRC) moc_file_create(f"{BUILD_DIR}/moc_tmp.c",list(item[2:] for item in CINC)) CSRC.append(f"{BUILD_DIR}/moc_tmp.c") build_depend(CSRC) build_object(CSRC) build_target(CSRC+ASRC) if __name__ == "__main__": tick_start=time.time() main() tick_end=time.time() print(f"cost: {tick_end-tick_start}")