增加 JIT REPL
This commit is contained in:
1 parent
9910e05760
commit
a5ceb3d4eb
56 files changed
+7621
-584
No files matched your search
@@ -115,7 +115,10 @@ def TranslateFileGetTrans(mb: rawptr[memhub.MemBuddy], file_path: str,
|
||||
pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE)
|
||||
if pyi_buf is not None:
|
||||
pyi_buf[0] = 0
|
||||
pyi_pos: sizet = StubConverter._GeneratePyiFromAst(mb, tree, None, pyi_buf, PYI_BUF_SIZE)
|
||||
# rel_path 传 file_path(本文件绝对路径):vpi 生成期间 fatal_error
|
||||
# 的报错归因需指向本源文件(Phase A 预注册/翻译时 file_path 已可用),
|
||||
# 且绝对路径可被 fatal_error 的 _read_source_line 直接打开打印源码行。
|
||||
pyi_pos: sizet = StubConverter._GeneratePyiFromAst(mb, tree, file_path, pyi_buf, PYI_BUF_SIZE)
|
||||
if pyi_pos > 0:
|
||||
# 写入 {sha1}.vpi 到 temp_dir(切片路径)
|
||||
td_len_vpi: sizet = len(temp_dir)
|
||||
@@ -709,6 +712,37 @@ def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: sizet)
|
||||
return out_pos
|
||||
|
||||
|
||||
def _append_host_export_implib(linker_flags: str, implib_path: str) -> str:
|
||||
"""宿主导出模式:为链接参数追加 `--out-implib=<绝对路径>`(REPL 片段导入宿主用)
|
||||
|
||||
触发条件 = linker_flags 显式含 "--export-all-symbols"(工程级开关,宿主的
|
||||
project.vpj 里声明)。此时 exe 会带导出表,REPL 片段 DLL 需要一份 import lib
|
||||
才能把 IR 里的跨模块引用(形如 `<16位hex>.<函数名>`,见 .text.ll 的
|
||||
`define i32 @"<sha1>.utf8_is_valid"`)解析到宿主的导出符号。
|
||||
|
||||
为什么路径由本层计算而不写进 project.vpj:Config 对 linker.flags 既不做
|
||||
%VAR% 展开、也不按 project_dir 解析(Config.vpj:180-230 的 _join_flags_array
|
||||
只做拼接;:570-632 只重写 -T 后的脚本路径;env 展开只发生在 static_libs/
|
||||
dynamic_libs/includes/build_dir 等字段),而 out-implib 的值是相对
|
||||
clang 进程 cwd 解析的 ⇒ 只有本层能从 output_dir + linker_output 算出绝对路径。
|
||||
|
||||
未开启工程的 linker_flags 不含该标志 ⇒ 原样返回,链接命令逐字节不变。
|
||||
"""
|
||||
if linker_flags is None or implib_path is None:
|
||||
return linker_flags
|
||||
if string.strstr(linker_flags, "--export-all-symbols") is None:
|
||||
return linker_flags
|
||||
extra: sizet = string.strlen(" -Wl,--out-implib=") + string.strlen(implib_path) + 1
|
||||
buf: str = _mbuddy.alloc(string.strlen(linker_flags) + extra)
|
||||
if buf is None:
|
||||
VLogger.warning("宿主导出:import lib 参数缓冲分配失败(片段将无法导入宿主符号)", "link")
|
||||
return linker_flags
|
||||
viperlib.snprintf(buf, string.strlen(linker_flags) + extra,
|
||||
"%s -Wl,--out-implib=%s", linker_flags, implib_path)
|
||||
VLogger.info(f"宿主导出:产出 import lib {implib_path}", "link")
|
||||
return buf
|
||||
|
||||
|
||||
def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_flags: str, linker_output: str,
|
||||
includes_binary_dir: str, linker_static_libs: str = None, linker_dynamic_libs: str = None) -> int:
|
||||
"""调用 clang++ 链接 .obj 为 .exe
|
||||
@@ -734,6 +768,16 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
if obj_path is None:
|
||||
return 1
|
||||
|
||||
# 宿主 exe 导出(工程 linker.flags 含 --export-all-symbols 时)同步产出 import lib:
|
||||
# {output_dir}/{linker_output}.dll.a —— REPL 片段链接时把它加进命令行即可导入
|
||||
# 宿主(同一进程/同一份 includes 代码与数据)。未开启的工程不受影响。
|
||||
if linker_output is not None:
|
||||
implib_len: sizet = string.strlen(output_dir) + string.strlen(linker_output) + 8
|
||||
implib_path: str = _mbuddy.alloc(implib_len)
|
||||
if implib_path is not None:
|
||||
viperlib.snprintf(implib_path, implib_len, "%s/%s.dll.a", output_dir, linker_output)
|
||||
linker_flags = _append_host_export_implib(linker_flags, implib_path)
|
||||
|
||||
# 收集 includes.binary 的 .obj 文件路径
|
||||
EXTRA_BUF_SIZE: sizet = 32768
|
||||
extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE)
|
||||
@@ -988,6 +1032,13 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: sizet,
|
||||
# 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags
|
||||
# ASan 运行库同样不再由 TPV 注入(在 link_obj_to_exe 里已有说明):
|
||||
# 由 project.vpj 声明,--asan 下由 main.vp 校验。
|
||||
# 宿主导出:linker_output 是完整输出路径 ⇒ import lib 取名 <linker_output>.dll.a
|
||||
if linker_output is not None:
|
||||
implib_len2: sizet = string.strlen(linker_output) + 8
|
||||
implib_path2: str = _mbuddy.alloc(implib_len2)
|
||||
if implib_path2 is not None:
|
||||
viperlib.snprintf(implib_path2, implib_len2, "%s.dll.a", linker_output)
|
||||
linker_flags = _append_host_export_implib(linker_flags, implib_path2)
|
||||
use_flags: str = linker_flags
|
||||
static_libs2: str = linker_static_libs
|
||||
if static_libs2 is None:
|
||||
|
||||
@@ -1007,7 +1007,7 @@ def RunPhase1(mb: rawptr[memhub.MemBuddy], includes_dir: str, temp_dir: str,
|
||||
pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
|
||||
if pyi_buf is not None:
|
||||
pyi_pos: sizet = StubConverter._GeneratePyiFromAst(
|
||||
mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE)
|
||||
mb, tree, entry.Path, pyi_buf, Phase1.PYI_BUF_SIZE)
|
||||
if pyi_pos > 0:
|
||||
pf_1b: rawptr[fileio.File] = fileio.File(vpi_path_1b, fileio.MODE.W)
|
||||
if not pf_1b.closed:
|
||||
|
||||
@@ -133,7 +133,7 @@ def _ScanClassInheritance(mb: rawptr[memhub.MemBuddy],
|
||||
continue
|
||||
|
||||
# 遍历 AST 顶层节点,收集 ClassDef
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is not None:
|
||||
cn: sizet = len(ch)
|
||||
for ci in range(cn):
|
||||
@@ -305,7 +305,7 @@ def _PreRegisterAllGenericTemplates(mb: rawptr[memhub.MemBuddy],
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||||
ch_pg: rawptr[list[rawptr[ast.AST]]] = tree_pg.children
|
||||
ch_pg: list[ast.AST*]* = tree_pg.children
|
||||
if ch_pg is not None:
|
||||
cn_pg: sizet = len(ch_pg)
|
||||
for ci_pg in range(cn_pg):
|
||||
@@ -405,13 +405,13 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
elif k_s == ast.ASTKind.Call:
|
||||
cl_s2: rawptr[ast.Call] = rawptr[ast.Call](node)
|
||||
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box, depth + 1)
|
||||
cl_args_s: rawptr[list[rawptr[ast.AST]]] = cl_s2.args
|
||||
cl_args_s: list[ast.AST*]* = cl_s2.args
|
||||
if cl_args_s is not None:
|
||||
na_s: sizet = len(cl_args_s)
|
||||
i_a2: sizet
|
||||
for i_a2 in range(na_s):
|
||||
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box, depth + 1)
|
||||
cl_kws_s: rawptr[list[rawptr[ast.AST]]] = cl_s2.keywords
|
||||
cl_kws_s: list[ast.AST*]* = cl_s2.keywords
|
||||
if cl_kws_s is not None:
|
||||
nk_s: sizet = len(cl_kws_s)
|
||||
i_k2: sizet
|
||||
@@ -422,7 +422,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
elif k_s == ast.ASTKind.Assign:
|
||||
asn_s: rawptr[ast.Assign] = rawptr[ast.Assign](node)
|
||||
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
tgts_s: rawptr[list[rawptr[ast.AST]]] = asn_s.targets
|
||||
tgts_s: list[ast.AST*]* = asn_s.targets
|
||||
if tgts_s is not None:
|
||||
nt_s: sizet = len(tgts_s)
|
||||
i_t2: sizet
|
||||
@@ -437,7 +437,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box, depth + 1)
|
||||
fn_args_s: rawptr[ast.Arguments] = rawptr[ast.Arguments](fn_s.args)
|
||||
if fn_args_s is not None:
|
||||
fa_s: rawptr[list[rawptr[ast.AST]]] = fn_args_s.args
|
||||
fa_s: list[ast.AST*]* = fn_args_s.args
|
||||
if fa_s is not None:
|
||||
nf_s: sizet = len(fa_s)
|
||||
i_f2: sizet
|
||||
@@ -447,7 +447,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.ClassDef:
|
||||
cd_s: rawptr[ast.ClassDef] = rawptr[ast.ClassDef](node)
|
||||
bases_s: rawptr[list[rawptr[ast.AST]]] = cd_s.bases
|
||||
bases_s: list[ast.AST*]* = cd_s.bases
|
||||
if bases_s is not None:
|
||||
nb_s: sizet = len(bases_s)
|
||||
i_b2: sizet
|
||||
@@ -458,7 +458,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Tuple:
|
||||
tu_s: rawptr[ast.Tuple] = rawptr[ast.Tuple](node)
|
||||
elts_s: rawptr[list[rawptr[ast.AST]]] = tu_s.elts
|
||||
elts_s: list[ast.AST*]* = tu_s.elts
|
||||
if elts_s is not None:
|
||||
ne_s: sizet = len(elts_s)
|
||||
i_e2: sizet
|
||||
@@ -476,7 +476,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
elif k_s == ast.ASTKind.Compare:
|
||||
cp_s: rawptr[ast.Compare] = rawptr[ast.Compare](node)
|
||||
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box, depth + 1)
|
||||
cps_s: rawptr[list[rawptr[ast.AST]]] = cp_s.comparators
|
||||
cps_s: list[ast.AST*]* = cp_s.comparators
|
||||
if cps_s is not None:
|
||||
nc_s: sizet = len(cps_s)
|
||||
i_c2: sizet
|
||||
@@ -484,7 +484,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.BoolOp:
|
||||
bo_s: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
|
||||
bvs_s: rawptr[list[rawptr[ast.AST]]] = bo_s.values
|
||||
bvs_s: list[ast.AST*]* = bo_s.values
|
||||
if bvs_s is not None:
|
||||
nv_s: sizet = len(bvs_s)
|
||||
i_v2: sizet
|
||||
@@ -498,7 +498,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
# need_dict_box[0] = 1
|
||||
# 递归语句块子节点
|
||||
if node.children is not None:
|
||||
ch_s: rawptr[list[rawptr[ast.AST]]] = node.children
|
||||
ch_s: list[ast.AST*]* = node.children
|
||||
n_s: sizet = len(ch_s)
|
||||
ci_s: sizet
|
||||
for ci_s in range(n_s):
|
||||
|
||||
@@ -304,7 +304,7 @@ def _PreRegisterAppGenericTemplates(mb: rawptr[memhub.MemBuddy],
|
||||
stdlib.free(src_buf_pa)
|
||||
continue
|
||||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||||
ch_pa: rawptr[list[rawptr[ast.AST]]] = tree_pa.children
|
||||
ch_pa: list[ast.AST*]* = tree_pa.children
|
||||
if ch_pa is not None:
|
||||
cn_pa: sizet = len(ch_pa)
|
||||
for ci_pa in range(cn_pa):
|
||||
@@ -765,7 +765,8 @@ def RunMultiFileProject(mb: rawptr[memhub.MemBuddy],
|
||||
continue
|
||||
stdlib.free(vpi_path_vp2)
|
||||
# 读取源文件 → 解析 AST → 生成 vpi
|
||||
# (rel_path 传 None:与 TranslateFileGetTrans 后续覆盖写的内容一致)
|
||||
# (rel_path 传 ent_vp2.Path:vpi 内容不依赖它——与 TranslateFileGetTrans
|
||||
# 后续覆盖写的内容一致;此处仅用于 fatal_error 的报错归因,指向本源文件)
|
||||
f_vp2: rawptr[fileio.File] = fileio.File(ent_vp2.Path, fileio.MODE.R)
|
||||
if f_vp2.closed:
|
||||
vpi_failed_p2 += 1
|
||||
@@ -812,7 +813,7 @@ def RunMultiFileProject(mb: rawptr[memhub.MemBuddy],
|
||||
pyi_buf_vp2: bytes = stdlib.malloc(PYI_BUF_SIZE_P2)
|
||||
if pyi_buf_vp2 is not None:
|
||||
pyi_pos_vp2: sizet = StubConverter._GeneratePyiFromAst(
|
||||
mb, tree_vp2, None, pyi_buf_vp2, PYI_BUF_SIZE_P2)
|
||||
mb, tree_vp2, ent_vp2.Path, pyi_buf_vp2, PYI_BUF_SIZE_P2)
|
||||
if pyi_pos_vp2 > 0:
|
||||
pyi_path_vp2: str = StubMergerCollect._sliced_path(temp_dir, td_len_vpa, ent_vp2.Sha1, "vpi")
|
||||
if pyi_path_vp2 is not None:
|
||||
|
||||
Reference in new issue
Block a user