125 lines
5.6 KiB
Plaintext
125 lines
5.6 KiB
Plaintext
from stdint import *
|
|
import memhub
|
|
import string
|
|
import stdlib
|
|
import mlirlite
|
|
import win32.win32file as win32file
|
|
import win32.win32base as win32base
|
|
import win32.fileio as fileio
|
|
import viperlib
|
|
import sys
|
|
import ast
|
|
import lib.core.VLogger as VLogger
|
|
import lib.core.IncludesScanner as IncludesScanner
|
|
import lib.core.Gen.Translator as HandlesTranslator
|
|
import lib.Phase.BuildPipeline as BuildPipeline
|
|
import lib.Stub.StubGen.VpiReader as VpiReader
|
|
import lib.Projectrans.Utils as Utils
|
|
import lib.Projectrans.Config as Config
|
|
|
|
|
|
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
|
import lib.Stub.StubMerger.StubMergerTopo as StubMergerTopo
|
|
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
|
|
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
|
import lib.Stub.StubMerger as StubMerger
|
|
|
|
# StubMergerCollect - slice-path construction and stub-file SHA1 collection.
|
|
# Functions live in this module; cross-module globals are accessed via StubMerger._xxx.
|
|
|
|
# _sliced_path - build a slice path (stdlib.malloc; caller frees; creates subdir when level>0).
|
|
# Shards by Config.Sha1SliceLevel into SHA1-prefix subdirs; returns the full path or None on failure.
|
|
def _sliced_path(temp_dir: str, td_len: sizet, sha1: str, ext: str) -> str:
|
|
"""Build a SHA1-sliced path (stdlib.malloc; caller frees; creates the subdir)."""
|
|
if temp_dir is None or sha1 is None or ext is None: return None
|
|
sha1_len: sizet = string.strlen(sha1)
|
|
ext_len: sizet = string.strlen(ext)
|
|
|
|
# Subdir prefix: reuse Config.slice_subdir (the authoritative SHA1 slice impl; mbuddy-allocated, no free)
|
|
subdir_buf: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel)
|
|
sub_len: sizet = 0
|
|
if subdir_buf is not None:
|
|
sub_len = string.strlen(subdir_buf)
|
|
|
|
# Ensure subdir {temp_dir}/{subdir} exists.
|
|
# Otherwise fileio.File(MODE.W) fails silently (file.closed==True) and the reader returns 0.
|
|
dir_path_len: sizet = td_len + sub_len + 2
|
|
dir_path: bytes = stdlib.malloc(dir_path_len)
|
|
if dir_path is not None:
|
|
viperlib.snprintf(dir_path, dir_path_len, "%s/%s", temp_dir, subdir_buf)
|
|
BuildPipeline.ensure_dir(dir_path)
|
|
stdlib.free(dir_path)
|
|
|
|
# Build the full path
|
|
path: str = None
|
|
path_len: sizet = 0
|
|
if sub_len > 0:
|
|
path_len = td_len + sub_len + sha1_len + ext_len + 4
|
|
path = stdlib.malloc(path_len)
|
|
if path is not None: viperlib.snprintf(path, path_len, "%s/%s/%s.%s", temp_dir, subdir_buf, sha1, ext)
|
|
else:
|
|
path_len = td_len + sha1_len + ext_len + 3
|
|
path = stdlib.malloc(path_len)
|
|
if path is not None: viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext)
|
|
|
|
return path
|
|
|
|
# _load_includes_sha1_set - collect includes SHA1 from the global in-memory store.
|
|
# Source is PopulateSha1MapStore (not _sha1_map.txt); filters stubs to avoid linking ViperC's own lib/* stubs.
|
|
def _load_includes_sha1_set(pool: memhub.MemBuddy*, temp_dir: str, sha1_set: str) -> int:
|
|
"""Copy includes SHA1s from the global store into sha1_set; returns the count, -1 on error."""
|
|
if sha1_set is None: return -1
|
|
if StubMerger._sha1_store_arr is None: return -1
|
|
count: int = 0
|
|
for i in range(int(StubMerger._sha1_store_count)):
|
|
if count >= StubMerger.MAX_INCLUDES_SHA1: break
|
|
idx: sizet = sizet(i) * 17
|
|
string.strcpy(sha1_set + sizet(count) * 17, StubMerger._sha1_store_arr + idx)
|
|
count += 1
|
|
return count
|
|
# _is_in_sha1_set - check whether a SHA1 is in the set.
|
|
def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int:
|
|
"""Whether sha1 is present in the set."""
|
|
if sha1 is None or sha1_set is None: return 0
|
|
for i in range(int(set_count)):
|
|
if string.strcmp(sha1_set + i * 17, sha1) == 0: return 1
|
|
return 0
|
|
# WriteIncludesSha1Map - write includes scan results to _sha1_map.txt (human-readable debug output only).
|
|
# Internally the in-memory store filled by PopulateSha1MapStore is used; returns 0 on success, non-zero on failure.
|
|
def WriteIncludesSha1Map(mb: memhub.MemBuddy*, temp_dir: str, scan_result: IncludesScanner.ScanResult*, filter_set: str, filter_count: int) -> int:
|
|
"""Write the includes scan result to _sha1_map.txt (human-readable debug output)."""
|
|
if temp_dir is None or scan_result is None: return 1
|
|
|
|
# Build the path temp_dir/_sha1_map.txt
|
|
dir_len: sizet = string.strlen(temp_dir)
|
|
map_path: bytes = stdlib.malloc(dir_len + 32)
|
|
if map_path is None: return 1
|
|
viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir)
|
|
|
|
# Open the file for writing (CREATE_ALWAYS)
|
|
f: fileio.File* = fileio.File(map_path, fileio.MODE.W)
|
|
if f.closed: return 1
|
|
|
|
# Write each include entry: {sha1}:includes/{rel_path}\n
|
|
entry_size_w: sizet = IncludesScanner.FileEntry.__sizeof__()
|
|
line_buf: bytes = stdlib.malloc(512)
|
|
if line_buf is None:
|
|
f.close()
|
|
return 1
|
|
|
|
written_count: int = 0
|
|
for i in range(int(scan_result.Count)):
|
|
ea_w: uint64 = uint64(scan_result.Entries) + i * entry_size_w
|
|
ent_w: IncludesScanner.FileEntry* = (IncludesScanner.FileEntry*)(ea_w)
|
|
if ent_w is None or ent_w.Sha1 is None or ent_w.RelPath is None: continue
|
|
# When a filter set is provided, write only its entries
|
|
if filter_set is not None and filter_count > 0:
|
|
if _is_in_sha1_set(ent_w.Sha1, filter_set, filter_count) == 0: continue
|
|
viperlib.snprintf(line_buf, 512, "%s:includes/%s\n", ent_w.Sha1, ent_w.RelPath)
|
|
line_len_w: sizet = string.strlen(line_buf)
|
|
f.write(line_buf, line_len_w)
|
|
written_count += 1
|
|
|
|
f.close()
|
|
return 0
|