snapshot before regression test
This commit is contained in:
510
TransPyV/App/main.py
Normal file
510
TransPyV/App/main.py
Normal file
@@ -0,0 +1,510 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import argparse
|
||||
import w32.win32console as w32cmd
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import sys
|
||||
import ast
|
||||
import lib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.BuildPipeline as BuildPipeline
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Phase1 as Phase1
|
||||
import lib.core.Phase2 as Phase2
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import llvmlite
|
||||
import subprocess
|
||||
import viperlib
|
||||
import hashlib
|
||||
|
||||
|
||||
# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费
|
||||
# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30)
|
||||
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃
|
||||
POOL_SIZE: t.CDefine = 1073741824
|
||||
# 语言编码页
|
||||
CODE_PAGE: t.CDefine = 65001
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
|
||||
# ============================================================
|
||||
# main: 命令行入口
|
||||
#
|
||||
# 解析参数 → 加载配置 → AST 解析 → LLVM IR 翻译 → 编译管线 → 可选执行
|
||||
# ============================================================
|
||||
def main() -> int:
|
||||
w32cmd.SetConsoleOutputCP(CODE_PAGE)
|
||||
w32cmd.SetConsoleCP(CODE_PAGE)
|
||||
# 初始化 mbuddy 内存池
|
||||
arena: bytes = stdlib.malloc(POOL_SIZE)
|
||||
if arena is None:
|
||||
stdio.printf("FAIL: malloc for arena failed\n")
|
||||
return 1
|
||||
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE)
|
||||
if mb is None:
|
||||
stdio.printf("FAIL: MemBuddy init failed\n")
|
||||
return 1
|
||||
|
||||
# 设置全局 mbuddy 指针(sys 和 argparse 都需要)
|
||||
sys._mbuddy = mb
|
||||
argparse._mbuddy = mb
|
||||
ast._mbuddy = mb
|
||||
lib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Config._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Utils._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
HandlesTranslator._mbuddy = mb
|
||||
BuildPipeline._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
IncludesScanner._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
StubMerger._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Phase1._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Phase2._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
subprocess._mbuddy = mb
|
||||
hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
lib.InitLib((memhub.MemManager | t.CPtr)(mb))
|
||||
|
||||
# 初始化 VLogger 并打印启动日志
|
||||
log: VLogger.Logger | t.CPtr = VLogger.get_logger()
|
||||
if log is not None:
|
||||
log.info("TransPyV 启动")
|
||||
|
||||
# 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline)
|
||||
sys._init_argv()
|
||||
|
||||
# 创建参数解析器
|
||||
parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser(
|
||||
"TransPyV", "TransPyV 命令行参数解析", pool=mb)
|
||||
|
||||
# 注册参数(与 Projectrans.py main() 一致)
|
||||
parser.add_argument("--project", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "project.json 路径(默认查找当前目录)")
|
||||
parser.add_argument("--src", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "源文件目录(覆盖 project.json)")
|
||||
parser.add_argument("--temp", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "声明接口临时目录(覆盖 project.json)")
|
||||
parser.add_argument("--output", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "输出目录(覆盖 project.json)")
|
||||
parser.add_argument("--phase", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "阶段: 1=生成声明, 2=翻译+编译, all=全部")
|
||||
parser.add_argument("--cc", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "LLVM 编译器命令(覆盖 project.json)")
|
||||
parser.add_argument("--clean", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "清理 output 和 temp 目录")
|
||||
parser.add_argument("--run", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "编译成功后立即执行生成的可执行文件")
|
||||
parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "删除 includes.binary 预编译缓存并重新编译所有 includes")
|
||||
parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存")
|
||||
|
||||
# 解析命令行参数
|
||||
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
|
||||
if args is None:
|
||||
if log is not None:
|
||||
log.error("参数解析失败", "argparse")
|
||||
return 1
|
||||
|
||||
# 打印解析结果
|
||||
if log is not None:
|
||||
log.banner("TransPyV 参数解析结果")
|
||||
|
||||
# 字符串参数
|
||||
project: str = args.get_str("project")
|
||||
if project is not None:
|
||||
stdio.printf(" --project: %s\n", project)
|
||||
else:
|
||||
stdio.printf(" --project: (未指定)\n")
|
||||
|
||||
src: str = args.get_str("src")
|
||||
if src is not None:
|
||||
stdio.printf(" --src: %s\n", src)
|
||||
else:
|
||||
stdio.printf(" --src: (未指定)\n")
|
||||
|
||||
temp: str = args.get_str("temp")
|
||||
if temp is not None:
|
||||
stdio.printf(" --temp: %s\n", temp)
|
||||
else:
|
||||
stdio.printf(" --temp: (未指定)\n")
|
||||
|
||||
output: str = args.get_str("output")
|
||||
if output is not None:
|
||||
stdio.printf(" --output: %s\n", output)
|
||||
else:
|
||||
stdio.printf(" --output: (未指定)\n")
|
||||
|
||||
phase: str = args.get_str("phase")
|
||||
if phase is not None:
|
||||
stdio.printf(" --phase: %s\n", phase)
|
||||
else:
|
||||
stdio.printf(" --phase: (未指定,默认 all)\n")
|
||||
|
||||
cc: str = args.get_str("cc")
|
||||
if cc is not None:
|
||||
stdio.printf(" --cc: %s\n", cc)
|
||||
else:
|
||||
stdio.printf(" --cc: (未指定)\n")
|
||||
|
||||
# 布尔参数
|
||||
_gb_clean: INT = args.get_bool("clean")
|
||||
if _gb_clean:
|
||||
stdio.printf(" --clean: True\n")
|
||||
else:
|
||||
stdio.printf(" --clean: False\n")
|
||||
|
||||
if args.get_bool("run"):
|
||||
stdio.printf(" --run: True\n")
|
||||
else:
|
||||
stdio.printf(" --run: False\n")
|
||||
|
||||
if args.get_bool("rebuild-includes"):
|
||||
stdio.printf(" --rebuild-includes: True\n")
|
||||
else:
|
||||
stdio.printf(" --rebuild-includes: False\n")
|
||||
|
||||
if args.get_bool("clear-cache"):
|
||||
stdio.printf(" --clear-cache: True\n")
|
||||
else:
|
||||
stdio.printf(" --clear-cache: False\n")
|
||||
|
||||
stdio.printf("\n参数解析完成。\n")
|
||||
|
||||
# 加载 project.vpj 配置
|
||||
proj_loaded: int = 0
|
||||
proj_path: str = project
|
||||
if proj_path is not None:
|
||||
if log is not None:
|
||||
log.banner("工程配置")
|
||||
if Config.Load_project_config(proj_path) == 0:
|
||||
proj_loaded = 1
|
||||
else:
|
||||
stdio.printf(" 警告: 无法加载 project.vpj: %s\n", proj_path)
|
||||
else:
|
||||
# 尝试默认路径 project.vpj(当前目录和上级目录)
|
||||
proj_path = "project.vpj"
|
||||
if Config.Load_project_config(proj_path) == 0:
|
||||
proj_loaded = 1
|
||||
else:
|
||||
proj_path = "../project.vpj"
|
||||
if Config.Load_project_config(proj_path) == 0:
|
||||
proj_loaded = 1
|
||||
if proj_loaded == 1:
|
||||
# 提取 project.vpj 所在目录,将相对路径解析为基于该目录的路径
|
||||
proj_len: t.CSizeT = string.strlen(proj_path)
|
||||
slash_pos: t.CSizeT = proj_len
|
||||
for i in range(proj_len):
|
||||
idx: t.CSizeT = proj_len - 1 - i
|
||||
ch: t.CChar = proj_path[idx]
|
||||
if ch == '/' or ch == '\\':
|
||||
slash_pos = idx
|
||||
break
|
||||
proj_dir: str = ""
|
||||
if slash_pos > 0 and slash_pos < proj_len:
|
||||
proj_dir = stdlib.malloc(slash_pos + 1)
|
||||
if proj_dir is not None:
|
||||
string.memcpy(proj_dir, proj_path, slash_pos)
|
||||
proj_dir[slash_pos] = '\0'
|
||||
Config.resolve_paths(proj_dir)
|
||||
Config.print_config()
|
||||
|
||||
# === --clean: 清理 temp 和 output 目录 ===
|
||||
if _gb_clean:
|
||||
stdio.printf("\n[clean] 清理临时目录...\n")
|
||||
if Config.TempDir is not None:
|
||||
n: int = Utils.CleanDir(Config.TempDir)
|
||||
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.TempDir, n)
|
||||
if Config.OutputDir is not None:
|
||||
n2: int = Utils.CleanDir(Config.OutputDir)
|
||||
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.OutputDir, n2)
|
||||
|
||||
# === --phase 参数控制 ===
|
||||
# phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译
|
||||
# phase=2: 仅 stub 合并 + 编译(跳过 stub 分离)
|
||||
# phase=all: 两者都执行(默认)
|
||||
phase_mode: str = phase
|
||||
if phase_mode is None:
|
||||
phase_mode = "all"
|
||||
do_phase1: int = 0
|
||||
do_phase2: int = 0
|
||||
if phase_mode == "1" or phase_mode == "all":
|
||||
do_phase1 = 1
|
||||
if phase_mode == "2" or phase_mode == "all":
|
||||
do_phase2 = 1
|
||||
stdio.printf("[phase] 模式: %s (phase1=%d phase2=%d)\n", phase_mode, do_phase1, do_phase2)
|
||||
|
||||
# === Phase1: 扫描 includes(按需翻译)===
|
||||
# 对 includes 目录中每个 .py 文件,若 stub 不存在则翻译并分离 stub
|
||||
if do_phase1 != 0 and Config.IncludesDir is not None:
|
||||
ph1_temp: str = Config.TempDir
|
||||
if ph1_temp is None:
|
||||
ph1_temp = "."
|
||||
Phase1.RunPhase1(mb, Config.IncludesDir, ph1_temp, log)
|
||||
# 如果仅 Phase1(不执行 Phase2),直接退出
|
||||
if do_phase2 == 0:
|
||||
stdio.printf("[phase] Phase1 完成,退出\n")
|
||||
return 0
|
||||
|
||||
# AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树
|
||||
src_path: str = args.get_str("src")
|
||||
|
||||
# === 多文件项目模式 ===
|
||||
# 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .py 文件编译
|
||||
if src_path is None and project is not None and Config.SourceDir is not None:
|
||||
mf_temp: str = Config.TempDir if Config.TempDir is not None else "."
|
||||
mf_output: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||
mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
||||
mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic"
|
||||
mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
||||
mf_linker_flags: str = Config.LinkerFlags if Config.LinkerFlags is not None else "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition"
|
||||
mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe"
|
||||
mf_includes_bin: str = Config.get_includes_binary_dir()
|
||||
|
||||
mf_ret: int = Phase2.RunMultiFileProject(
|
||||
mb, Config.SourceDir, mf_temp, mf_output,
|
||||
mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out,
|
||||
mf_includes_bin, Config.IncludesDir, do_phase1, do_phase2, log, args)
|
||||
argparse.release(args)
|
||||
if log is not None:
|
||||
log.success("TransPyV 完成")
|
||||
return mf_ret
|
||||
|
||||
# === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 ===
|
||||
if src_path is None and project is not None:
|
||||
if Config.SourceDir is not None:
|
||||
# 构造入口路径: SourceDir/main.py
|
||||
sd_len: t.CSizeT = string.strlen(Config.SourceDir)
|
||||
path_buf: bytes = stdlib.malloc(sd_len + 16)
|
||||
if path_buf is not None:
|
||||
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir)
|
||||
src_path = path_buf
|
||||
stdio.printf("[project] 入口文件: %s\n", src_path)
|
||||
if src_path is not None:
|
||||
if log is not None:
|
||||
log.banner("AST 解析")
|
||||
# 打开文件
|
||||
f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
if log is not None:
|
||||
log.error("无法打开文件", "fileio")
|
||||
stdio.printf(" 路径: %s\n", src_path)
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 分配源代码缓冲区
|
||||
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if src_buf is None:
|
||||
if log is not None:
|
||||
log.error("malloc for src_buf failed", "memhub")
|
||||
f.close()
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 读取文件内容
|
||||
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read < 0:
|
||||
if log is not None:
|
||||
log.error("读取文件失败", "fileio")
|
||||
stdio.printf(" 错误码: %d\n", bytes_read)
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 添加 null 终止符,确保 strlen 和 SHA1 计算正确
|
||||
if bytes_read < SRC_BUF_SIZE:
|
||||
src_buf[bytes_read] = 0
|
||||
else:
|
||||
src_buf[SRC_BUF_SIZE - 1] = 0
|
||||
if log is not None:
|
||||
log.info("文件读取完成", "fileio")
|
||||
stdio.printf("读取 %d 字节\n", bytes_read)
|
||||
# 解析 AST(拆分为词法+语法两阶段,便于调试)
|
||||
ast._init_tables(mb)
|
||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||
ast._lexer_init(lx, src_buf, mb)
|
||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||
if tree is None:
|
||||
if log is not None:
|
||||
log.error("AST 解析失败", "ast")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
|
||||
# === 翻译 AST → LLVM IR ===
|
||||
if log is not None:
|
||||
log.banner("LLVM IR 翻译")
|
||||
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
||||
result: int = tr.translate(tree)
|
||||
if result == 0:
|
||||
IR_BUF_SIZE: t.CSizeT = 262144
|
||||
ir_buf: bytes = stdlib.malloc(IR_BUF_SIZE)
|
||||
if ir_buf is not None:
|
||||
tr.dump_ir(ir_buf, IR_BUF_SIZE, llvmlite.OUTPUT_FULL)
|
||||
|
||||
# === 编译管线: .ll → .obj → .exe ===
|
||||
if log is not None:
|
||||
log.banner("编译管线")
|
||||
|
||||
# module_name 用源代码内容的 SHA1(前 16 字符),与 Projectrans.py 一致
|
||||
# output_name 从文件名推导(如 test.py -> test.exe),保持可读性
|
||||
module_name: str = Utils.compute_sha1(mb, src_buf)
|
||||
if module_name is None:
|
||||
module_name = "main"
|
||||
output_name: str = "test_prog.exe"
|
||||
# 从文件名提取 output_name(去掉路径和 .py 扩展名)
|
||||
src_len: t.CSizeT = string.strlen(src_path)
|
||||
if src_len > 0:
|
||||
# 找到最后一个 / 或 \ 之后的部分
|
||||
base_start: t.CSizeT = src_len
|
||||
i: t.CSizeT = src_len
|
||||
while i > 0:
|
||||
i -= 1
|
||||
ch: t.CChar = src_path[i]
|
||||
if ch == '/' or ch == '\\':
|
||||
base_start = i + 1
|
||||
break
|
||||
if i == 0:
|
||||
base_start = 0
|
||||
# 找到 .py 扩展名
|
||||
base_end: t.CSizeT = src_len
|
||||
j: t.CSizeT = base_start
|
||||
while j < src_len:
|
||||
if src_path[j] == '.':
|
||||
base_end = j
|
||||
break
|
||||
j += 1
|
||||
# 输出名 = 文件名 + ".exe"
|
||||
name_len: t.CSizeT = base_end - base_start
|
||||
if name_len > 0:
|
||||
out_len: t.CSizeT = name_len + 5
|
||||
output_name = stdlib.malloc(out_len)
|
||||
if output_name is not None:
|
||||
# 手动复制文件名并追加 .exe(viperlib.snprintf 不支持 %.*s,string 无 strcat)
|
||||
string.strncpy(output_name, src_path + base_start, name_len)
|
||||
output_name[name_len] = '.'
|
||||
output_name[name_len + 1] = 'e'
|
||||
output_name[name_len + 2] = 'x'
|
||||
output_name[name_len + 3] = 'e'
|
||||
output_name[name_len + 4] = '\0'
|
||||
# 使用 project.vpj 中的配置
|
||||
temp_dir: str = Config.TempDir if Config.TempDir is not None else "."
|
||||
output_dir: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||
cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
||||
cc_flags: str = "-filetype=obj -relocation-model=pic"
|
||||
linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
||||
linker_flags: str = "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition"
|
||||
# --project 模式且未显式指定 --src 时:使用 config 中的 linker_output(如 TransPyV.exe)
|
||||
# 显式指定 --src 时:使用从文件名推导的 output_name(如 test.exe),避免覆盖正在运行的 exe
|
||||
if project is not None and Config.LinkerOutput is not None and args.get_str("src") is None:
|
||||
linker_output: str = Config.LinkerOutput
|
||||
else:
|
||||
linker_output: str = output_name
|
||||
|
||||
# 计算 includes.binary 目录路径(链接时附加预编译 .obj)
|
||||
includes_binary_dir: str = Config.get_includes_binary_dir()
|
||||
|
||||
ir_len: t.CSizeT = string.strlen(ir_buf)
|
||||
|
||||
# (--phase 参数已在配置加载后处理,此处直接使用 do_phase1/do_phase2)
|
||||
|
||||
# === Phase1 stub 分离:使用 OUTPUT_STUB/TEXT 模式分别生成 stub.ll 和 text.ll ===
|
||||
if do_phase1 != 0 and temp_dir is not None and module_name is not None:
|
||||
if log is not None:
|
||||
log.banner("stub 分离")
|
||||
SF_IR_SIZE: t.CSizeT = 262144
|
||||
td_len_sf: t.CSizeT = string.strlen(temp_dir)
|
||||
# 保存 stub.ll
|
||||
sf_stub_buf: bytes = stdlib.malloc(SF_IR_SIZE)
|
||||
if sf_stub_buf is not None:
|
||||
tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||
sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf)
|
||||
sf_stub_path: bytes = stdlib.malloc(td_len_sf + 32)
|
||||
if sf_stub_path is not None:
|
||||
viperlib.snprintf(sf_stub_path, td_len_sf + 32, "%s/%s.stub.ll", temp_dir, module_name)
|
||||
sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W)
|
||||
if not sf_f.closed:
|
||||
sf_f.write(sf_stub_buf, sf_stub_len)
|
||||
sf_f.close()
|
||||
stdlib.free(sf_stub_path)
|
||||
stdlib.free(sf_stub_buf)
|
||||
# 保存 text.ll
|
||||
sf_text_buf: bytes = stdlib.malloc(SF_IR_SIZE)
|
||||
if sf_text_buf is not None:
|
||||
tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||
sf_text_len: t.CSizeT = string.strlen(sf_text_buf)
|
||||
sf_text_path: bytes = stdlib.malloc(td_len_sf + 32)
|
||||
if sf_text_path is not None:
|
||||
viperlib.snprintf(sf_text_path, td_len_sf + 32, "%s/%s.text.ll", temp_dir, module_name)
|
||||
sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W)
|
||||
if not sf_tf.closed:
|
||||
sf_tf.write(sf_text_buf, sf_text_len)
|
||||
sf_tf.close()
|
||||
stdlib.free(sf_text_path)
|
||||
stdlib.free(sf_text_buf)
|
||||
|
||||
# phase=1 模式:仅生成 stub,不执行编译
|
||||
if do_phase2 == 0:
|
||||
if log is not None:
|
||||
log.success("Phase1 完成(仅 stub 分离,跳过编译)")
|
||||
argparse.release(args)
|
||||
return 0
|
||||
|
||||
# === Phase2: 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR ===
|
||||
final_ir: bytes = ir_buf
|
||||
final_ir_len: t.CSizeT = ir_len
|
||||
if temp_dir is not None and module_name is not None:
|
||||
if log is not None:
|
||||
log.banner("IR 组合")
|
||||
SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB
|
||||
combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE)
|
||||
if combined_buf is not None:
|
||||
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE)
|
||||
if combined_len > 0:
|
||||
final_ir = combined_buf
|
||||
final_ir_len = combined_len
|
||||
else:
|
||||
stdio.printf("[stub] BuildCombinedIR 失败,使用原始 IR\n")
|
||||
stdlib.free(combined_buf)
|
||||
|
||||
br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline(
|
||||
final_ir, final_ir_len, temp_dir, output_dir, module_name,
|
||||
cc_cmd, cc_flags, linker_cmd, linker_flags, linker_output,
|
||||
includes_binary_dir
|
||||
)
|
||||
if br is not None and br.Success == 1:
|
||||
if log is not None:
|
||||
log.success("编译管线完成")
|
||||
stdio.printf("输出: %s/%s\n", output_dir, linker_output)
|
||||
# --run 模式:执行生成的可执行文件
|
||||
if args.get_bool("run"):
|
||||
exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2)
|
||||
if exe_path is not None:
|
||||
viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output)
|
||||
stdio.printf("[run] 执行: %s\n", exe_path)
|
||||
r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
||||
if r is not None:
|
||||
stdio.printf("[run] 退出码: %d\n", r.returncode)
|
||||
else:
|
||||
if log is not None:
|
||||
log.error("编译管线失败", "pipeline")
|
||||
if br is not None and br.ErrorMsg is not None:
|
||||
stdio.printf("[FATAL] 编译管线失败: %s\n", br.ErrorMsg)
|
||||
sys.exit(1)
|
||||
else:
|
||||
if log is not None:
|
||||
log.error("malloc for IR buffer failed", "memhub")
|
||||
else:
|
||||
if log is not None:
|
||||
log.error("翻译失败", "translator")
|
||||
|
||||
argparse.release(args)
|
||||
if log is not None:
|
||||
log.success("TransPyV 完成")
|
||||
return 0
|
||||
Reference in New Issue
Block a user