fix(compiler): 支持多 includes 目录,修复 G4 g4node 未注册 SHA1

- Config.vp 解析 includes 数组全部元素为空格分隔 IncludesDirs(首元素仍存 IncludesDir 兼容单目录)

- IncludesScanner 逐目录递归扫描合并,FileEntry.IncDir 记录所属 includes 根目录

- StubMerger 存储新增 IncDir 并行数组(MAX_INC_DIR_LEN=512),容量 256→1024

- Phase2 预注册/3.5 按需编译改用逐条目 IncDir 拼接源路径(空串回退 includes_dir)

- HandlesImports import 未注册错误显示行内内容 + App 兄弟模块文件豁免

- 新增 TransPyV 自身 project.vpj
This commit is contained in:
TermiNexus committed 2026-08-08 10:31:44 +08:00
1 parent ea8bb0b3a4
commit 60493d6ae5
7 files changed
+257 -35

No files matched your search

+60 -8
View File
@@ -34,7 +34,8 @@ TargetTriple: str
TargetDataLayout: str
Sha1SliceLevel: t.CInt # SHA1 切片层数(目录分散等级)
StrictMode: t.CInt
IncludesDir: str # includes 目录路径(从 includes 数组首元素)
IncludesDir: str # includes 目录路径(从 includes 数组首元素,兼容单目录场景)
IncludesDirs: str # 全部 includes 目录(空格分隔,多 includes 目录支持)
def Load_project_config(path: str) -> int:
@@ -49,7 +50,7 @@ def Load_project_config(path: str) -> int:
global SourceDir, BuildDir, TempDir, OutputDir, ProjectName, ProjectVersion
global CompilerCmd, CompilerFlags, LinkerCmd, LinkerFlags, LinkerOutput
global TargetTriple, TargetDataLayout, Sha1SliceLevel, StrictMode
global IncludesDir
global IncludesDir, IncludesDirs
if path is None:
return 1
@@ -141,14 +142,33 @@ def Load_project_config(path: str) -> int:
if sm is not None and sm.is_bool():
StrictMode = 1 if sm.as_bool() else 0
# 读取 includes 数组(取首个元素作为 includes 目录)
# 读取 includes 数组(支持多目录:首元素存 IncludesDir,全部拼接存 IncludesDirs)
includes_val: JsonValue | t.CPtr = root.__getitem__("includes")
if includes_val is not None and includes_val.is_array():
arr_len: t.CSizeT = includes_val.__len__()
if arr_len > 0:
first_inc: JsonValue | t.CPtr = includes_val.get_item(0)
if first_inc is not None and first_inc.is_string():
IncludesDir = first_inc.as_string()
inc_buf: bytes = stdlib.malloc(2048)
if inc_buf is not None:
inc_buf[0] = '\0'
inc_pos: t.CSizeT = 0
for inc_i in range(arr_len):
inc_item: JsonValue | t.CPtr = includes_val.get_item(inc_i)
if inc_item is None or not inc_item.is_string():
continue
inc_str: str = inc_item.as_string()
inc_slen: t.CSizeT = string.strlen(inc_str)
if inc_i == 0:
IncludesDir = inc_str
# 拼接进 IncludesDirs(空格分隔)
if inc_pos + inc_slen + 1 < 2048:
if inc_pos > 0:
inc_buf[inc_pos] = ' '
inc_pos += 1
string.strcpy(inc_buf + inc_pos, inc_str)
inc_pos += inc_slen
inc_buf[inc_pos] = '\0'
IncludesDirs = inc_buf
if IncludesDir is None:
IncludesDir = inc_buf
return 0
@@ -367,7 +387,7 @@ def resolve_paths(project_dir: str) -> int:
Returns:
0 表示成功,非 0 表示失败
"""
global SourceDir, BuildDir, TempDir, OutputDir, IncludesDir
global SourceDir, BuildDir, TempDir, OutputDir, IncludesDir, IncludesDirs
if project_dir is None:
return 1
if _mbuddy is None:
@@ -390,6 +410,38 @@ def resolve_paths(project_dir: str) -> int:
OutputDir = output_buf
# includes 路径可能是 ../includes 形式,需要基于 project_dir 解析
# IncludesDir(首元素)与 IncludesDirs(全部,空格分隔)逐项规范化
if IncludesDirs is not None:
id_total: t.CSizeT = string.strlen(IncludesDirs)
id_out: str = _mbuddy.alloc(id_total * 3 + 64)
if id_out is not None:
id_out[0] = '\0'
id_pos: t.CSizeT = 0
id_i: t.CSizeT = 0
while id_i < id_total:
while id_i < id_total and IncludesDirs[id_i] == ' ':
id_i += 1
if id_i >= id_total:
break
id_start: t.CSizeT = id_i
while id_i < id_total and IncludesDirs[id_i] != ' ':
id_i += 1
seg_len: t.CSizeT = id_i - id_start
if seg_len > 0:
seg_buf: str = _mbuddy.alloc(seg_len + 1)
if seg_buf is not None:
string.strncpy(seg_buf, IncludesDirs + id_start, seg_len)
seg_buf[seg_len] = '\0'
joined: str = _join_path(seg_buf, project_dir)
if joined is not None:
jl: t.CSizeT = string.strlen(joined)
if id_pos > 0:
id_out[id_pos] = ' '
id_pos += 1
string.strcpy(id_out + id_pos, joined)
id_pos += jl
id_out[id_pos] = '\0'
IncludesDirs = id_out
if IncludesDir is not None:
IncludesDir = _join_path(IncludesDir, project_dir)
return 0
+75
View File
@@ -7,6 +7,7 @@ import stdlib
import viperlib
import stdio
import sys
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
@@ -507,6 +508,27 @@ def _report_import_error(node: ast.AST | t.CPtr, msg: str) -> None:
if file_name is None:
file_name = "<unknown>"
stdio.printf(' File "%s", line %d\n', file_name, lineno)
# 显示行内内容(读源文件第 lineno 行的实际代码,便于快速定位)
if lineno > 0 and file_name is not None:
f_err: fileio.File | t.CPtr = fileio.File(file_name, fileio.MODE.R)
if not f_err.closed:
line_buf_err: bytes = stdlib.malloc(512)
if line_buf_err is not None:
cur_ln: int = 0
while cur_ln < lineno:
r_err: LONG = f_err.readline(line_buf_err, 511)
if r_err <= 0:
break
cur_ln += 1
if cur_ln == lineno:
ll_err: t.CSizeT = string.strlen(line_buf_err)
while ll_err > 0 and (line_buf_err[ll_err - 1] == '\n' or line_buf_err[ll_err - 1] == '\r'):
ll_err -= 1
line_buf_err[ll_err] = '\0'
stdio.printf(" %s\n", line_buf_err)
break
stdlib.free(line_buf_err)
f_err.close()
stdio.printf("ImportError: %s\n", msg)
sys.exit(1)
@@ -522,6 +544,54 @@ def _report_import_error(node: ast.AST | t.CPtr, msg: str) -> None:
#
# t/c 是内部库,不参与 includes 扫描,豁免检查。
# ============================================================
def _is_local_module_file(mod_name: str) -> int:
"""当前文件同目录存在 {mod_name}.vp/.py → 项目内兄弟模块
多文件项目(如 Test/G4/App 的 caller1.vp import g4node)的兄弟模块
不在 includes 扫描存储器中(SHA1 在项目源文件列表),检查应豁免。
"""
cur: str = _g_current_file
if cur is None or mod_name is None:
return 0
cur_len: t.CSizeT = string.strlen(cur)
if cur_len == 0:
return 0
sep_pos: t.CSizeT = cur_len
while sep_pos > 0:
sep_pos -= 1
ch: t.CChar = cur[sep_pos]
if ch == '/' or ch == '\\':
sep_pos += 1
break
mod_len: t.CSizeT = string.strlen(mod_name)
path_len: t.CSizeT = sep_pos + mod_len + 5
path_buf: bytes = stdlib.malloc(path_len + 1)
if path_buf is None:
return 0
# .vp 文件
string.strncpy(path_buf, cur, sep_pos)
path_buf[sep_pos] = '\0'
string.strcat(path_buf, mod_name)
string.strcat(path_buf, ".vp")
fex: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
if not fex.closed:
fex.close()
stdlib.free(path_buf)
return 1
# .py 文件(Python 模块可能无 .vp)
string.strncpy(path_buf, cur, sep_pos)
path_buf[sep_pos] = '\0'
string.strcat(path_buf, mod_name)
string.strcat(path_buf, ".py")
fex2: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
if not fex2.closed:
fex2.close()
stdlib.free(path_buf)
return 1
stdlib.free(path_buf)
return 0
def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int:
"""导入时校验模块 SHA1 是否已注册,未注册则立即报错退出
@@ -539,6 +609,11 @@ def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int:
return 1
mod_sha1: str = StubMerger.LookupSha1ByModName(mod_name)
if mod_sha1 is None:
# App 兄弟模块豁免:当前文件同目录存在 {mod_name}.vp/.py
# (如 Test/G4/App/caller1.vp import g4node——同项目源文件,
# SHA1 在项目文件列表而非 includes 扫描存储器,不应报错)
if _is_local_module_file(mod_name) != 0:
return 1
err_buf: t.CChar | t.CPtr = stdlib.malloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
+42 -11
View File
@@ -27,7 +27,7 @@ _mbuddy: memhub.MemBuddy | t.CPtr
# 文件路径最大长度
MAX_PATH_LEN: t.CDefine = 512
# 单次扫描最大文件数
MAX_FILES: t.CDefine = 256
MAX_FILES: t.CDefine = 1024
# ============================================================
@@ -40,6 +40,7 @@ class FileEntry:
Sha1: str # SHA1 前16字符(16字节+null)
RelPath: str # 相对于 includes 根目录的路径
ModuleName: str # 模块名(如 "ast.parser")
IncDir: str # 所属 includes 根目录(多 includes 目录支持)
# ============================================================
@@ -83,8 +84,8 @@ def create_scan_result(pool: memhub.MemBuddy | t.CPtr) -> ScanResult | t.CPtr:
def add_file_entry(result: ScanResult | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
abs_path: str, rel_path: str,
sha1: str) -> int:
"""添加文件条目到扫描结果,返回 0 成功"""
sha1: str, inc_dir: str) -> int:
"""添加文件条目到扫描结果,返回 0 成功(inc_dir 为所属 includes 根目录)"""
if result is None or pool is None:
return 1
if result.Count >= result.Capacity:
@@ -127,6 +128,15 @@ def add_file_entry(result: ScanResult | t.CPtr,
# 复制模块名
entry.ModuleName = mod_buf
# 复制所属 includes 根目录(多 includes 目录支持,Phase2 拼路径用)
if inc_dir is not None:
inc_len: t.CSizeT = string.strlen(inc_dir)
inc_buf: str = stdlib.malloc(inc_len + 1)
if inc_buf is None:
return 1
string.strcpy(inc_buf, inc_dir)
entry.IncDir = inc_buf
result.Count += 1
return 0
@@ -193,8 +203,9 @@ def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr,
def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
root_dir: str,
rel_prefix: str,
result: ScanResult | t.CPtr) -> int:
"""递归扫描目录,收集 .vp/.py 文件"""
result: ScanResult | t.CPtr,
inc_dir: str) -> int:
"""递归扫描目录,收集 .vp/.py 文件(inc_dir 为所属 includes 根目录)"""
if pool is None or root_dir is None or result is None:
return 1
@@ -262,7 +273,7 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
if is_dir != 0:
# 递归扫描子目录
scan_directory_recursive(pool, full_path, rel_path, result)
scan_directory_recursive(pool, full_path, rel_path, result, inc_dir)
else:
# 检查是否为 .vp 或 .py 文件(.vp 为 Viper 源,.py 向后兼容)
is_py: int = 0
@@ -280,7 +291,7 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
# 计算 SHA1
sha1: str = compute_file_sha1(pool, full_path)
if sha1 is not None:
add_file_entry(result, pool, full_path, rel_path, sha1)
add_file_entry(result, pool, full_path, rel_path, sha1, inc_dir)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "扫描: %s -> %s", rel_path, sha1)
@@ -300,16 +311,36 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
# 扫描指定的 includes 目录,返回所有 .vp/.py 文件的路径和 SHA1。
# ============================================================
def scan_includes(pool: memhub.MemBuddy | t.CPtr,
includes_dir: str) -> ScanResult | t.CPtr:
"""扫描 includes 目录,返回所有 .vp/.py 文件的扫描结果"""
if pool is None or includes_dir is None:
includes_dirs: str) -> ScanResult | t.CPtr:
"""扫描 includes 目录(支持空格分隔的多目录),返回所有 .vp/.py 文件的扫描结果"""
if pool is None or includes_dirs is None:
return None
result: ScanResult | t.CPtr = create_scan_result(pool)
if result is None:
return None
scan_directory_recursive(pool, includes_dir, None, result)
# 解析空格分隔的多 includes 目录(如 "../../includes ./includes"),逐目录递归扫描合并
dirs_total: t.CSizeT = string.strlen(includes_dirs)
d_i: t.CSizeT = 0
while d_i < dirs_total:
while d_i < dirs_total and includes_dirs[d_i] == ' ':
d_i += 1
if d_i >= dirs_total:
break
d_start: t.CSizeT = d_i
while d_i < dirs_total and includes_dirs[d_i] != ' ':
d_i += 1
d_len: t.CSizeT = d_i - d_start
if d_len == 0:
continue
dir_buf: bytes = stdlib.malloc(d_len + 1)
if dir_buf is None:
continue
string.strncpy(dir_buf, includes_dirs + d_start, d_len)
dir_buf[d_len] = '\0'
scan_directory_recursive(pool, dir_buf, None, result, dir_buf)
stdlib.free(dir_buf)
return result
+16 -7
View File
@@ -281,7 +281,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
if store_count_inc_pre > 0:
store_sha1_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
store_rel_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
inc_dir_len_pre: t.CSizeT = string.strlen(includes_dir)
store_incdir_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreIncdirArrPtr()
deps_filled_pre: int = 0
PHASE_A_INC_MAX_PASSES: t.CInt = 3
# [修复] 记录预注册失败的 includes:多遍后仍失败 → 报错终止编译。
@@ -320,11 +320,16 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
inc_fail_flags[si_inc] = 0
continue
rel_len_pre: t.CSizeT = string.strlen(inc_rel_pre)
full_path_pre: bytes = stdlib.malloc(inc_dir_len_pre + rel_len_pre + 2)
# 所属 includes 根目录(多目录逐条取自 IncDir 数组,空串回退 includes_dir)
incdir_pre: str = store_incdir_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_INC_DIR_LEN
if incdir_pre is None or incdir_pre[0] == '\0':
incdir_pre = includes_dir
incdir_len_pre: t.CSizeT = string.strlen(incdir_pre)
full_path_pre: bytes = stdlib.malloc(incdir_len_pre + rel_len_pre + 2)
if full_path_pre is None:
continue
viperlib.snprintf(full_path_pre, inc_dir_len_pre + rel_len_pre + 2,
"%s/%s", includes_dir, inc_rel_pre)
viperlib.snprintf(full_path_pre, incdir_len_pre + rel_len_pre + 2,
"%s/%s", incdir_pre, inc_rel_pre)
pkg_inc_pre: str = HandlesImports.compute_package_from_relpath(mb, inc_rel_pre)
tr_inc_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(
mb, full_path_pre, inc_sha1_pre, pkg_inc_pre, 1)
@@ -652,6 +657,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
store_sha1_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
store_mod_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreModArrPtr()
store_rel_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
store_incdir_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreIncdirArrPtr()
for si_mi in range(store_count_mi):
# 获取当前条目的 SHA1 和 rel_path
@@ -680,9 +686,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
continue
# .obj 不存在,需要编译
# 构造源文件路径: {includes_dir}/{rel_path}
# 构造源文件路径: {所属 includes 根目录}/{rel_path}(多目录逐条取 IncDir,空串回退 includes_dir)
rel_path_len_mi: t.CSizeT = string.strlen(inc_rel_mi)
inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir)
incdir_mi: str = store_incdir_arr_mi + t.CSizeT(si_mi) * StubMerger.MAX_INC_DIR_LEN
if incdir_mi is None or incdir_mi[0] == '\0':
incdir_mi = includes_dir
inc_dir_len_mi: t.CSizeT = string.strlen(incdir_mi)
src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1)
if src_fp_mi is None:
stdlib.free(check_pat_mi)
@@ -690,7 +699,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(check_fd_mi)
continue
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1,
"%s/%s", includes_dir, inc_rel_mi)
"%s/%s", incdir_mi, inc_rel_mi)
# 检查是否为声明文件(只有 declare 没有实质 define)
# 判断方法: text.ll 中若有混淆函数 define(含 @")则为实现文件
+32 -6
View File
@@ -39,17 +39,18 @@ import lib.Projectrans.Config as Config
_mbuddy: memhub.MemBuddy | t.CPtr
# 最大 includes SHA1 数(用于过滤)
MAX_INCLUDES_SHA1: t.CDefine = 256
MAX_INCLUDES_SHA1: t.CDefine = 1024
# stub 读取缓冲区大小
STUB_READ_BUF_SIZE: t.CDefine = 1048576
# 最大 includes 条目数
MAX_INCLUDES: t.CDefine = 256
MAX_INCLUDES: t.CDefine = 1024
# 全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件)
# Phase1 扫描完成后填充,供所有函数使用
_sha1_store_arr: bytes # SHA1 数组(每个 17 字节,MAX_INCLUDES 个)
_sha1_store_mod: bytes # 模块名数组(每个 64 字节,MAX_INCLUDES 个)
_sha1_store_rel: bytes # 相对路径数组(每个 256 字节,MAX_INCLUDES 个)
_sha1_store_incdir: bytes # 所属 includes 根目录数组(每个 512 字节,MAX_INCLUDES 个,多 includes 支持)
_sha1_store_count: int # 条目数
# includes 依赖内存存储(不依赖 deps.txt 过程文件)
@@ -64,6 +65,8 @@ MAX_DEPS_STR_LEN: t.CDefine = 512
# rel_path 最大长度
MAX_REL_PATH_LEN: t.CDefine = 256
# includes 根目录最大长度(绝对路径,多 includes 支持)
MAX_INC_DIR_LEN: t.CDefine = 512
# ============================================================
@@ -345,7 +348,7 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
模块名通过 _PathToModuleName(includes/rel_path) 计算。
内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
"""
global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_count
global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_incdir, _sha1_store_count
if scan_result is None:
return -1
# 释放旧存储器
@@ -355,14 +358,18 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
stdlib.free(_sha1_store_mod)
if _sha1_store_rel is not None:
stdlib.free(_sha1_store_rel)
if _sha1_store_incdir is not None:
stdlib.free(_sha1_store_incdir)
_sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17)
_sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
_sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
if _sha1_store_arr is None or _sha1_store_mod is None or _sha1_store_rel is None:
_sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN)
if _sha1_store_arr is None or _sha1_store_mod is None or _sha1_store_rel is None or _sha1_store_incdir is None:
return -1
string.memset(_sha1_store_arr, 0, MAX_INCLUDES * 17)
string.memset(_sha1_store_mod, 0, MAX_INCLUDES * 64)
string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
string.memset(_sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN)
_sha1_store_count = 0
entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
for i in range(scan_result.Count):
@@ -398,6 +405,15 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
else:
string.strncpy(_sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1)
_sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0'
# 保存所属 includes 根目录(Phase2 预注册/按需编译拼路径用)
idx_inc: t.CSizeT = t.CSizeT(_sha1_store_count) * MAX_INC_DIR_LEN
if ent.IncDir is not None:
icd_len: t.CSizeT = string.strlen(ent.IncDir)
if icd_len < MAX_INC_DIR_LEN:
string.strcpy(_sha1_store_incdir + idx_inc, ent.IncDir)
else:
string.strncpy(_sha1_store_incdir + idx_inc, ent.IncDir, MAX_INC_DIR_LEN - 1)
_sha1_store_incdir[idx_inc + MAX_INC_DIR_LEN - 1] = '\0'
_sha1_store_count += 1
return _sha1_store_count
@@ -424,7 +440,7 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
# ============================================================
def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
"""追加条目到全局 SHA1 映射存储器(Phase2 用)"""
global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_count
global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_incdir, _sha1_store_count
if sha1 is None or rel_path is None:
return 1
# 存储器未初始化:自动初始化(Phase2 可能先于 Phase1 调用)
@@ -432,11 +448,13 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
_sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17)
_sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
_sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
if _sha1_store_arr is None or _sha1_store_mod is None or _sha1_store_rel is None:
_sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN)
if _sha1_store_arr is None or _sha1_store_mod is None or _sha1_store_rel is None or _sha1_store_incdir is None:
return 1
string.memset(_sha1_store_arr, 0, MAX_INCLUDES * 17)
string.memset(_sha1_store_mod, 0, MAX_INCLUDES * 64)
string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
string.memset(_sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN)
_sha1_store_count = 0
if _sha1_store_count >= MAX_INCLUDES:
return 1
@@ -474,6 +492,9 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
else:
string.strncpy(_sha1_store_rel + idx_r, rel_path, MAX_REL_PATH_LEN - 1)
_sha1_store_rel[idx_r + MAX_REL_PATH_LEN - 1] = '\0'
# App 源文件不属于任何 includes 目录:IncDir 留空(Phase2 回退 includes_dir 参数)
idx_inc_a: t.CSizeT = t.CSizeT(_sha1_store_count) * MAX_INC_DIR_LEN
_sha1_store_incdir[idx_inc_a] = '\0'
_sha1_store_count += 1
return 0
@@ -639,6 +660,11 @@ def GetSha1StoreRelArrPtr() -> bytes | t.CPtr:
return _sha1_store_rel
def GetSha1StoreIncdirArrPtr() -> bytes | t.CPtr:
"""返回所属 includes 根目录数组指针(每个条目 MAX_INC_DIR_LEN 字节,空串表示不属于任何 includes 目录)"""
return _sha1_store_incdir
# ============================================================
# GetSha1StoreArr - 获取全局存储器数组指针(直接遍历用)
#
+3 -3
View File
@@ -304,11 +304,11 @@ def main() -> int:
# === Phase1: 扫描 includes(按需翻译)===
# 对 includes 目录中每个 .vp/.py 文件,若 stub 不存在则翻译并分离 stub
if do_phase1 != 0 and Config.IncludesDir is not None:
if do_phase1 != 0 and Config.IncludesDirs is not None:
ph1_temp: str = Config.TempDir
if ph1_temp is None:
ph1_temp = "."
Phase1.RunPhase1(mb, Config.IncludesDir, ph1_temp, log)
Phase1.RunPhase1(mb, Config.IncludesDirs, ph1_temp, log)
# 如果仅 Phase1(不执行 Phase2),直接退出
if do_phase2 == 0:
if log is not None:
@@ -333,7 +333,7 @@ def main() -> int:
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)
mf_includes_bin, Config.IncludesDirs, do_phase1, do_phase2, log, args)
argparse.release(args)
if log is not None:
log.success("TransPyV 完成")
+29
View File
@@ -0,0 +1,29 @@
{
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
"name": "TransPyV",
"version": "1.0.0",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"compiler": {
"cmd": "llc",
"flags": ["-filetype=obj", "-relocation-model=pic"]
},
"linker": {
"cmd": "clang++",
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition", "-Wl,--stack,0x1000000"],
"output": "TransPyV.exe"
},
"includes": [
"../includes"
],
"target": {
"triple": "x86_64-pc-windows-gnu",
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
},
"options": {
"slice_level": 3,
"sha1_slice_level": 1,
"target": "llvm",
"strict_mode": true
}
}