Compare commits
33 Commits
0b50c31aa8
...
v1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
043359fe66 | ||
|
|
c55f38ef1c | ||
|
|
ae2c90160e | ||
|
|
4de53090a1 | ||
|
|
742c4e9e1b | ||
|
|
369cfa808c | ||
|
|
c32dc161f8 | ||
|
|
abfc507e4e | ||
|
|
cb496bca0f | ||
|
|
7b720cbdf4 | ||
|
|
6428e523df | ||
|
|
c738acd871 | ||
|
|
05bde87c38 | ||
|
|
02f3124224 | ||
|
|
21082a38e0 | ||
|
|
42ac3eb65d | ||
|
|
69c0bf1574 | ||
|
|
4f949e9854 | ||
|
|
0d54031dd5 | ||
|
|
e4fcfd11d7 | ||
|
|
d3f1e824fa | ||
|
|
ad7b9126b7 | ||
|
|
f271b2e82c | ||
|
|
a3850c2c8a | ||
|
|
0d59f88444 | ||
|
|
c44216a450 | ||
|
|
07e42c774a | ||
|
|
a95a1535a9 | ||
|
|
858e7de57d | ||
|
|
cd6645df98 | ||
|
|
3343428796 | ||
|
|
f881132fa8 | ||
|
|
4962276760 |
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/.out
|
||||||
|
/Src/__pycache__
|
||||||
|
/build/__pycache__
|
||||||
|
/build_temp
|
||||||
|
/DebugVarEdit_GUI.build
|
||||||
|
/DebugVarEdit_GUI.dist
|
||||||
|
/DebugVarEdit_GUI.onefile-build
|
||||||
Binary file not shown.
@@ -1,732 +0,0 @@
|
|||||||
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build scanVars.py
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import argparse
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
# === Словарь соответствия типов XML → DebugVarType_t ===
|
|
||||||
type_map = dict([
|
|
||||||
*[(k, 'pt_int8') for k in ('signed char', 'char')],
|
|
||||||
*[(k, 'pt_int16') for k in ('int', 'int16', 'short')],
|
|
||||||
*[(k, 'pt_int32') for k in ('long', 'int32', '_iqx')],
|
|
||||||
*[(k, 'pt_int64') for k in ('long long', 'int64')],
|
|
||||||
|
|
||||||
*[(k, 'pt_uint8') for k in ('unsigned char',)],
|
|
||||||
*[(k, 'pt_uint16') for k in ('unsigned int', 'unsigned short', 'Uint16')],
|
|
||||||
*[(k, 'pt_uint32') for k in ('unsigned long', 'Uint32')],
|
|
||||||
*[(k, 'pt_uint64') for k in ('unsigned long long', 'Uint64')],
|
|
||||||
|
|
||||||
*[(k, 'pt_ptr_int8') for k in ('signed char*',)],
|
|
||||||
*[(k, 'pt_ptr_int16') for k in ('int*', 'short*')],
|
|
||||||
*[(k, 'pt_ptr_int32') for k in ('long*',)],
|
|
||||||
*[(k, 'pt_ptr_uint8') for k in ('unsigned char*',)],
|
|
||||||
*[(k, 'pt_ptr_uint16') for k in ('unsigned int*', 'unsigned short*')],
|
|
||||||
*[(k, 'pt_ptr_uint32') for k in ('unsigned long*',)],
|
|
||||||
('unsigned long long*', 'pt_int64'),
|
|
||||||
|
|
||||||
*[(k, 'pt_arr_int8') for k in ('signed char[]',)],
|
|
||||||
*[(k, 'pt_arr_int16') for k in ('int[]', 'short[]')],
|
|
||||||
*[(k, 'pt_arr_int32') for k in ('long[]',)],
|
|
||||||
*[(k, 'pt_arr_uint8') for k in ('unsigned char[]',)],
|
|
||||||
*[(k, 'pt_arr_uint16') for k in ('unsigned int[]', 'unsigned short[]')],
|
|
||||||
*[(k, 'pt_arr_uint32') for k in ('unsigned long[]',)],
|
|
||||||
|
|
||||||
*[(k, 'pt_float') for k in ('float', 'float32')],
|
|
||||||
|
|
||||||
('struct', 'pt_struct'),
|
|
||||||
('union', 'pt_union'),
|
|
||||||
])
|
|
||||||
|
|
||||||
def parse_makefile(makefile_path):
|
|
||||||
makefile_dir = os.path.dirname(makefile_path)
|
|
||||||
project_root = os.path.dirname(makefile_dir) # поднялись из Debug
|
|
||||||
|
|
||||||
with open(makefile_path, 'r', encoding='utf-8') as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
|
|
||||||
objs_lines = []
|
|
||||||
collecting = False
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
stripped = line.strip()
|
|
||||||
if stripped.startswith("ORDERED_OBJS") and "+=" in stripped:
|
|
||||||
parts = stripped.split("\\")
|
|
||||||
first_part = parts[0]
|
|
||||||
idx = first_part.find("+=")
|
|
||||||
tail = first_part[idx+2:].strip()
|
|
||||||
if tail:
|
|
||||||
objs_lines.append(tail)
|
|
||||||
collecting = True
|
|
||||||
if len(parts) > 1:
|
|
||||||
for p in parts[1:]:
|
|
||||||
p = p.strip()
|
|
||||||
if p:
|
|
||||||
objs_lines.append(p)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if collecting:
|
|
||||||
if stripped.endswith("\\"):
|
|
||||||
objs_lines.append(stripped[:-1].strip())
|
|
||||||
else:
|
|
||||||
objs_lines.append(stripped)
|
|
||||||
collecting = False
|
|
||||||
|
|
||||||
objs_str = ' '.join(objs_lines)
|
|
||||||
|
|
||||||
objs_str = re.sub(r"\$\([^)]+\)", "", objs_str)
|
|
||||||
|
|
||||||
objs = []
|
|
||||||
for part in objs_str.split():
|
|
||||||
part = part.strip()
|
|
||||||
if part.startswith('"') and part.endswith('"'):
|
|
||||||
part = part[1:-1]
|
|
||||||
if part:
|
|
||||||
objs.append(part)
|
|
||||||
|
|
||||||
c_files = []
|
|
||||||
include_dirs = set()
|
|
||||||
|
|
||||||
for obj_path in objs:
|
|
||||||
if "DebugTools" in obj_path:
|
|
||||||
continue
|
|
||||||
if "v120" in obj_path:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if obj_path.startswith("Debug\\") or obj_path.startswith("Debug/"):
|
|
||||||
rel_path = obj_path.replace("Debug\\", "Src\\").replace("Debug/", "Src/")
|
|
||||||
else:
|
|
||||||
rel_path = obj_path
|
|
||||||
|
|
||||||
abs_path = os.path.normpath(os.path.join(project_root, rel_path))
|
|
||||||
|
|
||||||
root, ext = os.path.splitext(abs_path)
|
|
||||||
if ext.lower() == ".obj":
|
|
||||||
c_path = root + ".c"
|
|
||||||
else:
|
|
||||||
c_path = abs_path
|
|
||||||
|
|
||||||
# Сохраняем только .c файлы
|
|
||||||
if c_path.lower().endswith(".c"):
|
|
||||||
c_files.append(c_path)
|
|
||||||
dir_path = os.path.dirname(c_path)
|
|
||||||
if dir_path and "DebugTools" not in dir_path:
|
|
||||||
include_dirs.add(dir_path)
|
|
||||||
|
|
||||||
return c_files, sorted(include_dirs)
|
|
||||||
|
|
||||||
# Шаблон для поиска глобальных переменных
|
|
||||||
# Пример: int varname;
|
|
||||||
# Пропускаем строки с static и функции
|
|
||||||
VAR_PATTERN = re.compile(
|
|
||||||
r'^\s*(?!static)(\w[\w\s\*]+)\s+(\w+)\s*(=\s*[^;]+)?\s*;',
|
|
||||||
re.MULTILINE)
|
|
||||||
EXTERN_PATTERN = re.compile(
|
|
||||||
r'^\s*extern\s+[\w\s\*]+\s+(\w+)\s*;',
|
|
||||||
re.MULTILINE)
|
|
||||||
|
|
||||||
|
|
||||||
TYPEDEF_PATTERN = re.compile(
|
|
||||||
r'typedef\s+(struct|union)?\s*(\w+)?\s*{[^}]*}\s*(\w+)\s*;', re.DOTALL)
|
|
||||||
|
|
||||||
TYPEDEF_SIMPLE_PATTERN = re.compile(
|
|
||||||
r'typedef\s+(.+?)\s+(\w+)\s*;', re.DOTALL)
|
|
||||||
|
|
||||||
def map_type_to_pt(typename, varname):
|
|
||||||
typename = typename.strip()
|
|
||||||
|
|
||||||
# Убираем const и volatile, где бы они ни были (например, "const volatile int")
|
|
||||||
for qualifier in ('const', 'volatile'):
|
|
||||||
typename = typename.replace(qualifier, '')
|
|
||||||
|
|
||||||
typename = typename.strip() # снова убрать лишние пробелы после удаления
|
|
||||||
|
|
||||||
# Раскрутка через typedef
|
|
||||||
resolved_type = typedef_aliases.get(typename, typename)
|
|
||||||
|
|
||||||
# Прямая проверка
|
|
||||||
if resolved_type in type_map:
|
|
||||||
return type_map[resolved_type]
|
|
||||||
|
|
||||||
if resolved_type.startswith('struct'):
|
|
||||||
return type_map['struct']
|
|
||||||
if resolved_type.startswith('union'):
|
|
||||||
return type_map['union']
|
|
||||||
|
|
||||||
if '_iq' in resolved_type and '_iqx' in type_map:
|
|
||||||
return type_map['_iqx']
|
|
||||||
|
|
||||||
return 'pt_unknown'
|
|
||||||
|
|
||||||
def get_iq_define(vtype):
|
|
||||||
if '_iq' in vtype:
|
|
||||||
# Преобразуем _iqXX в t_iqXX
|
|
||||||
return 't' + vtype[vtype.index('_iq'):]
|
|
||||||
else:
|
|
||||||
return 't_iq_none'
|
|
||||||
|
|
||||||
def get_files_by_ext(roots, exts):
|
|
||||||
files = []
|
|
||||||
for root in roots:
|
|
||||||
for dirpath, _, filenames in os.walk(root):
|
|
||||||
for f in filenames:
|
|
||||||
if any(f.endswith(e) for e in exts):
|
|
||||||
files.append(os.path.join(dirpath, f))
|
|
||||||
return files
|
|
||||||
|
|
||||||
def read_file_try_encodings(filepath):
|
|
||||||
for enc in ['utf-8', 'cp1251']:
|
|
||||||
try:
|
|
||||||
with open(filepath, 'r', encoding=enc) as f:
|
|
||||||
content = f.read()
|
|
||||||
content = strip_single_line_comments(content) # <=== ВАЖНО
|
|
||||||
return content, enc
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
continue
|
|
||||||
raise UnicodeDecodeError(f"Не удалось прочитать файл {filepath} с кодировками utf-8 и cp1251")
|
|
||||||
|
|
||||||
FUNC_PATTERN = re.compile(
|
|
||||||
r'\w[\w\s\*\(\),]*\([^;{)]*\)\s*\{(?:[^{}]*|\{[^}]*\})*?\}', re.DOTALL)
|
|
||||||
|
|
||||||
def strip_single_line_comments(code):
|
|
||||||
# Удалим // ... до конца строки
|
|
||||||
return re.sub(r'//.*?$', '', code, flags=re.MULTILINE)
|
|
||||||
|
|
||||||
def remove_function_bodies(code):
|
|
||||||
|
|
||||||
result = []
|
|
||||||
i = 0
|
|
||||||
length = len(code)
|
|
||||||
while i < length:
|
|
||||||
match = re.search(r'\b[\w\s\*\(\),]*\([^;{}]*\)\s*\{', code[i:])
|
|
||||||
if not match:
|
|
||||||
result.append(code[i:])
|
|
||||||
break
|
|
||||||
|
|
||||||
start = i + match.start()
|
|
||||||
brace_start = i + match.end() - 1
|
|
||||||
result.append(code[i:start]) # Добавляем всё до функции
|
|
||||||
|
|
||||||
# Ищем конец функции по уровню вложенности скобок
|
|
||||||
brace_level = 1
|
|
||||||
j = brace_start + 1
|
|
||||||
in_string = False
|
|
||||||
while j < length and brace_level > 0:
|
|
||||||
char = code[j]
|
|
||||||
|
|
||||||
if char == '"' or char == "'":
|
|
||||||
quote = char
|
|
||||||
j += 1
|
|
||||||
while j < length and code[j] != quote:
|
|
||||||
if code[j] == '\\':
|
|
||||||
j += 2
|
|
||||||
else:
|
|
||||||
j += 1
|
|
||||||
elif code[j] == '{':
|
|
||||||
brace_level += 1
|
|
||||||
elif code[j] == '}':
|
|
||||||
brace_level -= 1
|
|
||||||
j += 1
|
|
||||||
|
|
||||||
# Заменяем тело функции пробелами той же длины
|
|
||||||
result.append(' ' * (j - start))
|
|
||||||
i = j
|
|
||||||
|
|
||||||
return ''.join(result)
|
|
||||||
|
|
||||||
def extract_struct_definitions_from_file(filepath):
|
|
||||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Удаляем комментарии
|
|
||||||
content = re.sub(r'//.*', '', content)
|
|
||||||
content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
|
|
||||||
|
|
||||||
type_definitions = {}
|
|
||||||
anonymous_counter = [0]
|
|
||||||
|
|
||||||
def split_fields(body):
|
|
||||||
"""
|
|
||||||
Разбивает тело struct/union на поля с учётом вложенных { }.
|
|
||||||
Возвращает список строк - полей (без ;).
|
|
||||||
"""
|
|
||||||
fields = []
|
|
||||||
start = 0
|
|
||||||
brace_level = 0
|
|
||||||
for i, ch in enumerate(body):
|
|
||||||
if ch == '{':
|
|
||||||
brace_level += 1
|
|
||||||
elif ch == '}':
|
|
||||||
brace_level -= 1
|
|
||||||
elif ch == ';' and brace_level == 0:
|
|
||||||
fields.append(body[start:i].strip())
|
|
||||||
start = i + 1
|
|
||||||
# если что-то осталось после последнего ;
|
|
||||||
tail = body[start:].strip()
|
|
||||||
if tail:
|
|
||||||
fields.append(tail)
|
|
||||||
return fields
|
|
||||||
|
|
||||||
def parse_fields(body):
|
|
||||||
fields = {}
|
|
||||||
body = body.strip('{} \n\t')
|
|
||||||
field_strings = split_fields(body)
|
|
||||||
for field_str in field_strings:
|
|
||||||
if field_str.startswith(('struct ', 'union ')):
|
|
||||||
# Вложенный struct/union
|
|
||||||
# Пытаемся найти имя и тело
|
|
||||||
m = re.match(r'(struct|union)\s*(\w*)\s*({.*})\s*(\w+)?', field_str, re.DOTALL)
|
|
||||||
if m:
|
|
||||||
kind, tag, inner_body, varname = m.groups()
|
|
||||||
if not varname:
|
|
||||||
# Анонимная вложенная структура/объединение
|
|
||||||
varname = f"__anon_{anonymous_counter[0]}"
|
|
||||||
anonymous_counter[0] += 1
|
|
||||||
type_definitions[varname] = parse_fields(inner_body)
|
|
||||||
fields[varname] = varname
|
|
||||||
else:
|
|
||||||
# Если есть имя переменной
|
|
||||||
anon_type_name = f"__anon_{anonymous_counter[0]}"
|
|
||||||
anonymous_counter[0] += 1
|
|
||||||
type_definitions[anon_type_name] = parse_fields(inner_body)
|
|
||||||
fields[varname] = anon_type_name if tag == '' else f"{kind} {tag}"
|
|
||||||
else:
|
|
||||||
# Не смогли распарсить вложенную структуру - кладём как есть
|
|
||||||
fields[field_str] = None
|
|
||||||
else:
|
|
||||||
# Обычное поле
|
|
||||||
# Нужно выделить тип и имя поля с учётом указателей и массивов
|
|
||||||
m = re.match(r'(.+?)\s+([\w\*\[\]]+)$', field_str)
|
|
||||||
if m:
|
|
||||||
typename, varname = m.groups()
|
|
||||||
fields[varname.strip()] = typename.strip()
|
|
||||||
else:
|
|
||||||
# не распарсили поле — кладём "как есть"
|
|
||||||
fields[field_str] = None
|
|
||||||
return fields
|
|
||||||
|
|
||||||
# Парсим typedef struct/union {...} Alias;
|
|
||||||
typedef_struct_pattern = re.compile(
|
|
||||||
r'\btypedef\s+(struct|union)\s*({.*?})\s*(\w+)\s*;', re.DOTALL)
|
|
||||||
for match in typedef_struct_pattern.finditer(content):
|
|
||||||
alias = match.group(3)
|
|
||||||
body = match.group(2)
|
|
||||||
type_definitions[alias] = parse_fields(body)
|
|
||||||
|
|
||||||
# Парсим struct/union Name {...};
|
|
||||||
named_struct_pattern = re.compile(
|
|
||||||
r'\b(struct|union)\s+(\w+)\s*({.*?})\s*;', re.DOTALL)
|
|
||||||
for match in named_struct_pattern.finditer(content):
|
|
||||||
name = match.group(2)
|
|
||||||
body = match.group(3)
|
|
||||||
if name not in type_definitions:
|
|
||||||
type_definitions[name] = parse_fields(body)
|
|
||||||
|
|
||||||
return type_definitions
|
|
||||||
|
|
||||||
def parse_vars_from_file(filepath):
|
|
||||||
content, encoding = read_file_try_encodings(filepath)
|
|
||||||
content_clean = remove_function_bodies(content)
|
|
||||||
|
|
||||||
vars_found = []
|
|
||||||
for m in VAR_PATTERN.finditer(content_clean):
|
|
||||||
typename = m.group(1).strip()
|
|
||||||
varlist = m.group(2)
|
|
||||||
for var in varlist.split(','):
|
|
||||||
varname = var.strip()
|
|
||||||
# Убираем указатели и массивы
|
|
||||||
varname = varname.strip('*').split('[')[0]
|
|
||||||
# Фильтрация мусора
|
|
||||||
if not re.match(r'^[_a-zA-Z][_a-zA-Z0-9]*$', varname):
|
|
||||||
continue
|
|
||||||
vars_found.append((varname, typename))
|
|
||||||
return vars_found, encoding
|
|
||||||
|
|
||||||
def parse_typedefs_from_file(filepath):
|
|
||||||
"""
|
|
||||||
Парсит typedef из файла C:
|
|
||||||
- typedef struct/union { ... } Alias;
|
|
||||||
- typedef simple_type Alias;
|
|
||||||
|
|
||||||
Возвращает словарь alias -> базовый тип (например, 'MyType' -> 'struct' или 'unsigned int').
|
|
||||||
"""
|
|
||||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Убираем однострочные комментарии
|
|
||||||
content = re.sub(r'//.*?$', '', content, flags=re.MULTILINE)
|
|
||||||
# Убираем многострочные комментарии
|
|
||||||
content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
|
|
||||||
|
|
||||||
aliases = {}
|
|
||||||
|
|
||||||
# --- Парсим typedef struct/union {...} Alias;
|
|
||||||
# Используем стек для вложенных фигурных скобок
|
|
||||||
typedef_struct_union_pattern = re.compile(r'\btypedef\s+(struct|union)\b', re.IGNORECASE)
|
|
||||||
pos = 0
|
|
||||||
while True:
|
|
||||||
m = typedef_struct_union_pattern.search(content, pos)
|
|
||||||
if not m:
|
|
||||||
break
|
|
||||||
kind = m.group(1)
|
|
||||||
brace_open_pos = content.find('{', m.end())
|
|
||||||
if brace_open_pos == -1:
|
|
||||||
# Нет тела структуры, пропускаем
|
|
||||||
pos = m.end()
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Ищем позицию закрывающей скобки с учётом вложенности
|
|
||||||
brace_level = 1
|
|
||||||
i = brace_open_pos + 1
|
|
||||||
while i < len(content) and brace_level > 0:
|
|
||||||
if content[i] == '{':
|
|
||||||
brace_level += 1
|
|
||||||
elif content[i] == '}':
|
|
||||||
brace_level -= 1
|
|
||||||
i += 1
|
|
||||||
if brace_level != 0:
|
|
||||||
# Некорректный синтаксис
|
|
||||||
pos = m.end()
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Отрезок typedef структуры/объединения
|
|
||||||
typedef_block = content[m.start():i]
|
|
||||||
|
|
||||||
# После закрывающей скобки ожидаем имя алиаса и точку с запятой
|
|
||||||
rest = content[i:].lstrip()
|
|
||||||
alias_match = re.match(r'(\w+)\s*;', rest)
|
|
||||||
if alias_match:
|
|
||||||
alias_name = alias_match.group(1)
|
|
||||||
aliases[alias_name] = kind # например, "struct" или "union"
|
|
||||||
pos = i + alias_match.end()
|
|
||||||
else:
|
|
||||||
# Анонимный typedef? Просто пропускаем
|
|
||||||
pos = i
|
|
||||||
|
|
||||||
# --- Удаляем typedef struct/union {...} Alias; чтобы не мешали простым typedef
|
|
||||||
# Для этого удалим весь блок typedef struct/union {...} Alias;
|
|
||||||
def remove_typedef_struct_union_blocks(text):
|
|
||||||
result = []
|
|
||||||
last_pos = 0
|
|
||||||
for m in typedef_struct_union_pattern.finditer(text):
|
|
||||||
brace_open_pos = text.find('{', m.end())
|
|
||||||
if brace_open_pos == -1:
|
|
||||||
continue
|
|
||||||
brace_level = 1
|
|
||||||
i = brace_open_pos + 1
|
|
||||||
while i < len(text) and brace_level > 0:
|
|
||||||
if text[i] == '{':
|
|
||||||
brace_level += 1
|
|
||||||
elif text[i] == '}':
|
|
||||||
brace_level -= 1
|
|
||||||
i += 1
|
|
||||||
if brace_level != 0:
|
|
||||||
continue
|
|
||||||
# Ищем имя алиаса и точку с запятой после i
|
|
||||||
rest = text[i:].lstrip()
|
|
||||||
alias_match = re.match(r'\w+\s*;', rest)
|
|
||||||
if alias_match:
|
|
||||||
end_pos = i + alias_match.end()
|
|
||||||
result.append(text[last_pos:m.start()])
|
|
||||||
last_pos = end_pos
|
|
||||||
result.append(text[last_pos:])
|
|
||||||
return ''.join(result)
|
|
||||||
|
|
||||||
content_simple = remove_typedef_struct_union_blocks(content)
|
|
||||||
|
|
||||||
# --- Парсим простые typedef: typedef base_type alias;
|
|
||||||
simple_typedef_pattern = re.compile(
|
|
||||||
r'\btypedef\s+([^{};]+?)\s+(\w+)\s*;', re.MULTILINE)
|
|
||||||
for m in simple_typedef_pattern.finditer(content_simple):
|
|
||||||
base_type = m.group(1).strip()
|
|
||||||
alias = m.group(2).strip()
|
|
||||||
if alias not in aliases:
|
|
||||||
aliases[alias] = base_type
|
|
||||||
|
|
||||||
return aliases
|
|
||||||
|
|
||||||
def parse_externs_from_file(filepath):
|
|
||||||
content, encoding = read_file_try_encodings(filepath)
|
|
||||||
extern_vars = set(EXTERN_PATTERN.findall(content))
|
|
||||||
return extern_vars, encoding
|
|
||||||
|
|
||||||
def get_relpath_to_srcdirs(filepath, src_dirs):
|
|
||||||
# Ищем первый SRC_DIR, в котором лежит filepath, и возвращаем относительный путь
|
|
||||||
for d in src_dirs:
|
|
||||||
try:
|
|
||||||
rel = os.path.relpath(filepath, d)
|
|
||||||
# Проверим, что rel не уходит выше корня (например, не начинается с '..')
|
|
||||||
if not rel.startswith('..'):
|
|
||||||
return rel.replace('\\', '/') # Для единообразия в путях
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
# Если ни один SRC_DIR не подходит, вернуть basename
|
|
||||||
return os.path.basename(filepath)
|
|
||||||
|
|
||||||
def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
|
|
||||||
"""
|
|
||||||
Рекурсивно ищет все include-файлы начиная с заданных c_files.
|
|
||||||
include_dirs — список директорий, в которых ищем include-файлы.
|
|
||||||
processed_files — множество уже обработанных файлов (для избежания циклов).
|
|
||||||
"""
|
|
||||||
if processed_files is None:
|
|
||||||
processed_files = set()
|
|
||||||
|
|
||||||
include_files = set()
|
|
||||||
include_pattern = re.compile(r'#include\s+"([^"]+)"')
|
|
||||||
|
|
||||||
for cfile in c_files:
|
|
||||||
norm_path = os.path.normpath(cfile)
|
|
||||||
if norm_path in processed_files:
|
|
||||||
continue
|
|
||||||
processed_files.add(norm_path)
|
|
||||||
|
|
||||||
content, _ = read_file_try_encodings(cfile)
|
|
||||||
includes = include_pattern.findall(content)
|
|
||||||
for inc in includes:
|
|
||||||
include_files.add(inc)
|
|
||||||
|
|
||||||
# Ищем полный путь к include-файлу в include_dirs
|
|
||||||
inc_full_path = None
|
|
||||||
for dir_ in include_dirs:
|
|
||||||
candidate = os.path.normpath(os.path.join(dir_, inc))
|
|
||||||
if os.path.isfile(candidate):
|
|
||||||
inc_full_path = candidate
|
|
||||||
break
|
|
||||||
|
|
||||||
# Если нашли include-файл и ещё не обработали — рекурсивно ищем include внутри него
|
|
||||||
if inc_full_path and inc_full_path not in processed_files:
|
|
||||||
nested_includes = find_all_includes_recursive(
|
|
||||||
[inc_full_path], include_dirs, processed_files
|
|
||||||
)
|
|
||||||
include_files.update(nested_includes)
|
|
||||||
|
|
||||||
return include_files
|
|
||||||
|
|
||||||
def file_uses_typedef_vars(filepath, missing_vars, typedefs):
|
|
||||||
"""
|
|
||||||
Проверяем, содержит ли файл typedef с одним из missing_vars.
|
|
||||||
typedefs — словарь alias->базовый тип, полученный parse_typedefs_from_file.
|
|
||||||
"""
|
|
||||||
# Здесь проще проверить, есть ли в typedefs ключи из missing_vars,
|
|
||||||
# но в условии — typedef переменных из missing_in_h,
|
|
||||||
# значит, нужно проверить typedef переменных с этими именами
|
|
||||||
|
|
||||||
# Для упрощения — прочитаем содержимое и проверим наличие typedef с именами из missing_vars
|
|
||||||
|
|
||||||
content, _ = read_file_try_encodings(filepath)
|
|
||||||
|
|
||||||
for var in missing_vars:
|
|
||||||
# Ищем в content что-то типа typedef ... var ...;
|
|
||||||
# Для простоты регулярка: typedef ... var;
|
|
||||||
pattern = re.compile(r'\btypedef\b[^;]*\b' + re.escape(var) + r'\b[^;]*;', re.DOTALL)
|
|
||||||
if pattern.search(content):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def file_contains_extern_vars(filepath, extern_vars):
|
|
||||||
content, _ = read_file_try_encodings(filepath)
|
|
||||||
for var in extern_vars:
|
|
||||||
pattern = re.compile(r'\bextern\b[^;]*\b' + re.escape(var) + r'\b\s*;')
|
|
||||||
if pattern.search(content):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def add_struct_fields(new_debug_vars, var_prefix, struct_type, all_structs, existing_debug_vars):
|
|
||||||
"""
|
|
||||||
Рекурсивно добавляет поля структуры в new_debug_vars.
|
|
||||||
|
|
||||||
var_prefix: имя переменной или путь к полю (например "myVar" или "myVar.subfield")
|
|
||||||
struct_type: имя типа структуры (например "MyStruct")
|
|
||||||
all_structs: словарь всех структур
|
|
||||||
existing_debug_vars: множество уже существующих имен переменных
|
|
||||||
"""
|
|
||||||
if struct_type not in all_structs:
|
|
||||||
# Типа нет в структуре, значит не структура или неизвестный тип — выходим
|
|
||||||
return
|
|
||||||
|
|
||||||
fields = all_structs[struct_type]
|
|
||||||
for field_name, field_type in fields.items():
|
|
||||||
full_var_name = f"{var_prefix}.{field_name}"
|
|
||||||
|
|
||||||
if full_var_name in existing_debug_vars or full_var_name in new_debug_vars:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if field_type is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
iq_type = get_iq_define(field_type)
|
|
||||||
pt_type = map_type_to_pt(field_type, full_var_name)
|
|
||||||
formated_name = f'"{full_var_name}"'
|
|
||||||
line = f'\t{{(char *)&{full_var_name:<40} , {pt_type:<20} , {iq_type:<20} , {formated_name:<40}}}, \\'
|
|
||||||
new_debug_vars[full_var_name] = line
|
|
||||||
|
|
||||||
# Если поле — тоже структура, рекурсивно раскрываем
|
|
||||||
# При этом убираем указатели и массивы из типа, если они есть
|
|
||||||
base_field_type = field_type.split()[0] # например "struct" или "MyStruct*"
|
|
||||||
# Удаляем указатели и массивы из имени типа для поиска в all_structs
|
|
||||||
base_field_type = re.sub(r'[\*\[\]0-9]+', '', base_field_type)
|
|
||||||
base_field_type = base_field_type.strip()
|
|
||||||
|
|
||||||
if base_field_type in all_structs:
|
|
||||||
add_struct_fields(new_debug_vars, full_var_name, base_field_type, all_structs, existing_debug_vars)
|
|
||||||
else:
|
|
||||||
a=1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main(make_path):
|
|
||||||
|
|
||||||
c_files, include_dirs = parse_makefile(make_path)
|
|
||||||
all_dirs = c_files + include_dirs
|
|
||||||
|
|
||||||
h_files = get_files_by_ext(include_dirs, ['.h'])
|
|
||||||
|
|
||||||
vars_in_c = {}
|
|
||||||
encodings_c = set()
|
|
||||||
for cf in c_files:
|
|
||||||
vars_found, enc = parse_vars_from_file(cf)
|
|
||||||
encodings_c.add(enc)
|
|
||||||
for vname, vtype in vars_found:
|
|
||||||
vars_in_c[vname] = (vtype, cf)
|
|
||||||
|
|
||||||
externs_in_h = set()
|
|
||||||
for hf in h_files:
|
|
||||||
externs, _ = parse_externs_from_file(hf)
|
|
||||||
externs_in_h |= externs
|
|
||||||
|
|
||||||
missing_in_h = {v: vars_in_c[v] for v in vars_in_c if v not in externs_in_h}
|
|
||||||
|
|
||||||
all_structs = {}
|
|
||||||
for fl in c_files + h_files:
|
|
||||||
structs = extract_struct_definitions_from_file(fl)
|
|
||||||
all_structs.update(structs)
|
|
||||||
|
|
||||||
# Подготовка typedef-ов
|
|
||||||
global typedef_aliases
|
|
||||||
typedef_aliases = {}
|
|
||||||
for f in h_files + c_files:
|
|
||||||
aliases = parse_typedefs_from_file(f)
|
|
||||||
typedef_aliases.update(aliases)
|
|
||||||
|
|
||||||
|
|
||||||
included_headers = find_all_includes_recursive(c_files, include_dirs) # все подключенные .h
|
|
||||||
include_files = []
|
|
||||||
|
|
||||||
for header in included_headers:
|
|
||||||
# Полный путь к файлу нужно получить
|
|
||||||
full_path = None
|
|
||||||
for d in all_dirs:
|
|
||||||
candidate = os.path.join(d, header)
|
|
||||||
if os.path.isfile(candidate):
|
|
||||||
full_path = candidate
|
|
||||||
break
|
|
||||||
if not full_path:
|
|
||||||
continue # файл не найден в SRC_DIRS — игнорируем
|
|
||||||
|
|
||||||
# Проверяем, что это строго .h
|
|
||||||
if not full_path.endswith('.h'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Парсим typedef из файла
|
|
||||||
typedefs = parse_typedefs_from_file(full_path)
|
|
||||||
|
|
||||||
# Проверяем, использует ли typedef переменные из missing_in_h по их vtype
|
|
||||||
uses_typedef = any(vtype in typedefs for (vtype, path) in missing_in_h.values())
|
|
||||||
|
|
||||||
# Проверяем наличие extern переменных
|
|
||||||
has_extern = file_contains_extern_vars(full_path, externs_in_h)
|
|
||||||
|
|
||||||
if not has_extern and not uses_typedef:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Если прошло оба условия — добавляем
|
|
||||||
include_files.append(full_path)
|
|
||||||
|
|
||||||
# Путь к debug_vars.h
|
|
||||||
common_prefix = os.path.commonpath(include_dirs)
|
|
||||||
output_dir = os.path.join(common_prefix, 'DebugTools')
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
|
||||||
output_path = os.path.join(output_dir, 'debug_vars.c')
|
|
||||||
|
|
||||||
# Считываем существующие переменные
|
|
||||||
existing_debug_vars = {}
|
|
||||||
if os.path.isfile(output_path):
|
|
||||||
with open(output_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
||||||
old_lines = f.readlines()
|
|
||||||
for line in old_lines:
|
|
||||||
m = re.match(r'\s*{.*?,\s+.*?,\s+.*?,\s+"([_a-zA-Z][_a-zA-Z0-9]*)"\s*},', line)
|
|
||||||
if m:
|
|
||||||
varname = m.group(1)
|
|
||||||
existing_debug_vars[varname] = line.strip()
|
|
||||||
|
|
||||||
# Генерируем новые переменные
|
|
||||||
new_debug_vars = {}
|
|
||||||
for vname, (vtype, path) in vars_in_c.items():
|
|
||||||
if vname in existing_debug_vars:
|
|
||||||
continue
|
|
||||||
iq_type = get_iq_define(vtype)
|
|
||||||
pt_type = map_type_to_pt(vtype, vname)
|
|
||||||
|
|
||||||
if pt_type not in ('pt_struct', 'pt_union'):
|
|
||||||
formated_name = f'"{vname}"'
|
|
||||||
line = f'{{(char *)&{vname:<41} , {pt_type:<21} , {iq_type:<21} , {formated_name:<42}}}, \\'
|
|
||||||
new_debug_vars[vname] = line
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
# Если тип переменной — структура, добавляем поля
|
|
||||||
base_type = vtype.split()[0]
|
|
||||||
# Удаляем символы указателей '*' и всю квадратную скобку с содержимым (например [10])
|
|
||||||
base_type = re.sub(r'\*|\[[^\]]*\]', '', base_type).strip()
|
|
||||||
if base_type in all_structs:
|
|
||||||
add_struct_fields(new_debug_vars, vname, base_type, all_structs, existing_debug_vars)
|
|
||||||
|
|
||||||
# Сортируем новые переменные по алфавиту по имени
|
|
||||||
sorted_new_debug_vars = dict(sorted(new_debug_vars.items()))
|
|
||||||
# Объединяем все переменные
|
|
||||||
all_debug_lines = list(existing_debug_vars.values()) + list(sorted_new_debug_vars.values())
|
|
||||||
|
|
||||||
# DebugVar_Numb теперь по всем переменным
|
|
||||||
out_lines = []
|
|
||||||
out_lines.append("// Этот файл сгенерирован автоматически")
|
|
||||||
out_lines.append(f'#include "debug_tools.h"')
|
|
||||||
|
|
||||||
out_lines.append('\n\n// Инклюды для доступа к переменным')
|
|
||||||
out_lines.append(f'#include "IQmathLib.h"')
|
|
||||||
for incf in include_files:
|
|
||||||
out_lines.append(f'#include "{incf}"')
|
|
||||||
|
|
||||||
|
|
||||||
out_lines.append('\n\n// Экстерны для доступа к переменным')
|
|
||||||
for vname, (vtype, path) in missing_in_h.items():
|
|
||||||
out_lines.append(f'extern {vtype} {vname};')
|
|
||||||
|
|
||||||
out_lines.append(f'\n\n// Определение массива с указателями на переменные для отладки')
|
|
||||||
out_lines.append(f'int DebugVar_Numb = {len(all_debug_lines)};')
|
|
||||||
out_lines.append('#pragma DATA_SECTION(dbg_vars,".dbgvar_info")')
|
|
||||||
out_lines.append('DebugVar_t dbg_vars[] = {\\')
|
|
||||||
out_lines.extend(all_debug_lines)
|
|
||||||
out_lines.append('};')
|
|
||||||
out_lines.append('')
|
|
||||||
# Выберем кодировку для записи файла
|
|
||||||
# Если встречается несколько, возьмем первую из set
|
|
||||||
enc_to_write = 'cp1251'
|
|
||||||
|
|
||||||
#print("== GLOBAL VARS FOUND ==")
|
|
||||||
#for vname, (vtype, path) in vars_in_c.items():
|
|
||||||
#print(f"{vtype:<20} {vname:<40} // {path}")
|
|
||||||
|
|
||||||
|
|
||||||
with open(output_path, 'w', encoding=enc_to_write) as f:
|
|
||||||
f.write('\n'.join(out_lines))
|
|
||||||
|
|
||||||
print(f'Файл debug_vars.c сгенерирован в кодировке, переменных: {len(all_debug_lines)}')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
main('F:/Work/Projects/TMS/TMS_new_bus/Debug/makefile')
|
|
||||||
print("Usage: parse_makefile.py path/to/Makefile")
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
main(sys.argv[1])
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
|
|
||||||
# === Словарь соответствия типов XML → DebugVarType_t ===
|
|
||||||
type_map = dict([
|
|
||||||
*[(k, 'pt_int8') for k in ('signed char', 'char')],
|
|
||||||
*[(k, 'pt_int16') for k in ('int', 'int16', 'short')],
|
|
||||||
*[(k, 'pt_int32') for k in ('long', 'int32', '_iqx')],
|
|
||||||
*[(k, 'pt_int64') for k in ('long long', 'int64')],
|
|
||||||
|
|
||||||
*[(k, 'pt_uint8') for k in ('unsigned char',)],
|
|
||||||
*[(k, 'pt_uint16') for k in ('unsigned int', 'unsigned short', 'Uint16')],
|
|
||||||
*[(k, 'pt_uint32') for k in ('unsigned long', 'Uint32')],
|
|
||||||
*[(k, 'pt_uint64') for k in ('unsigned long long', 'Uint64')],
|
|
||||||
|
|
||||||
*[(k, 'pt_ptr_int8') for k in ('signed char*',)],
|
|
||||||
*[(k, 'pt_ptr_int16') for k in ('int*', 'short*')],
|
|
||||||
*[(k, 'pt_ptr_int32') for k in ('long*',)],
|
|
||||||
*[(k, 'pt_ptr_uint8') for k in ('unsigned char*',)],
|
|
||||||
*[(k, 'pt_ptr_uint16') for k in ('unsigned int*', 'unsigned short*')],
|
|
||||||
*[(k, 'pt_ptr_uint32') for k in ('unsigned long*',)],
|
|
||||||
('unsigned long long*', 'pt_int64'),
|
|
||||||
|
|
||||||
*[(k, 'pt_arr_int8') for k in ('signed char[]',)],
|
|
||||||
*[(k, 'pt_arr_int16') for k in ('int[]', 'short[]')],
|
|
||||||
*[(k, 'pt_arr_int32') for k in ('long[]',)],
|
|
||||||
*[(k, 'pt_arr_uint8') for k in ('unsigned char[]',)],
|
|
||||||
*[(k, 'pt_arr_uint16') for k in ('unsigned int[]', 'unsigned short[]')],
|
|
||||||
*[(k, 'pt_arr_uint32') for k in ('unsigned long[]',)],
|
|
||||||
|
|
||||||
*[(k, 'pt_float') for k in ('float', 'float32')],
|
|
||||||
|
|
||||||
('struct', 'pt_struct'),
|
|
||||||
('union', 'pt_union'),
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def is_anonymous(elem):
|
|
||||||
typ = elem.attrib.get('type', '')
|
|
||||||
return 'anonymous' in typ
|
|
||||||
|
|
||||||
|
|
||||||
def get_array_sizes(elem):
|
|
||||||
sizes = []
|
|
||||||
i = 0
|
|
||||||
while True:
|
|
||||||
attr = 'size' if i == 0 else f'size{i}'
|
|
||||||
if attr in elem.attrib:
|
|
||||||
sizes.append(elem.attrib[attr])
|
|
||||||
i += 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
return ''.join(f'[{size}]' for size in sizes)
|
|
||||||
|
|
||||||
|
|
||||||
def collect_externs_and_vars(element, prefix, extern_vars, variables):
|
|
||||||
kind = element.attrib.get('kind', '')
|
|
||||||
name = element.attrib.get('name', prefix)
|
|
||||||
vtype = element.attrib.get('type', 'unknown')
|
|
||||||
|
|
||||||
# Пропускаем анонимные типы полностью
|
|
||||||
if is_anonymous(element):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Для массивов учитываем все размеры size, size1, size2...
|
|
||||||
if kind == 'array':
|
|
||||||
array_dims = get_array_sizes(element)
|
|
||||||
extern_type = vtype # тип без размеров
|
|
||||||
extern_vars[name] = (extern_type, array_dims)
|
|
||||||
variables.append((name, vtype)) # В массив макросов кладём сам массив (без элементов)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Для обычных структур (не анонимных) и переменных
|
|
||||||
if kind in ('struct', 'union'):
|
|
||||||
extern_vars[name] = (vtype, '')
|
|
||||||
variables.append((name, vtype))
|
|
||||||
return
|
|
||||||
|
|
||||||
# Простые переменные
|
|
||||||
extern_vars[name] = (vtype, '')
|
|
||||||
variables.append((name, vtype))
|
|
||||||
|
|
||||||
|
|
||||||
def parse_variables(xml_path):
|
|
||||||
tree = ET.parse(xml_path)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
extern_vars = dict()
|
|
||||||
variables = []
|
|
||||||
|
|
||||||
for var in root.findall('variable'):
|
|
||||||
collect_externs_and_vars(var, var.attrib['name'], extern_vars, variables)
|
|
||||||
|
|
||||||
return variables, extern_vars
|
|
||||||
|
|
||||||
def format_extern_declaration(varname, vartype, dims):
|
|
||||||
base_type = vartype.replace('[]', '') # убираем [] из типа
|
|
||||||
return f"extern {base_type} {varname}{dims};"
|
|
||||||
|
|
||||||
|
|
||||||
def to_macro_entry(varname, vartype):
|
|
||||||
# pt_ и t_iq_none — пример, замените на вашу логику или словарь
|
|
||||||
ptr_type = type_map.get(vartype)
|
|
||||||
if ptr_type is None:
|
|
||||||
ptr_type = 'char *'
|
|
||||||
iq_type = "t_iq_none"
|
|
||||||
return f"\t{{(char *)&{varname:<40}, {ptr_type:<20}, {iq_type:<20}, \"{varname}\"}},"
|
|
||||||
|
|
||||||
|
|
||||||
def generate_code(variables, extern_vars):
|
|
||||||
# extern-блок
|
|
||||||
extern_lines = []
|
|
||||||
for var, (vtype, dims) in sorted(extern_vars.items()):
|
|
||||||
# фильтр анонимных структур по имени (пример)
|
|
||||||
if "anonymous" in var:
|
|
||||||
continue
|
|
||||||
extern_lines.append(format_extern_declaration(var, vtype, dims))
|
|
||||||
|
|
||||||
# define DebugVar_Numb
|
|
||||||
debugvar_numb = len(variables)
|
|
||||||
defines = [f"#define DebugVar_Numb\t{debugvar_numb}"]
|
|
||||||
|
|
||||||
# define DebugVar_Init
|
|
||||||
defines.append("#define DebugVar_Init\t\\")
|
|
||||||
defines.append("{\\")
|
|
||||||
for varname, vartype in variables:
|
|
||||||
defines.append(to_macro_entry(varname, vartype))
|
|
||||||
defines.append("}")
|
|
||||||
|
|
||||||
return "\n".join(extern_lines) + "\n\n" + "\n".join(defines)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
xml_file = "F:/Work/Projects/TMS/TMS_new_bus/bin/New_bus_allVars.xml"
|
|
||||||
variables, extern_vars = parse_variables(xml_file)
|
|
||||||
|
|
||||||
code = generate_code(variables, extern_vars)
|
|
||||||
|
|
||||||
with open("debug_vars.h", "w") as f:
|
|
||||||
f.write(code)
|
|
||||||
|
|
||||||
print("Сгенерировано в debug_vars.h")
|
|
||||||
@@ -1,581 +0,0 @@
|
|||||||
import sys
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
from generateVars import map_type_to_pt, get_iq_define, type_map
|
|
||||||
from enum import IntEnum
|
|
||||||
from scanVars import run_scan
|
|
||||||
from generateVars import run_generate
|
|
||||||
|
|
||||||
from PySide6.QtWidgets import (
|
|
||||||
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
|
||||||
QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton,
|
|
||||||
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit
|
|
||||||
)
|
|
||||||
from PySide6.QtGui import QTextCursor
|
|
||||||
from PySide6.QtCore import Qt, QProcess
|
|
||||||
|
|
||||||
class rows(IntEnum):
|
|
||||||
include = 0
|
|
||||||
name = 1
|
|
||||||
type = 2
|
|
||||||
pt_type = 3
|
|
||||||
iq_type = 4
|
|
||||||
ret_type = 5
|
|
||||||
short_name = 6
|
|
||||||
|
|
||||||
# 1. Парсим vars.xml
|
|
||||||
def make_absolute_path(path, base_path):
|
|
||||||
if not os.path.isabs(path):
|
|
||||||
return os.path.abspath(os.path.join(base_path, path))
|
|
||||||
return os.path.abspath(path)
|
|
||||||
|
|
||||||
def parse_vars(filename):
|
|
||||||
tree = ET.parse(filename)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
vars_list = []
|
|
||||||
variables_elem = root.find('variables')
|
|
||||||
if variables_elem is not None:
|
|
||||||
for var in variables_elem.findall('var'):
|
|
||||||
name = var.attrib.get('name', '')
|
|
||||||
vars_list.append({
|
|
||||||
'name': name,
|
|
||||||
'enable': var.findtext('enable', 'false'),
|
|
||||||
'shortname': var.findtext('shortname', name),
|
|
||||||
'pt_type': var.findtext('pt_type', 'pt_unknown'),
|
|
||||||
'iq_type': var.findtext('iq_type', 'iq_none'),
|
|
||||||
'return_type': var.findtext('return_type', 'int'),
|
|
||||||
'type': var.findtext('type', 'unknown'),
|
|
||||||
'file': var.findtext('file', ''),
|
|
||||||
'extern': var.findtext('extern', 'false') == 'true',
|
|
||||||
'static': var.findtext('static', 'false') == 'true',
|
|
||||||
})
|
|
||||||
|
|
||||||
return vars_list
|
|
||||||
|
|
||||||
# 2. Парсим structSup.xml
|
|
||||||
def parse_structs(filename):
|
|
||||||
tree = ET.parse(filename)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
structs = {}
|
|
||||||
typedef_map = {}
|
|
||||||
|
|
||||||
# --- Считываем структуры ---
|
|
||||||
structs_elem = root.find('structs')
|
|
||||||
if structs_elem is not None:
|
|
||||||
for struct in structs_elem.findall('struct'):
|
|
||||||
name = struct.attrib['name']
|
|
||||||
fields = {}
|
|
||||||
for field in struct.findall('field'):
|
|
||||||
fname = field.attrib.get('name')
|
|
||||||
ftype = field.attrib.get('type')
|
|
||||||
if fname and ftype:
|
|
||||||
fields[fname] = ftype
|
|
||||||
structs[name] = fields
|
|
||||||
|
|
||||||
# --- Считываем typedef-ы ---
|
|
||||||
typedefs_elem = root.find('typedefs')
|
|
||||||
if typedefs_elem is not None:
|
|
||||||
for typedef in typedefs_elem.findall('typedef'):
|
|
||||||
name = typedef.attrib.get('name')
|
|
||||||
target_type = typedef.attrib.get('type')
|
|
||||||
if name and target_type:
|
|
||||||
typedef_map[name.strip()] = target_type.strip()
|
|
||||||
|
|
||||||
return structs, typedef_map
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessOutputWindow(QWidget):
|
|
||||||
def __init__(self, command, args):
|
|
||||||
super().__init__()
|
|
||||||
self.setWindowTitle("Поиск переменных...")
|
|
||||||
self.resize(600, 400)
|
|
||||||
|
|
||||||
self.layout = QVBoxLayout(self)
|
|
||||||
self.output_edit = QTextEdit()
|
|
||||||
self.output_edit.setReadOnly(True)
|
|
||||||
self.layout.addWidget(self.output_edit)
|
|
||||||
|
|
||||||
self.btn_close = QPushButton("Закрыть")
|
|
||||||
self.btn_close.setEnabled(False)
|
|
||||||
self.btn_close.clicked.connect(self.close)
|
|
||||||
self.layout.addWidget(self.btn_close)
|
|
||||||
|
|
||||||
self.process = QProcess(self)
|
|
||||||
self.process.setProcessChannelMode(QProcess.MergedChannels)
|
|
||||||
self.process.readyReadStandardOutput.connect(self.handle_stdout)
|
|
||||||
self.process.finished.connect(self.process_finished)
|
|
||||||
|
|
||||||
self.process.start(command, args)
|
|
||||||
|
|
||||||
def handle_stdout(self):
|
|
||||||
data = self.process.readAllStandardOutput()
|
|
||||||
text = data.data().decode('utf-8')
|
|
||||||
self.output_edit.append(text)
|
|
||||||
|
|
||||||
def process_finished(self):
|
|
||||||
self.output_edit.append("\n--- Процесс завершён ---")
|
|
||||||
self.btn_close.setEnabled(True)
|
|
||||||
|
|
||||||
# 3. UI: таблица с переменными
|
|
||||||
class VarEditor(QWidget):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.vars_list = []
|
|
||||||
self.structs = {}
|
|
||||||
self.typedef_map = {}
|
|
||||||
self.structs_xml_path = None # сюда запишем путь из <structs_xml>
|
|
||||||
self.initUI()
|
|
||||||
|
|
||||||
def initUI(self):
|
|
||||||
self.setWindowTitle("Variable Editor")
|
|
||||||
|
|
||||||
# --- Поля ввода пути проекта и XML ---
|
|
||||||
|
|
||||||
# XML Output
|
|
||||||
xml_layout = QHBoxLayout()
|
|
||||||
xml_layout.addWidget(QLabel("XML Output:"))
|
|
||||||
self.xml_output_edit = QLineEdit()
|
|
||||||
xml_layout.addWidget(self.xml_output_edit)
|
|
||||||
self.xml_output_edit.returnPressed.connect(self.read_xml_file)
|
|
||||||
btn_xml_browse = QPushButton("...")
|
|
||||||
btn_xml_browse.setFixedWidth(30)
|
|
||||||
xml_layout.addWidget(btn_xml_browse)
|
|
||||||
btn_xml_browse.clicked.connect(self.browse_xml_output)
|
|
||||||
|
|
||||||
# Project Path
|
|
||||||
proj_layout = QHBoxLayout()
|
|
||||||
proj_layout.addWidget(QLabel("Project Path:"))
|
|
||||||
self.proj_path_edit = QLineEdit()
|
|
||||||
proj_layout.addWidget(self.proj_path_edit)
|
|
||||||
btn_proj_browse = QPushButton("...")
|
|
||||||
btn_proj_browse.setFixedWidth(30)
|
|
||||||
proj_layout.addWidget(btn_proj_browse)
|
|
||||||
btn_proj_browse.clicked.connect(self.browse_proj_path)
|
|
||||||
|
|
||||||
# Makefile Path
|
|
||||||
makefile_layout = QHBoxLayout()
|
|
||||||
makefile_layout.addWidget(QLabel("Makefile Path (relative path):"))
|
|
||||||
self.makefile_edit = QLineEdit()
|
|
||||||
makefile_layout.addWidget(self.makefile_edit)
|
|
||||||
btn_makefile_browse = QPushButton("...")
|
|
||||||
btn_makefile_browse.setFixedWidth(30)
|
|
||||||
makefile_layout.addWidget(btn_makefile_browse)
|
|
||||||
btn_makefile_browse.clicked.connect(self.browse_makefile)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Source Output File/Directory
|
|
||||||
source_output_layout = QHBoxLayout()
|
|
||||||
source_output_layout.addWidget(QLabel("Source Output File:"))
|
|
||||||
self.source_output_edit = QLineEdit()
|
|
||||||
source_output_layout.addWidget(self.source_output_edit)
|
|
||||||
btn_source_output_browse = QPushButton("...")
|
|
||||||
btn_source_output_browse.setFixedWidth(30)
|
|
||||||
source_output_layout.addWidget(btn_source_output_browse)
|
|
||||||
btn_source_output_browse.clicked.connect(self.browse_source_output)
|
|
||||||
|
|
||||||
|
|
||||||
self.btn_update_vars = QPushButton("Обновить данные о переменных")
|
|
||||||
self.btn_update_vars.clicked.connect(self.update_vars_data)
|
|
||||||
|
|
||||||
# Таблица переменных
|
|
||||||
self.table = QTableWidget(len(self.vars_list), 7)
|
|
||||||
self.table.setHorizontalHeaderLabels([
|
|
||||||
'Include',
|
|
||||||
'Name',
|
|
||||||
'Origin Type',
|
|
||||||
'Pointer Type',
|
|
||||||
'IQ Type',
|
|
||||||
'Return Type',
|
|
||||||
'Short Name'
|
|
||||||
])
|
|
||||||
self.table.setEditTriggers(QAbstractItemView.AllEditTriggers)
|
|
||||||
|
|
||||||
# Кнопка сохранения
|
|
||||||
btn_save = QPushButton("Build")
|
|
||||||
btn_save.clicked.connect(self.save_build)
|
|
||||||
|
|
||||||
# Основной layout
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.addLayout(xml_layout)
|
|
||||||
layout.addLayout(proj_layout)
|
|
||||||
layout.addLayout(makefile_layout)
|
|
||||||
layout.addWidget(self.btn_update_vars)
|
|
||||||
layout.addWidget(self.table)
|
|
||||||
layout.addWidget(btn_save)
|
|
||||||
layout.addLayout(source_output_layout)
|
|
||||||
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
def update_vars_data(self):
|
|
||||||
proj_path = os.path.abspath(self.proj_path_edit.text().strip())
|
|
||||||
xml_path = os.path.abspath(self.xml_output_edit.text().strip())
|
|
||||||
makefile_path = make_absolute_path(self.makefile_edit.text().strip(), proj_path)
|
|
||||||
|
|
||||||
if not proj_path or not xml_path:
|
|
||||||
QMessageBox.warning(self, "Ошибка", "Пожалуйста, укажите пути проекта и XML.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not os.path.isfile(makefile_path):
|
|
||||||
QMessageBox.warning(self, "Ошибка", f"Makefile не найден по пути:\n{makefile_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
scanvars_exe = "scanVars.exe"
|
|
||||||
args = [proj_path, makefile_path, xml_path]
|
|
||||||
|
|
||||||
# Создаем и показываем окно с выводом процесса
|
|
||||||
self.proc_win = ProcessOutputWindow("python", [])
|
|
||||||
self.proc_win.show()
|
|
||||||
self.proc_win.output_edit.append("Запуск анализа переменных...")
|
|
||||||
|
|
||||||
# Запускаем в отдельном процессе через QProcess, если нужен live-вывод:
|
|
||||||
from threading import Thread
|
|
||||||
|
|
||||||
def run_scan_wrapper():
|
|
||||||
try:
|
|
||||||
run_scan(proj_path, makefile_path, xml_path)
|
|
||||||
self.proc_win.output_edit.append("\n--- Анализ завершён ---")
|
|
||||||
except Exception as e:
|
|
||||||
self.proc_win.output_edit.append(f"\n[ОШИБКА] {e}")
|
|
||||||
self.proc_win.btn_close.setEnabled(True)
|
|
||||||
self.after_scanvars_finished(0, 0)
|
|
||||||
|
|
||||||
Thread(target=run_scan_wrapper).start()
|
|
||||||
# Можно подписаться на сигнал завершения процесса, если хочешь обновить UI после
|
|
||||||
#self.proc_win.process.finished.connect(lambda exitCode, exitStatus: self.after_scanvars_finished(exitCode, exitStatus))
|
|
||||||
|
|
||||||
|
|
||||||
def save_build(self):
|
|
||||||
vars_out = []
|
|
||||||
for row in range(self.table.rowCount()):
|
|
||||||
include_cb = self.table.cellWidget(row, rows.include)
|
|
||||||
if not include_cb.isChecked():
|
|
||||||
continue
|
|
||||||
name_edit = self.table.cellWidget(row, rows.name)
|
|
||||||
pt_type_combo = self.table.cellWidget(row, rows.pt_type)
|
|
||||||
iq_combo = self.table.cellWidget(row, rows.iq_type)
|
|
||||||
ret_combo = self.table.cellWidget(row, rows.ret_type)
|
|
||||||
short_name_edit = self.table.cellWidget(row, rows.short_name)
|
|
||||||
|
|
||||||
var_data = {
|
|
||||||
'name': name_edit.text(),
|
|
||||||
'type': 'pt_' + pt_type_combo.currentText(),
|
|
||||||
'iq_type': iq_combo.currentText(),
|
|
||||||
'return_type': ret_combo.currentText() if ret_combo.currentText() else 'int',
|
|
||||||
'short_name': short_name_edit.text(),
|
|
||||||
}
|
|
||||||
vars_out.append(var_data)
|
|
||||||
|
|
||||||
# Здесь нужно указать абсолютные пути к проекту, xml и output (замени на свои)
|
|
||||||
proj_path = os.path.abspath(self.proj_path_edit.text().strip())
|
|
||||||
xml_path = os.path.abspath(self.xml_output_edit.text().strip())
|
|
||||||
output_dir_c_file = os.path.abspath(self.source_output_edit.text().strip())
|
|
||||||
|
|
||||||
if not proj_path or not xml_path or not output_dir_c_file:
|
|
||||||
QMessageBox.warning(self, "Ошибка", "Заполните все пути: проект, XML и output.")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
run_generate(proj_path, xml_path, output_dir_c_file)
|
|
||||||
QMessageBox.information(self, "Готово", "Файл debug_vars.c успешно сгенерирован.")
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.critical(self, "Ошибка при генерации", str(e))
|
|
||||||
|
|
||||||
def browse_proj_path(self):
|
|
||||||
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку проекта")
|
|
||||||
if dir_path:
|
|
||||||
self.proj_path_edit.setText(dir_path)
|
|
||||||
|
|
||||||
def read_xml_file(self):
|
|
||||||
file_path = self.xml_output_edit.text().strip()
|
|
||||||
if file_path and not os.path.isfile(file_path):
|
|
||||||
return
|
|
||||||
|
|
||||||
self.vars_list = parse_vars(file_path)
|
|
||||||
try:
|
|
||||||
tree = ET.parse(file_path)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
proj_path = self.proj_path_edit.text().strip()
|
|
||||||
|
|
||||||
if not proj_path:
|
|
||||||
# Если в поле ничего нет, пробуем взять из XML
|
|
||||||
proj_path_from_xml = root.attrib.get('proj_path', '').strip()
|
|
||||||
if proj_path_from_xml and os.path.isdir(proj_path_from_xml):
|
|
||||||
proj_path = proj_path_from_xml
|
|
||||||
self.proj_path_edit.setText(proj_path_from_xml)
|
|
||||||
else:
|
|
||||||
QMessageBox.warning(
|
|
||||||
self,
|
|
||||||
"Внимание",
|
|
||||||
"Путь к проекту (proj_path) не найден или не существует.\n"
|
|
||||||
"Пожалуйста, укажите его вручную в поле 'Project Path'."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if not os.path.isdir(proj_path):
|
|
||||||
QMessageBox.warning(
|
|
||||||
self,
|
|
||||||
"Внимание",
|
|
||||||
f"Указанный путь к проекту не существует:\n{proj_path}\n"
|
|
||||||
"Пожалуйста, исправьте путь в поле 'Project Path'."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# --- makefile_path из атрибута ---
|
|
||||||
makefile_path = root.attrib.get('makefile_path', '').strip()
|
|
||||||
makefile_path_full = make_absolute_path(makefile_path, proj_path)
|
|
||||||
if makefile_path_full and os.path.isfile(makefile_path_full):
|
|
||||||
self.makefile_edit.setText(makefile_path)
|
|
||||||
|
|
||||||
# --- structs_path из атрибута ---
|
|
||||||
structs_path = root.attrib.get('structs_path', '').strip()
|
|
||||||
structs_path_full = make_absolute_path(structs_path, proj_path)
|
|
||||||
if structs_path_full and os.path.isfile(structs_path_full):
|
|
||||||
self.structs_xml_path = structs_path_full
|
|
||||||
self.structs, self.typedef_map = parse_structs(structs_path_full)
|
|
||||||
else:
|
|
||||||
self.structs_xml_path = None
|
|
||||||
|
|
||||||
self.update_table()
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
|
|
||||||
|
|
||||||
def browse_xml_output(self):
|
|
||||||
file_path, _ = QFileDialog.getSaveFileName(
|
|
||||||
self,
|
|
||||||
"Выберите XML файл",
|
|
||||||
filter="XML files (*.xml);;All Files (*)"
|
|
||||||
)
|
|
||||||
self.xml_output_edit.setText(file_path)
|
|
||||||
self.read_xml_file()
|
|
||||||
|
|
||||||
|
|
||||||
def browse_xml_struct(self):
|
|
||||||
file_path, _ = QFileDialog.getSaveFileName(self, "Выберите XML файл", filter="XML files (*.xml);;All Files (*)")
|
|
||||||
if file_path:
|
|
||||||
self.xml_output_edit.setText(file_path)
|
|
||||||
if os.path.isfile(file_path):
|
|
||||||
self.structs, self.typedef_map = parse_structs(file_path)
|
|
||||||
|
|
||||||
def browse_makefile(self):
|
|
||||||
file_path, _ = QFileDialog.getOpenFileName(
|
|
||||||
self, "Выберите Makefile", filter="Makefile (makefile);;All Files (*)"
|
|
||||||
)
|
|
||||||
if file_path:
|
|
||||||
self.makefile_edit.setText(file_path)
|
|
||||||
|
|
||||||
def browse_source_output(self):
|
|
||||||
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку для debug_vars.c")
|
|
||||||
if dir_path:
|
|
||||||
self.source_output_edit.setText(dir_path)
|
|
||||||
|
|
||||||
def after_scanvars_finished(self, exitCode, exitStatus):
|
|
||||||
xml_path = self.xml_output_edit.text().strip()
|
|
||||||
if not os.path.isfile(xml_path):
|
|
||||||
QMessageBox.critical(self, "Ошибка", f"Файл не найден: {xml_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Читаем структуры, если задан путь
|
|
||||||
if self.structs_xml_path and os.path.isfile(self.structs_xml_path):
|
|
||||||
try:
|
|
||||||
self.structs, self.typedef_map = parse_structs(self.structs_xml_path)
|
|
||||||
# При необходимости обновите UI или сделайте что-то с self.structs
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.warning(self, "Внимание", f"Не удалось загрузить структуры из {self.structs_xml_path}:\n{e}")
|
|
||||||
|
|
||||||
self.vars_list = parse_vars(xml_path)
|
|
||||||
self.update_table()
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить переменные:\n{e}")
|
|
||||||
|
|
||||||
def update_table(self):
|
|
||||||
self.type_options = list(dict.fromkeys(type_map.values()))
|
|
||||||
self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
|
|
||||||
iq_types = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
|
|
||||||
self.table.setRowCount(len(self.vars_list))
|
|
||||||
|
|
||||||
for row, var in enumerate(self.vars_list):
|
|
||||||
cb = QCheckBox()
|
|
||||||
enable_str = var.get('enable', 'false')
|
|
||||||
cb.setChecked(enable_str.lower() == 'true')
|
|
||||||
self.table.setCellWidget(row, rows.include, cb)
|
|
||||||
|
|
||||||
name_edit = QLineEdit(var['name'])
|
|
||||||
if var['type'] in self.structs:
|
|
||||||
completer = QCompleter(self.structs[var['type']].keys())
|
|
||||||
completer.setCaseSensitivity(Qt.CaseInsensitive)
|
|
||||||
name_edit.setCompleter(completer)
|
|
||||||
self.table.setCellWidget(row, rows.name, name_edit)
|
|
||||||
|
|
||||||
# Type (origin)
|
|
||||||
origin_type = var.get('type', '').strip()
|
|
||||||
origin_item = QTableWidgetItem(origin_type)
|
|
||||||
origin_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) # read-only
|
|
||||||
self.table.setItem(row, rows.type, origin_item)
|
|
||||||
|
|
||||||
pt_type_combo = QComboBox()
|
|
||||||
pt_type_combo.addItems(self.display_type_options)
|
|
||||||
internal_type = map_type_to_pt(var['type'], var['name'], self.typedef_map)
|
|
||||||
display_type = internal_type.replace('pt_', '')
|
|
||||||
if display_type in self.display_type_options:
|
|
||||||
pt_type_combo.setCurrentText(display_type)
|
|
||||||
else:
|
|
||||||
pt_type_combo.addItem(display_type)
|
|
||||||
pt_type_combo.setCurrentText(display_type)
|
|
||||||
self.table.setCellWidget(row, rows.pt_type, pt_type_combo)
|
|
||||||
|
|
||||||
iq_combo = QComboBox()
|
|
||||||
iq_combo.addItems(iq_types)
|
|
||||||
iq_type = get_iq_define(var['type']) # Получаем IQ-тип, например 'iq24'
|
|
||||||
display_type = iq_type.replace('t_', '')
|
|
||||||
if iq_type in iq_types:
|
|
||||||
iq_combo.setCurrentText(display_type)
|
|
||||||
else:
|
|
||||||
iq_combo.addItem(display_type)
|
|
||||||
iq_combo.setCurrentText(display_type)
|
|
||||||
self.table.setCellWidget(row, rows.iq_type, iq_combo)
|
|
||||||
|
|
||||||
ret_combo = QComboBox()
|
|
||||||
ret_combo.addItems(iq_types)
|
|
||||||
self.table.setCellWidget(row, rows.ret_type, ret_combo)
|
|
||||||
|
|
||||||
short_name_edit = QLineEdit(var['name'])
|
|
||||||
self.table.setCellWidget(row, rows.short_name, short_name_edit)
|
|
||||||
|
|
||||||
cb.stateChanged.connect(self.save_table_to_xml)
|
|
||||||
name_edit.textChanged.connect(self.save_table_to_xml)
|
|
||||||
pt_type_combo.currentTextChanged.connect(self.save_table_to_xml)
|
|
||||||
iq_combo.currentTextChanged.connect(self.save_table_to_xml)
|
|
||||||
ret_combo.currentTextChanged.connect(self.save_table_to_xml)
|
|
||||||
short_name_edit.textChanged.connect(self.save_table_to_xml)
|
|
||||||
|
|
||||||
|
|
||||||
def save_table_to_xml(self):
|
|
||||||
def make_relative_path(abs_path, base_path):
|
|
||||||
try:
|
|
||||||
return os.path.relpath(abs_path, base_path).replace("\\", "/")
|
|
||||||
except ValueError:
|
|
||||||
return abs_path.replace("\\", "/")
|
|
||||||
|
|
||||||
xml_path = self.xml_output_edit.text().strip()
|
|
||||||
proj_path = self.proj_path_edit.text().strip()
|
|
||||||
makefile_path = self.makefile_edit.text().strip()
|
|
||||||
|
|
||||||
if not xml_path or not os.path.isfile(xml_path):
|
|
||||||
print("XML файл не найден или путь пустой")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
tree = ET.parse(xml_path)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
# Обновим атрибуты с относительными путями
|
|
||||||
if os.path.isdir(proj_path):
|
|
||||||
root.set("proj_path", proj_path.replace("\\", "/"))
|
|
||||||
|
|
||||||
if os.path.isfile(makefile_path):
|
|
||||||
rel_makefile = make_relative_path(makefile_path, proj_path)
|
|
||||||
root.set("makefile_path", rel_makefile)
|
|
||||||
|
|
||||||
if self.structs_xml_path and os.path.isfile(self.structs_xml_path):
|
|
||||||
rel_struct_path = make_relative_path(self.structs_xml_path, proj_path)
|
|
||||||
root.set("structs_path", rel_struct_path)
|
|
||||||
|
|
||||||
|
|
||||||
vars_elem = root.find('variables')
|
|
||||||
if vars_elem is None:
|
|
||||||
# Если блока нет, создаём
|
|
||||||
vars_elem = ET.SubElement(root, 'variables')
|
|
||||||
|
|
||||||
original_info = {}
|
|
||||||
for var_elem in vars_elem.findall('var'):
|
|
||||||
name = var_elem.attrib.get('name')
|
|
||||||
if name:
|
|
||||||
original_info[name] = {
|
|
||||||
'type': var_elem.findtext('type', ''),
|
|
||||||
'file': var_elem.findtext('file', ''),
|
|
||||||
'extern': var_elem.findtext('extern', ''),
|
|
||||||
'static': var_elem.findtext('static', '')
|
|
||||||
}
|
|
||||||
# Собираем данные из таблицы
|
|
||||||
updated_vars = []
|
|
||||||
for row in range(self.table.rowCount()):
|
|
||||||
cb = self.table.cellWidget(row, 0)
|
|
||||||
name_edit = self.table.cellWidget(row, 1)
|
|
||||||
pt_type_combo = self.table.cellWidget(row, 3)
|
|
||||||
iq_combo = self.table.cellWidget(row, 4)
|
|
||||||
ret_combo = self.table.cellWidget(row, 5)
|
|
||||||
short_name_edit = self.table.cellWidget(row, 6)
|
|
||||||
|
|
||||||
var_name = name_edit.text()
|
|
||||||
|
|
||||||
# Берём оригинальные type и file из словаря, если есть
|
|
||||||
orig_type = original_info.get(var_name, {}).get('type', '')
|
|
||||||
orig_file = original_info.get(var_name, {}).get('file', '')
|
|
||||||
orig_extern = original_info.get(var_name, {}).get('extern', '')
|
|
||||||
orig_static = original_info.get(var_name, {}).get('static', '')
|
|
||||||
|
|
||||||
updated_vars.append({
|
|
||||||
'name': var_name,
|
|
||||||
'enable': cb.isChecked(),
|
|
||||||
'shortname': short_name_edit.text(),
|
|
||||||
'pt_type': 'pt_' + pt_type_combo.currentText(),
|
|
||||||
'iq_type': iq_combo.currentText(),
|
|
||||||
'return_type': ret_combo.currentText() or 'int',
|
|
||||||
'type': orig_type,
|
|
||||||
'file': orig_file,
|
|
||||||
'extern': orig_extern,
|
|
||||||
'static': orig_static,
|
|
||||||
})
|
|
||||||
|
|
||||||
# Обновляем или добавляем по одному var в XML
|
|
||||||
for v in updated_vars:
|
|
||||||
var_elem = None
|
|
||||||
for ve in vars_elem.findall('var'):
|
|
||||||
if ve.attrib.get('name') == v['name']:
|
|
||||||
var_elem = ve
|
|
||||||
break
|
|
||||||
if var_elem is None:
|
|
||||||
var_elem = ET.SubElement(vars_elem, 'var', {'name': v['name']})
|
|
||||||
|
|
||||||
def set_sub_elem_text(parent, tag, text):
|
|
||||||
el = parent.find(tag)
|
|
||||||
if el is None:
|
|
||||||
el = ET.SubElement(parent, tag)
|
|
||||||
el.text = str(text)
|
|
||||||
|
|
||||||
set_sub_elem_text(var_elem, 'enable', 'true' if v['enable'] else 'false')
|
|
||||||
set_sub_elem_text(var_elem, 'shortname', v['shortname'])
|
|
||||||
set_sub_elem_text(var_elem, 'pt_type', v['pt_type'])
|
|
||||||
set_sub_elem_text(var_elem, 'iq_type', v['iq_type'])
|
|
||||||
set_sub_elem_text(var_elem, 'return_type', v['return_type'])
|
|
||||||
set_sub_elem_text(var_elem, 'type', v['type'])
|
|
||||||
set_sub_elem_text(var_elem, 'file', v['file'])
|
|
||||||
set_sub_elem_text(var_elem, 'extern', v['extern'])
|
|
||||||
set_sub_elem_text(var_elem, 'static', v['static'])
|
|
||||||
|
|
||||||
# Сохраняем изменения
|
|
||||||
tree.write(xml_path, encoding='utf-8', xml_declaration=True)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Ошибка при сохранении XML: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
|
|
||||||
editor = VarEditor()
|
|
||||||
editor.resize(900, 600)
|
|
||||||
editor.show()
|
|
||||||
|
|
||||||
sys.exit(app.exec())
|
|
||||||
|
|
||||||
|
|
||||||
BIN
DebugVarEdit.exe
BIN
DebugVarEdit.exe
Binary file not shown.
172
README.md
Normal file
172
README.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# DebugTools - Просмотр переменных по указателям
|
||||||
|
Модуль состоит из трех файлов:
|
||||||
|
- **debug_tools.c** - реализация считывания переменных
|
||||||
|
- **debug_tools.h** - объявление всякого для считывания переменных
|
||||||
|
- **debug_vars.c** - определение массива считываемых переменных
|
||||||
|
|
||||||
|
Этот модуль предоставляет функциональность для чтения значений переменных во встроенной системе, включая работу с IQ-форматами, защиту доступа и проверку диапазонов памяти.
|
||||||
|
|
||||||
|
Для чтения переменных можно использовать функции:
|
||||||
|
|
||||||
|
```c
|
||||||
|
int Debug_ReadVar(int var_ind, int32_t *return_long);
|
||||||
|
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Переменные доступные для чтения определяются в **debug_vars.c** (их можно прописывать вручную или генерировать через **DebugVarEdit**):
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Определение массива с указателями на переменные для отладки
|
||||||
|
int DebugVar_Qnt = 5;
|
||||||
|
#pragma DATA_SECTION(dbg_vars,".dbgvar_info")
|
||||||
|
// pointer_type iq_type return_iq_type short_name
|
||||||
|
DebugVar_t dbg_vars[] = {\
|
||||||
|
{(uint8_t *)&freqTerm, pt_float, t_iq_none, t_iq10, "freqT" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][0], pt_int16, t_iq_none, t_iq_none, "ADC_sf00" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][1], pt_int16, t_iq_none, t_iq_none, "ADC_sf01" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][2], pt_int16, t_iq_none, t_iq_none, "ADC_sf02" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][3], pt_int16, t_iq_none, t_iq_none, "ADC_sf03" }, \
|
||||||
|
{(uint8_t *)&Bender[0].KOhms, pt_uint16, t_iq, t_iq10, "Bend0.KOhm" }, \
|
||||||
|
{(uint8_t *)&Bender[0].Times, pt_uint16, t_iq_none, t_iq_none, "Bend0.Time" }, \
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# DebugVarEdit - Настройка переменных
|
||||||
|
**DebugVarEdit** — графическое приложение для Windows, предназначенное для настройки и генерации отладочных переменных (`debug_vars.c`) на основе исходного C-проекта. Работает с `makefile` проекта, сохраняет изменения в XML и позволяет удобно редактировать переменные и их типы через интерфейс.
|
||||||
|
|
||||||
|
Программа — один исполняемый файл `DebugVarEdit.exe`, не требующий установки и дополнительных зависимостей.
|
||||||
|
|
||||||
|
> Требуется Windows 7 или новее.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Как использовать приложение
|
||||||
|
|
||||||
|
1. Запустите **DebugVarEdit.exe.**
|
||||||
|
|
||||||
|
2. Укажите пути и контроллер:
|
||||||
|
- **Путь к XML** — новый или существующий файл настроек переменных;
|
||||||
|
- **Путь к проекту** — путь к корню проека (папка, которая является корнем для проекта в Code Composer);
|
||||||
|
- **Путь к makefile** — путь к `makefile` относительно корня проекта;
|
||||||
|
- **Путь для debug_vars.c** — папка, куда будет сгенерирован файл `debug_vars.c` с переменными.
|
||||||
|
- **МК** — TMS или STM. Они отличаются размером int, и также принятыми кодировками файлов (utf-8/cp1251)
|
||||||
|
|
||||||
|
3. Нажмите **Сканировать переменные**:
|
||||||
|
- Программа проанализирует исходники, указанные в makefile, и найдёт все переменные.
|
||||||
|
- Результат сохранится в двух XML-файлах:
|
||||||
|
- `structs.xml` — информация обо всех структурах и typedef;
|
||||||
|
- `<ваш_файл>.xml` — список всех найденных переменных.
|
||||||
|
|
||||||
|
4. Нажмите **Добавить переменные**:
|
||||||
|
- В **левой таблице** отображаются все найденные переменные.
|
||||||
|
Для добавления переменной в проект дважды кликните по ней или нажмите кнопку `>`, чтобы переместить в правую таблицу.
|
||||||
|
- В **правой таблице** находятся переменные, выбранные для использования.
|
||||||
|
Чтобы убрать переменную из проекта, переместите её обратно в левую таблицу двойным кликом или кнопкой `<`.
|
||||||
|
- После выбора переменных нажмите **Применить**, чтобы обновить основной список переменных и включить их в проект.
|
||||||
|
|
||||||
|
5. Настройте параметры выбранных переменных:
|
||||||
|
- **En** — включение или отключение переменной для генерации;
|
||||||
|
- **Base Type** — базовый тип переменной (например, int8, uint16 и т.д.);
|
||||||
|
- **IQ Type** — формат IQ, если применимо;
|
||||||
|
- **Return Type** — формат возвращаемого значения (IQ-тип или целочисленный);
|
||||||
|
- **Shortname** — короткое имя переменной для для терминалки.
|
||||||
|
|
||||||
|
Все параметры выбираются из выпадающих списков, которые можно настроить, чтобы отображались только нужные опции.
|
||||||
|
|
||||||
|
6. Нажмите **Сгенерировать файл** для создания файла `debug_vars.c` с выбранными переменными.
|
||||||
|
---
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- Загрузка и сохранение настроек переменных в XML-файлах.
|
||||||
|
- Автоматическое определение исходных файлов с переменными для удобства работы.
|
||||||
|
- Редактирование переменных: включение, короткого имени и типов через удобные списки.
|
||||||
|
- Подсветка ошибок при вводе (неправильные имена, слишком длинные короткие имена).
|
||||||
|
- Быстрая фильтрация переменных по столбцам.
|
||||||
|
- Автоматическая генерация файла debug_vars.c с выбранными переменными.
|
||||||
|
- Возможность сразу открыть сгенерированный файл в редакторе.
|
||||||
|
- Умное автодополнение имён переменных и полей структур.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Пример XML-файла
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<project proj_path="C:/myproj" makefile_path="Debug/Makefile" structs_path="Src/DebugTools/structs.xml">
|
||||||
|
<variables>
|
||||||
|
<var name="g_myvar">
|
||||||
|
<enable>true</enable>
|
||||||
|
<show_var>true</show_var>
|
||||||
|
<shortname>myv</shortname>
|
||||||
|
<pt_type>pt_float</pt_type>
|
||||||
|
<iq_type>t_iq24</iq_type>
|
||||||
|
<return_type>t_iq24</return_type>
|
||||||
|
<type>float</type>
|
||||||
|
<file>Src/main/main.c</file>
|
||||||
|
<extern>true</extern>
|
||||||
|
<static>false</static>
|
||||||
|
</var>
|
||||||
|
</variables>
|
||||||
|
</project>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
# Для разработчиков
|
||||||
|
|
||||||
|
### Структура проекта:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Src
|
||||||
|
├── build/
|
||||||
|
│ └── build_and_clean.py # Билдинг проекта в .exe (через nuitka или pyinstaller)
|
||||||
|
├── DebugVarEdit_GUI.py # Главное окно
|
||||||
|
├── var_table.py # Таблица выбранных переменных
|
||||||
|
├── var_selector_window.py # Окно выбора переменных
|
||||||
|
├── var_selector_table.py # Таблица переменных в окне выбора переменных
|
||||||
|
├── scan_progress_gui.py # Отображение процесса сканирования переменных
|
||||||
|
├── scan_vars.py # Сканирование переменных среди .c/.h файлов
|
||||||
|
├── generate_debug_vars.py # Генерация debug_vars.c
|
||||||
|
├── myXML.py # Утилиты для XML
|
||||||
|
├── makefile_parser.py # Парсинг makefile на .c/.h файлы
|
||||||
|
├── var_setup.py # Подготовка переменных для окна выбора переменных
|
||||||
|
├── libclang.dll # Бибилиотека clang
|
||||||
|
├── icon.ico # Иконка
|
||||||
|
```
|
||||||
|
|
||||||
|
### Зависимости
|
||||||
|
|
||||||
|
Для запуска приложения:
|
||||||
|
- **Python 3.7+**
|
||||||
|
- **clang** — используется для парсинга C-кода (требуется `libclang.dll`, лежит в папке Src)
|
||||||
|
- **PySide2** — GUI-фреймворк
|
||||||
|
- **lxml** — работа с XML
|
||||||
|
> Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7
|
||||||
|
|
||||||
|
Для сборки `.exe`:
|
||||||
|
- **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей
|
||||||
|
- **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен для запуска `.exe`)
|
||||||
|
|
||||||
|
|
||||||
|
### Сборка:
|
||||||
|
Если вы хотите собрать `DebugVarEdit.exe` самостоятельно из исходников, используйте скрипт **build/build_and_clean.py**. Он автоматически собирает проект с помощью Nuitka или PyInstaller:
|
||||||
|
- Собирает проект в `DebugVarEdit.exe` в корневой папке.
|
||||||
|
- Включает:
|
||||||
|
- все необходимые `.dll` (например, `libclang.dll`),
|
||||||
|
- иконку (`icon.ico`),
|
||||||
|
- плагины PySide2.
|
||||||
|
- Очищает временные папки после сборки:
|
||||||
|
- `build_temp`
|
||||||
|
- `__pycache__`
|
||||||
|
- `DebugVarEdit_GUI.*`
|
||||||
|
|
||||||
|
> Все пути, имена файлов, временные папки и выбор между Nuitka и PyInstaller можно настроить в начале файла `build_and_clean.py`.
|
||||||
|
|
||||||
|
### Установка зависимостей
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install clang PySide2 lxml nuitka pyinstaller
|
||||||
|
```
|
||||||
678
Src/DebugVarEdit_GUI.py
Normal file
678
Src/DebugVarEdit_GUI.py
Normal file
@@ -0,0 +1,678 @@
|
|||||||
|
# build command
|
||||||
|
# pyinstaller --onefile --name DebugVarEdit --add-binary "build/libclang.dll;build" --distpath ./ --workpath ./build_temp --specpath ./build_temp var_setup_GUI.py
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import lxml.etree as ET
|
||||||
|
from generate_debug_vars import type_map, choose_type_map
|
||||||
|
from enum import IntEnum
|
||||||
|
import threading
|
||||||
|
from generate_debug_vars import run_generate
|
||||||
|
import var_setup
|
||||||
|
from var_selector_window import VariableSelectorDialog
|
||||||
|
from var_table import VariableTableWidget, rows
|
||||||
|
from scan_progress_gui import ProcessOutputWindow
|
||||||
|
import scan_vars
|
||||||
|
import myXML
|
||||||
|
import time
|
||||||
|
|
||||||
|
from PySide2.QtWidgets import (
|
||||||
|
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
||||||
|
QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||||
|
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit,
|
||||||
|
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView,
|
||||||
|
QMenuBar, QMenu, QAction
|
||||||
|
)
|
||||||
|
from PySide2.QtGui import QTextCursor, QKeyEvent, QIcon, QFont
|
||||||
|
from PySide2.QtCore import Qt, QProcess, QObject, Signal, QSettings
|
||||||
|
|
||||||
|
|
||||||
|
var_edit_title = "Редактор переменных для отладки"
|
||||||
|
xml_path_title = "Путь к XML:"
|
||||||
|
proj_path_title = "Путь к проекту:"
|
||||||
|
makefile_path_title = "Пусть к makefile (относительно проекта)"
|
||||||
|
output_path_title = "Путь для для debug_vars.c:"
|
||||||
|
scan_title = "Сканировать переменные"
|
||||||
|
build_title = "Сгенерировать файл"
|
||||||
|
add_vars_title = "Добавить переменные"
|
||||||
|
open_output_title = "Открыть файл"
|
||||||
|
|
||||||
|
def set_sub_elem_text(parent, tag, text):
|
||||||
|
el = parent.find(tag)
|
||||||
|
if el is None:
|
||||||
|
el = ET.SubElement(parent, tag)
|
||||||
|
el.text = str(text)
|
||||||
|
|
||||||
|
# 3. UI: таблица с переменными
|
||||||
|
class VarEditor(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.vars_list = []
|
||||||
|
self.structs = {}
|
||||||
|
self.typedef_map = {}
|
||||||
|
|
||||||
|
self.proj_path = None
|
||||||
|
self.xml_path = None
|
||||||
|
self.makefile_path = None
|
||||||
|
self.structs_path = None
|
||||||
|
self.output_path = None
|
||||||
|
self._updating = False # Флаг блокировки рекурсии
|
||||||
|
self._resizing = False # флаг блокировки повторного вызова
|
||||||
|
self.target = 'TMS'
|
||||||
|
self.initUI()
|
||||||
|
|
||||||
|
def initUI(self):
|
||||||
|
self.setWindowTitle(var_edit_title)
|
||||||
|
|
||||||
|
base_path = scan_vars.get_base_path()
|
||||||
|
icon_path = os.path.join(base_path, "icon.ico")
|
||||||
|
if os.path.exists(icon_path):
|
||||||
|
self.setWindowIcon(QIcon(icon_path))
|
||||||
|
|
||||||
|
# --- Поля ввода пути проекта и XML ---
|
||||||
|
|
||||||
|
# XML Output
|
||||||
|
xml_layout = QHBoxLayout()
|
||||||
|
xml_layout.addWidget(QLabel(xml_path_title))
|
||||||
|
self.xml_output_edit = QLineEdit()
|
||||||
|
self.xml_output_edit.returnPressed.connect(self.update)
|
||||||
|
self.xml_output_edit.textChanged.connect(self.__on_xml_path_changed)
|
||||||
|
xml_layout.addWidget(self.xml_output_edit)
|
||||||
|
btn_xml_browse = QPushButton("...")
|
||||||
|
btn_xml_browse.setFixedWidth(30)
|
||||||
|
xml_layout.addWidget(btn_xml_browse)
|
||||||
|
btn_xml_browse.clicked.connect(self.__browse_xml_output)
|
||||||
|
|
||||||
|
# Project Path
|
||||||
|
proj_layout = QHBoxLayout()
|
||||||
|
proj_layout.addWidget(QLabel(proj_path_title))
|
||||||
|
self.proj_path_edit = QLineEdit()
|
||||||
|
self.proj_path_edit.returnPressed.connect(self.update)
|
||||||
|
self.proj_path_edit.textChanged.connect(self.__on_proj_path_changed)
|
||||||
|
proj_layout.addWidget(self.proj_path_edit)
|
||||||
|
btn_proj_browse = QPushButton("...")
|
||||||
|
btn_proj_browse.setFixedWidth(30)
|
||||||
|
proj_layout.addWidget(btn_proj_browse)
|
||||||
|
btn_proj_browse.clicked.connect(self.__browse_proj_path)
|
||||||
|
|
||||||
|
# Makefile Path
|
||||||
|
makefile_layout = QHBoxLayout()
|
||||||
|
makefile_layout.addWidget(QLabel(makefile_path_title))
|
||||||
|
self.makefile_edit = QLineEdit()
|
||||||
|
self.makefile_edit.returnPressed.connect(self.update)
|
||||||
|
self.makefile_edit.textChanged.connect(self.__on_makefile_path_changed)
|
||||||
|
makefile_layout.addWidget(self.makefile_edit)
|
||||||
|
btn_makefile_browse = QPushButton("...")
|
||||||
|
btn_makefile_browse.setFixedWidth(30)
|
||||||
|
makefile_layout.addWidget(btn_makefile_browse)
|
||||||
|
btn_makefile_browse.clicked.connect(self.__browse_makefile)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Source Output File/Directory
|
||||||
|
source_output_layout = QHBoxLayout()
|
||||||
|
source_output_layout.addWidget(QLabel(output_path_title))
|
||||||
|
self.source_output_edit = QLineEdit()
|
||||||
|
source_output_layout.addWidget(self.source_output_edit)
|
||||||
|
btn_source_output_browse = QPushButton("...")
|
||||||
|
btn_source_output_browse.setFixedWidth(30)
|
||||||
|
source_output_layout.addWidget(btn_source_output_browse)
|
||||||
|
btn_source_output_browse.clicked.connect(self.__browse_source_output)
|
||||||
|
|
||||||
|
|
||||||
|
self.btn_update_vars = QPushButton(scan_title)
|
||||||
|
self.btn_update_vars.clicked.connect(self.update_vars_data)
|
||||||
|
|
||||||
|
# Добавляем чекбокс для выбора типовой карты
|
||||||
|
# --- Создаем верхнее меню ---
|
||||||
|
menubar = QMenuBar(self)
|
||||||
|
menubar.setToolTip('Разные размеры int и кодировки файлов')
|
||||||
|
self.target_menu = QMenu("МК:", menubar)
|
||||||
|
# Создаем действия для выбора Target
|
||||||
|
self.action_tms = QAction("TMS", self, checkable=True)
|
||||||
|
self.action_stm = QAction("STM", self, checkable=True)
|
||||||
|
# Инициализируем QSettings с именем организации и приложения
|
||||||
|
self.settings = QSettings("SET", "DebugVarEdit_MainWindow")
|
||||||
|
# Восстанавливаем сохранённое состояние, если есть
|
||||||
|
mcu = self.settings.value("mcu_choosen", True, type=str)
|
||||||
|
self.on_target_selected(mcu)
|
||||||
|
|
||||||
|
self.target_menu.setToolTip(f'TMS: Размер int 16 бит. Кодировка cp1251\nSTM: Размер int 32 бита. Кодировка utf-8')
|
||||||
|
# Группируем действия чтобы выбирался только один
|
||||||
|
self.action_tms.triggered.connect(lambda: self.on_target_selected("TMS"))
|
||||||
|
self.action_tms.setToolTip('Размер int 16 бит. Кодировка cp1251')
|
||||||
|
self.action_stm.triggered.connect(lambda: self.on_target_selected("STM"))
|
||||||
|
self.action_stm.setToolTip('Размер int 32 бита. Кодировка utf-8')
|
||||||
|
|
||||||
|
self.target_menu.addAction(self.action_tms)
|
||||||
|
self.target_menu.addAction(self.action_stm)
|
||||||
|
|
||||||
|
menubar.addMenu(self.target_menu)
|
||||||
|
|
||||||
|
# Кнопка сохранения
|
||||||
|
btn_save = QPushButton(build_title)
|
||||||
|
btn_save.clicked.connect(self.save_build)
|
||||||
|
|
||||||
|
# Кнопка добавления переменных
|
||||||
|
self.btn_add_vars = QPushButton(add_vars_title)
|
||||||
|
self.btn_add_vars.clicked.connect(self.__open_variable_selector)
|
||||||
|
|
||||||
|
# Кнопка открыть output-файл с выбором программы
|
||||||
|
btn_open_output = QPushButton(open_output_title)
|
||||||
|
btn_open_output.clicked.connect(self.__open_output_file_with_program)
|
||||||
|
# Таблица
|
||||||
|
self.table = VariableTableWidget()
|
||||||
|
# Основной layout
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.setMenuBar(menubar) # прикрепляем menubar в layout сверху
|
||||||
|
layout.addLayout(xml_layout)
|
||||||
|
layout.addLayout(proj_layout)
|
||||||
|
layout.addLayout(makefile_layout)
|
||||||
|
layout.addWidget(self.btn_update_vars)
|
||||||
|
layout.addWidget(self.table)
|
||||||
|
layout.addWidget(self.btn_add_vars)
|
||||||
|
layout.addLayout(source_output_layout)
|
||||||
|
layout.addWidget(btn_save)
|
||||||
|
layout.addWidget(btn_open_output)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
def on_target_selected(self, target):
|
||||||
|
self.target_menu.setTitle(f'МК: {target}')
|
||||||
|
self.settings.setValue("mcu_choosen", target)
|
||||||
|
self.target = target.lower()
|
||||||
|
if self.target == "stm":
|
||||||
|
choose_type_map(True)
|
||||||
|
self.action_stm.setChecked(True)
|
||||||
|
self.action_tms.setChecked(False)
|
||||||
|
else:
|
||||||
|
choose_type_map(False)
|
||||||
|
self.action_tms.setChecked(True)
|
||||||
|
self.action_stm.setChecked(False)
|
||||||
|
|
||||||
|
|
||||||
|
def get_xml_path(self):
|
||||||
|
xml_path = self.xml_output_edit.text().strip()
|
||||||
|
return xml_path
|
||||||
|
|
||||||
|
def get_proj_path(self):
|
||||||
|
proj_path = self.proj_path_edit.text().strip()
|
||||||
|
return proj_path
|
||||||
|
|
||||||
|
def get_makefile_path(self):
|
||||||
|
proj_path = self.get_proj_path()
|
||||||
|
rel_makefile_path = self.makefile_edit.text().strip()
|
||||||
|
if not rel_makefile_path:
|
||||||
|
return None
|
||||||
|
makefile_path = myXML.make_absolute_path(rel_makefile_path, proj_path)
|
||||||
|
return makefile_path
|
||||||
|
|
||||||
|
def get_struct_path(self):
|
||||||
|
proj_path = self.get_proj_path()
|
||||||
|
xml_path = self.get_xml_path()
|
||||||
|
root, tree = myXML.safe_parse_xml(xml_path)
|
||||||
|
if root is None:
|
||||||
|
return
|
||||||
|
# --- structs_path из атрибута ---
|
||||||
|
structs_path = root.attrib.get('structs_path', '').strip()
|
||||||
|
structs_path_full = myXML.make_absolute_path(structs_path, proj_path)
|
||||||
|
if structs_path_full and os.path.isfile(structs_path_full):
|
||||||
|
structs_path = structs_path_full
|
||||||
|
else:
|
||||||
|
structs_path = None
|
||||||
|
return structs_path
|
||||||
|
|
||||||
|
def get_output_path(self):
|
||||||
|
output_path = os.path.abspath(self.source_output_edit.text().strip())
|
||||||
|
return output_path
|
||||||
|
|
||||||
|
def update_all_paths(self):
|
||||||
|
self.proj_path = self.get_proj_path()
|
||||||
|
self.xml_path = self.get_xml_path()
|
||||||
|
self.makefile_path = self.get_makefile_path()
|
||||||
|
self.structs_path = self.get_struct_path()
|
||||||
|
self.output_path = self.get_output_path()
|
||||||
|
|
||||||
|
|
||||||
|
def update_vars_data(self):
|
||||||
|
self.update_all_paths()
|
||||||
|
|
||||||
|
if not self.proj_path or not self.xml_path:
|
||||||
|
QMessageBox.warning(self, "Ошибка", "Укажите пути проекта и XML.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not os.path.isfile(self.makefile_path):
|
||||||
|
QMessageBox.warning(self, "Ошибка", f"Makefile не найден:\n{self.makefile_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# Создаём окно с кнопкой "Готово"
|
||||||
|
self.proc_win = ProcessOutputWindow(self.proj_path, self.makefile_path, self.xml_path,
|
||||||
|
self.__after_scan_vars_finished, self)
|
||||||
|
self.proc_win.start_scan()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def save_build(self):
|
||||||
|
vars_out = []
|
||||||
|
for row in range(self.table.rowCount()):
|
||||||
|
include_cb = self.table.cellWidget(row, rows.include)
|
||||||
|
if not include_cb.isChecked():
|
||||||
|
continue
|
||||||
|
name_edit = self.table.cellWidget(row, rows.name)
|
||||||
|
pt_type_combo = self.table.cellWidget(row, rows.pt_type)
|
||||||
|
iq_combo = self.table.cellWidget(row, rows.iq_type)
|
||||||
|
ret_combo = self.table.cellWidget(row, rows.ret_type)
|
||||||
|
short_name_edit = self.table.cellWidget(row, rows.short_name)
|
||||||
|
|
||||||
|
var_data = {
|
||||||
|
'name': name_edit.text(),
|
||||||
|
'type': 'pt_' + pt_type_combo.currentText(),
|
||||||
|
'iq_type': 't_' + iq_combo.currentText(),
|
||||||
|
'return_type': 't_' + ret_combo.currentText() if ret_combo.currentText() else 't_iq_none',
|
||||||
|
'short_name': short_name_edit.text(),
|
||||||
|
}
|
||||||
|
vars_out.append(var_data)
|
||||||
|
|
||||||
|
self.update_all_paths()
|
||||||
|
|
||||||
|
if not self.proj_path or not self.xml_path or not self.output_path:
|
||||||
|
QMessageBox.warning(self, "Ошибка", f"Заполните: {xml_path_title[:-1]}, {proj_path_title[:-1]}, {output_path_title[:-1]}.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
run_generate(self.proj_path, self.xml_path, self.output_path, self.table._shortname_size)
|
||||||
|
QMessageBox.information(self, "Готово", "Файл debug_vars.c успешно сгенерирован.")
|
||||||
|
self.update()
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "Ошибка при генерации", str(e))
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, force=0):
|
||||||
|
if self._updating and (force==0):
|
||||||
|
return # Уже в процессе обновления — выходим, чтобы избежать рекурсии
|
||||||
|
self._updating = True
|
||||||
|
|
||||||
|
self.update_all_paths()
|
||||||
|
try:
|
||||||
|
if self.xml_path and not os.path.isfile(self.xml_path):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
root, tree = myXML.safe_parse_xml(self.xml_path)
|
||||||
|
if root is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.proj_path:
|
||||||
|
# Если в поле ничего нет, пробуем взять из XML
|
||||||
|
proj_path_from_xml = root.attrib.get('proj_path', '').strip()
|
||||||
|
if proj_path_from_xml and os.path.isdir(proj_path_from_xml):
|
||||||
|
self.proj_path = proj_path_from_xml
|
||||||
|
self.proj_path_edit.setText(proj_path_from_xml)
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"Внимание",
|
||||||
|
"Путь к проекту не найден или не существует.\n"
|
||||||
|
f"Пожалуйста, укажите его вручную в поле '{proj_path_title[:-1]}'."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if not os.path.isdir(self.proj_path):
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"Внимание",
|
||||||
|
f"Указанный путь к проекту не существует:\n{self.proj_path}\n"
|
||||||
|
"Пожалуйста, исправьте путь в поле '{proj_path_title[:-1]}'."
|
||||||
|
)
|
||||||
|
|
||||||
|
if not self.makefile_path and self.proj_path and os.path.isdir(self.proj_path):
|
||||||
|
makefile_path = root.attrib.get('makefile_path', '').strip()
|
||||||
|
makefile_path_full = myXML.make_absolute_path(makefile_path, self.proj_path)
|
||||||
|
if os.path.isfile(makefile_path_full):
|
||||||
|
# Обновляем edit-поле на относительный путь, абсолют сохраняем
|
||||||
|
self.makefile_path = makefile_path_full
|
||||||
|
self.makefile_edit.setText(makefile_path)
|
||||||
|
else:
|
||||||
|
self.makefile_path = None
|
||||||
|
self.makefile_edit.setText("")
|
||||||
|
|
||||||
|
|
||||||
|
# --- structs_path из атрибута ---
|
||||||
|
structs_path = root.attrib.get('structs_path', '').strip()
|
||||||
|
structs_path_full = myXML.make_absolute_path(structs_path, self.proj_path)
|
||||||
|
if structs_path_full and os.path.isfile(structs_path_full):
|
||||||
|
self.structs_path = structs_path_full
|
||||||
|
self.structs, self.typedef_map = var_setup.parse_structs(structs_path_full)
|
||||||
|
else:
|
||||||
|
self.structs_path = None
|
||||||
|
|
||||||
|
self.vars_list = var_setup.parse_vars(self.xml_path, self.typedef_map)
|
||||||
|
self.table.populate(self.vars_list, self.structs, self.write_to_xml)
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
|
||||||
|
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self._updating = False # Снимаем блокировку при выходе из функции
|
||||||
|
|
||||||
|
def __browse_proj_path(self):
|
||||||
|
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку проекта")
|
||||||
|
if dir_path:
|
||||||
|
self.proj_path_edit.setText(dir_path)
|
||||||
|
self.proj_path = dir_path
|
||||||
|
|
||||||
|
# Сброс makefile, если proj_path изменился
|
||||||
|
if not os.path.isdir(dir_path):
|
||||||
|
self.makefile_path = None
|
||||||
|
self.makefile_edit.setText("")
|
||||||
|
else:
|
||||||
|
if self.makefile_path and os.path.isfile(self.makefile_path):
|
||||||
|
rel_path = myXML.make_relative_path(self.makefile_path, dir_path)
|
||||||
|
self.makefile_edit.setText(rel_path)
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
if self.makefile_path and self.proj_path:
|
||||||
|
path = myXML.make_relative_path(self.makefile_path, self.proj_path)
|
||||||
|
self.makefile_edit.setText(path)
|
||||||
|
self.makefile_path = path
|
||||||
|
|
||||||
|
def __browse_xml_output(self):
|
||||||
|
dialog = QFileDialog(self, "Выберите или создайте XML-файл")
|
||||||
|
dialog.setAcceptMode(QFileDialog.AcceptSave)
|
||||||
|
dialog.setNameFilter("XML files (*.xml);;All Files (*)")
|
||||||
|
dialog.setDefaultSuffix("xml")
|
||||||
|
dialog.setOption(QFileDialog.DontConfirmOverwrite, True) # ⚠️ Не спрашивать про перезапись
|
||||||
|
if dialog.exec_():
|
||||||
|
file_path = dialog.selectedFiles()[0]
|
||||||
|
if not file_path.endswith(".xml"):
|
||||||
|
file_path += ".xml"
|
||||||
|
self.xml_output_edit.setText(file_path)
|
||||||
|
self.xml_path = file_path
|
||||||
|
|
||||||
|
def keyPressEvent(self, event: QKeyEvent):
|
||||||
|
if event.key() == Qt.Key_Delete:
|
||||||
|
self.delete_selected_rows()
|
||||||
|
else:
|
||||||
|
super().keyPressEvent(event)
|
||||||
|
|
||||||
|
def __browse_makefile(self):
|
||||||
|
if self.target == 'stm':
|
||||||
|
file_filter = "Makefile или Keil-проект (*.uvprojx *.uvproj makefile);;Все файлы (*)"
|
||||||
|
dialog_title = "Выберите Makefile или Keil-проект"
|
||||||
|
else: # 'TMS' или по умолчанию
|
||||||
|
file_filter = "Makefile (makefile);;Все файлы (*)"
|
||||||
|
dialog_title = "Выберите Makefile"
|
||||||
|
|
||||||
|
file_path, _ = QFileDialog.getOpenFileName(
|
||||||
|
self,
|
||||||
|
dialog_title,
|
||||||
|
filter=file_filter
|
||||||
|
)
|
||||||
|
if file_path:
|
||||||
|
if self.proj_path:
|
||||||
|
path = myXML.make_relative_path(file_path, self.proj_path)
|
||||||
|
else:
|
||||||
|
path = file_path
|
||||||
|
self.makefile_edit.setText(path)
|
||||||
|
self.makefile_path = path
|
||||||
|
|
||||||
|
def __browse_source_output(self):
|
||||||
|
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку для debug_vars.c")
|
||||||
|
if dir_path:
|
||||||
|
self.source_output_edit.setText(dir_path)
|
||||||
|
self.output_path = dir_path
|
||||||
|
else:
|
||||||
|
self.output_path = ''
|
||||||
|
|
||||||
|
|
||||||
|
def __on_xml_path_changed(self, _):
|
||||||
|
self.xml_path = self.get_xml_path()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def __on_proj_path_changed(self, _):
|
||||||
|
self.proj_path = self.get_proj_path()
|
||||||
|
|
||||||
|
if not os.path.isdir(self.proj_path):
|
||||||
|
self.makefile_path = None
|
||||||
|
self.makefile_edit.setText("")
|
||||||
|
return # Преждевременно выходим, если проект не существует
|
||||||
|
|
||||||
|
# Обновим путь к makefile, если он уже задан и абсолютен
|
||||||
|
if self.makefile_path and os.path.isfile(self.makefile_path):
|
||||||
|
rel_path = myXML.make_relative_path(self.makefile_path, self.proj_path)
|
||||||
|
self.makefile_edit.setText(rel_path)
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def __on_makefile_path_changed(self, _):
|
||||||
|
self.makefile_path = self.get_makefile_path()
|
||||||
|
if self.makefile_path and self.proj_path:
|
||||||
|
path = myXML.make_relative_path(self.makefile_path, self.proj_path)
|
||||||
|
self.makefile_edit.setText(path)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
|
||||||
|
def __after_scan_vars_finished(self):
|
||||||
|
if not os.path.isfile(self.xml_path):
|
||||||
|
self.makefile_path = None
|
||||||
|
self.structs_path = None
|
||||||
|
self.proj_path = None
|
||||||
|
QMessageBox.critical(self, "Ошибка", f"Файл не найден: {self.xml_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.update(1)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.makefile_path = None
|
||||||
|
self.structs_path = None
|
||||||
|
self.proj_path = None
|
||||||
|
QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить переменные:\n{e}")
|
||||||
|
|
||||||
|
|
||||||
|
def delete_selected_rows(self):
|
||||||
|
# Получаем имена всех выбранных переменных из первого столбца
|
||||||
|
selected_names = self.table.get_selected_var_names()
|
||||||
|
|
||||||
|
if not selected_names:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Меняем флаг show_var по имени
|
||||||
|
for var in self.vars_list:
|
||||||
|
if var.get('name') in selected_names:
|
||||||
|
var['show_var'] = 'false'
|
||||||
|
|
||||||
|
self.table.populate(self.vars_list, self.structs, self.write_to_xml)
|
||||||
|
self.write_to_xml()
|
||||||
|
|
||||||
|
|
||||||
|
def __open_variable_selector(self):
|
||||||
|
self.update()
|
||||||
|
if not self.vars_list:
|
||||||
|
QMessageBox.warning(self, "Нет переменных", f"Сначала загрузите переменные ({scan_title}).")
|
||||||
|
return
|
||||||
|
|
||||||
|
dlg = VariableSelectorDialog(self.table, self.vars_list, self.structs, self.typedef_map, self.xml_path, self)
|
||||||
|
if dlg.exec_():
|
||||||
|
self.write_to_xml()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def write_to_xml(self, dummy=None):
|
||||||
|
t0 = time.time()
|
||||||
|
self.update_all_paths()
|
||||||
|
def get_val(name, default=''):
|
||||||
|
return str(v_table[name] if v_table and name in v_table else v.get(name, default))
|
||||||
|
|
||||||
|
def element_differs(elem, values: dict):
|
||||||
|
for tag, new_val in values.items():
|
||||||
|
current_elem = elem.find(tag)
|
||||||
|
current_val = (current_elem.text or '').strip()
|
||||||
|
new_val_str = str(new_val or '').strip()
|
||||||
|
if current_val != new_val_str:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not self.xml_path or not os.path.isfile(self.xml_path):
|
||||||
|
print("XML файл не найден или путь пустой")
|
||||||
|
return
|
||||||
|
if not self.proj_path or not os.path.isdir(self.proj_path):
|
||||||
|
print("Project path не найден или путь пустой")
|
||||||
|
return
|
||||||
|
if not self.makefile_path or not os.path.isfile(self.makefile_path):
|
||||||
|
print("makefile файл не найден или путь пустой")
|
||||||
|
return
|
||||||
|
if os.path.abspath(self.makefile_path) == os.path.abspath(self.proj_path):
|
||||||
|
print("makefile_path совпадает с proj_path — игнор")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
root, tree = myXML.safe_parse_xml(self.xml_path)
|
||||||
|
if root is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
root.set("proj_path", self.proj_path.replace("\\", "/"))
|
||||||
|
|
||||||
|
if self.makefile_path and os.path.isfile(self.makefile_path):
|
||||||
|
rel_makefile = myXML.make_relative_path(self.makefile_path, self.proj_path)
|
||||||
|
# Если результат — абсолютный путь, не записываем
|
||||||
|
if not os.path.isabs(rel_makefile):
|
||||||
|
root.set("makefile_path", rel_makefile)
|
||||||
|
|
||||||
|
if self.structs_path and os.path.isfile(self.structs_path):
|
||||||
|
rel_struct = myXML.make_relative_path(self.structs_path, self.proj_path)
|
||||||
|
root.set("structs_path", rel_struct)
|
||||||
|
if not os.path.isabs(rel_struct):
|
||||||
|
root.set("structs_path", rel_struct)
|
||||||
|
|
||||||
|
t1 = time.time()
|
||||||
|
|
||||||
|
vars_elem = root.find('variables')
|
||||||
|
if vars_elem is None:
|
||||||
|
vars_elem = ET.SubElement(root, 'variables')
|
||||||
|
|
||||||
|
original_info = {}
|
||||||
|
for var_elem in vars_elem.findall('var'):
|
||||||
|
name = var_elem.attrib.get('name')
|
||||||
|
if name:
|
||||||
|
original_info[name] = {
|
||||||
|
'file': var_elem.findtext('file', ''),
|
||||||
|
'extern': var_elem.findtext('extern', ''),
|
||||||
|
'static': var_elem.findtext('static', '')
|
||||||
|
}
|
||||||
|
var_elements_by_name = {ve.attrib.get('name'): ve for ve in vars_elem.findall('var')}
|
||||||
|
|
||||||
|
# Читаем переменные из таблицы (активные/изменённые)
|
||||||
|
table_vars = {v['name']: v for v in self.table.read_data()}
|
||||||
|
# Все переменные (в том числе новые, которых нет в таблице)
|
||||||
|
all_vars_by_name = {v['name']: v for v in self.vars_list}
|
||||||
|
|
||||||
|
# Объединённый список переменных для записи
|
||||||
|
all_names = list(all_vars_by_name.keys())
|
||||||
|
t2 = time.time()
|
||||||
|
for name in all_names:
|
||||||
|
v = all_vars_by_name[name]
|
||||||
|
v_table = table_vars.get(name)
|
||||||
|
var_elem = None
|
||||||
|
|
||||||
|
pt_type_val = get_val('pt_type').lower()
|
||||||
|
if 'arr' in pt_type_val or 'struct' in pt_type_val or 'union' in pt_type_val:
|
||||||
|
continue
|
||||||
|
|
||||||
|
show_var_val = str(v.get('show_var', 'false')).lower()
|
||||||
|
enable_val = get_val('enable').lower()
|
||||||
|
|
||||||
|
# Тут подтягиваем из таблицы, если есть, иначе из v
|
||||||
|
shortname_val = get_val('shortname')
|
||||||
|
iq_type_val = get_val('iq_type')
|
||||||
|
ret_type_val = get_val('return_type')
|
||||||
|
|
||||||
|
|
||||||
|
# file/extern/static: из original_info, либо из v
|
||||||
|
file_val = v.get('file') or original_info.get(name, {}).get('file', '')
|
||||||
|
extern_val = v.get('extern') or original_info.get(name, {}).get('extern', '')
|
||||||
|
static_val = v.get('static') or original_info.get(name, {}).get('static', '')
|
||||||
|
|
||||||
|
values_to_write = {
|
||||||
|
'show_var': show_var_val,
|
||||||
|
'enable': enable_val,
|
||||||
|
'shortname': shortname_val,
|
||||||
|
'pt_type': pt_type_val,
|
||||||
|
'iq_type': iq_type_val,
|
||||||
|
'return_type': ret_type_val,
|
||||||
|
'type': v.get('type', ''),
|
||||||
|
'file': file_val,
|
||||||
|
'extern': extern_val,
|
||||||
|
'static': static_val
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ищем уже существующий <var> в XML
|
||||||
|
var_elem = var_elements_by_name.get(name)
|
||||||
|
# Если элемента нет, это новая переменная — сразу пишем
|
||||||
|
if var_elem is None:
|
||||||
|
var_elem = ET.SubElement(vars_elem, 'var', {'name': name})
|
||||||
|
var_elements_by_name[name] = var_elem
|
||||||
|
write_all = True # обязательно записать все поля
|
||||||
|
else:
|
||||||
|
write_all = element_differs(var_elem, values_to_write)
|
||||||
|
|
||||||
|
if not write_all:
|
||||||
|
continue # Пропускаем, если нет изменений
|
||||||
|
|
||||||
|
for tag, text in values_to_write.items():
|
||||||
|
set_sub_elem_text(var_elem, tag, text)
|
||||||
|
|
||||||
|
t3 = time.time()
|
||||||
|
# Преобразуем дерево в строку
|
||||||
|
myXML.fwrite(root, self.xml_path)
|
||||||
|
self.table.check()
|
||||||
|
t4 = time.time()
|
||||||
|
'''print(f"[T1] parse + set paths: {t1 - t0:.3f} сек")
|
||||||
|
print(f"[T2] prepare variables: {t2 - t1:.3f} сек")
|
||||||
|
print(f"[T3] loop + updates: {t3 - t2:.3f} сек")
|
||||||
|
print(f"[T4] write to file: {t4 - t3:.3f} сек")
|
||||||
|
print(f"[TOTAL] write_to_xml total: {t4 - t0:.3f} сек")'''
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка при сохранении XML: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def __open_output_file_with_program(self):
|
||||||
|
output_path = self.get_output_path()
|
||||||
|
if not output_path:
|
||||||
|
QMessageBox.warning(self,
|
||||||
|
"Ошибка",
|
||||||
|
"Путь к debug_var.c не задан."
|
||||||
|
f"Пожалуйста, укажите его в поле '{output_path_title[:-1]}'.")
|
||||||
|
return
|
||||||
|
|
||||||
|
output_file = os.path.join(output_path, "debug_vars.c")
|
||||||
|
if not os.path.isfile(output_file):
|
||||||
|
QMessageBox.warning(self, "Ошибка", f"Файл не найден:\n{output_file}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Открыть стандартное окно Windows "Открыть с помощью..."
|
||||||
|
subprocess.run([
|
||||||
|
"rundll32.exe",
|
||||||
|
"shell32.dll,OpenAs_RunDLL",
|
||||||
|
output_file
|
||||||
|
], shell=False)
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "Ошибка", f"Не удалось открыть диалог 'Открыть с помощью':\n{e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
editor = VarEditor()
|
||||||
|
editor.resize(900, 600)
|
||||||
|
editor.show()
|
||||||
|
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
55
Src/README_DEVELOP.md
Normal file
55
Src/README_DEVELOP.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Для разработчиков
|
||||||
|
|
||||||
|
### Структура проекта:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Src
|
||||||
|
├── build/
|
||||||
|
│ └── build_and_clean.py # Билдинг проекта в .exe (через nuitka или pyinstaller)
|
||||||
|
├── DebugVarEdit_GUI.py # Главное окно
|
||||||
|
├── var_table.py # Таблица выбранных переменных
|
||||||
|
├── var_selector_window.py # Окно выбора переменных
|
||||||
|
├── var_selector_table.py # Таблица переменных в окне выбора переменных
|
||||||
|
├── scan_progress_gui.py # Отображение процесса сканирования переменных
|
||||||
|
├── scan_vars.py # Сканирование переменных среди .c/.h файлов
|
||||||
|
├── generate_debug_vars.py # Генерация debug_vars.c
|
||||||
|
├── myXML.py # Утилиты для XML
|
||||||
|
├── makefile_parser.py # Парсинг makefile на .c/.h файлы
|
||||||
|
├── var_setup.py # Подготовка переменных для окна выбора переменных
|
||||||
|
├── libclang.dll # Бибилиотека clang
|
||||||
|
├── icon.ico # Иконка
|
||||||
|
```
|
||||||
|
|
||||||
|
### Зависимости
|
||||||
|
|
||||||
|
Для запуска приложения:
|
||||||
|
- **Python 3.7+**
|
||||||
|
- **clang** — используется для парсинга C-кода (требуется `libclang.dll`)
|
||||||
|
- **PySide2** — GUI-фреймворк
|
||||||
|
- **lxml** — работа с XML
|
||||||
|
> Python 3.7 и PySide2 рекомендуется для совместимости с Windows 7
|
||||||
|
|
||||||
|
Для сборки `.exe`:
|
||||||
|
- **Nuitka** — создает полностью автономный `.exe` без внешних зависимостей
|
||||||
|
- **PyInstaller** — создает `.exe` с зависимостью от `pythonXX.dll` (Python должен быть установлен)
|
||||||
|
|
||||||
|
|
||||||
|
### Сборка:
|
||||||
|
Если вы хотите собрать `DebugVarEdit.exe` самостоятельно из исходников, используйте скрипт **build/build_and_clean.py**. Он автоматически собирает проект с помощью Nuitka или PyInstaller:
|
||||||
|
- Собирает проект в `DebugVarEdit.exe` в корневой папке.
|
||||||
|
- Включает:
|
||||||
|
- все необходимые `.dll` (например, `libclang.dll`),
|
||||||
|
- иконку (`icon.ico`),
|
||||||
|
- плагины PySide2.
|
||||||
|
- Очищает временные папки после сборки:
|
||||||
|
- `build_temp`
|
||||||
|
- `__pycache__`
|
||||||
|
- `DebugVarEdit_GUI.*`
|
||||||
|
|
||||||
|
> Все пути, имена файлов, временные папки и выбор между Nuitka и PyInstaller можно настроить в начале файла `build_and_clean.py`.
|
||||||
|
|
||||||
|
### Установка зависимостей
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install PySide2 lxml nuitka pyinstaller
|
||||||
|
```
|
||||||
@@ -1,279 +0,0 @@
|
|||||||
import re
|
|
||||||
from PySide6.QtWidgets import (
|
|
||||||
QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
|
|
||||||
QLineEdit, QLabel, QHeaderView
|
|
||||||
)
|
|
||||||
from PySide6.QtCore import Qt
|
|
||||||
from setupVars import *
|
|
||||||
from scanVars import *
|
|
||||||
|
|
||||||
|
|
||||||
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
|
|
||||||
|
|
||||||
class VariableSelectorDialog(QDialog):
|
|
||||||
def __init__(self, all_vars, structs, typedefs, xml_path=None, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.setWindowTitle("Выбор переменных")
|
|
||||||
self.resize(600, 500)
|
|
||||||
self.selected_names = []
|
|
||||||
|
|
||||||
self.all_vars = all_vars
|
|
||||||
self.structs = structs
|
|
||||||
self.typedefs = typedefs
|
|
||||||
self.expanded_vars = []
|
|
||||||
self.var_map = {v['name']: v for v in all_vars}
|
|
||||||
|
|
||||||
self.xml_path = xml_path # сохраняем путь к xml
|
|
||||||
|
|
||||||
self.search_input = QLineEdit()
|
|
||||||
self.search_input.setPlaceholderText("Поиск по имени переменной...")
|
|
||||||
self.search_input.textChanged.connect(self.filter_tree)
|
|
||||||
|
|
||||||
self.tree = QTreeWidget()
|
|
||||||
self.tree.setHeaderLabels(["Имя переменной", "Тип"])
|
|
||||||
self.tree.setSelectionMode(QTreeWidget.ExtendedSelection)
|
|
||||||
self.tree.setRootIsDecorated(True)
|
|
||||||
self.tree.setUniformRowHeights(True)
|
|
||||||
|
|
||||||
self.tree.setStyleSheet("""
|
|
||||||
QTreeWidget::item:selected {
|
|
||||||
background-color: #87CEFA;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
QTreeWidget::item:hover {
|
|
||||||
background-color: #D3D3D3;
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
|
|
||||||
self.btn_add = QPushButton("Добавить выбранные")
|
|
||||||
self.btn_add.clicked.connect(self.on_add_clicked)
|
|
||||||
|
|
||||||
self.btn_delete = QPushButton("Удалить выбранные")
|
|
||||||
self.btn_delete.clicked.connect(self.on_delete_clicked)
|
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.addWidget(QLabel("Поиск:"))
|
|
||||||
layout.addWidget(self.search_input)
|
|
||||||
layout.addWidget(self.tree)
|
|
||||||
layout.addWidget(self.btn_add)
|
|
||||||
layout.addWidget(self.btn_delete) # Кнопка удаления
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
self.populate_tree()
|
|
||||||
|
|
||||||
|
|
||||||
def add_tree_item_recursively(self, parent, var):
|
|
||||||
"""
|
|
||||||
Рекурсивно добавляет переменную и её дочерние поля в дерево.
|
|
||||||
Если parent == None, добавляет на верхний уровень.
|
|
||||||
"""
|
|
||||||
name = var['name']
|
|
||||||
type_str = var.get('type', '')
|
|
||||||
show_var = var.get('show_var', 'false') == 'true'
|
|
||||||
|
|
||||||
item = QTreeWidgetItem([name, type_str])
|
|
||||||
item.setData(0, Qt.UserRole, name)
|
|
||||||
|
|
||||||
# Делаем bitfield-поля неактивными
|
|
||||||
if "(bitfield:" in type_str:
|
|
||||||
item.setDisabled(True)
|
|
||||||
self.set_tool(item, "Битовые поля недоступны для выбора")
|
|
||||||
|
|
||||||
for i, attr in enumerate(['file', 'extern', 'static']):
|
|
||||||
item.setData(0, Qt.UserRole + 1 + i, var.get(attr))
|
|
||||||
|
|
||||||
if show_var:
|
|
||||||
item.setForeground(0, Qt.gray)
|
|
||||||
item.setForeground(1, Qt.gray)
|
|
||||||
self.set_tool(item, "Уже добавлена")
|
|
||||||
|
|
||||||
if parent is None:
|
|
||||||
self.tree.addTopLevelItem(item)
|
|
||||||
else:
|
|
||||||
parent.addChild(item)
|
|
||||||
|
|
||||||
for child in var.get('children', []):
|
|
||||||
self.add_tree_item_recursively(item, child)
|
|
||||||
|
|
||||||
|
|
||||||
def populate_tree(self):
|
|
||||||
self.tree.clear()
|
|
||||||
|
|
||||||
expanded_vars = expand_vars(self.all_vars, self.structs, self.typedefs)
|
|
||||||
|
|
||||||
for var in expanded_vars:
|
|
||||||
self.add_tree_item_recursively(None, var)
|
|
||||||
|
|
||||||
header = self.tree.header()
|
|
||||||
header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять
|
|
||||||
self.tree.setColumnWidth(0, 400)
|
|
||||||
self.tree.resizeColumnToContents(1)
|
|
||||||
""" header.setSectionResizeMode(0, QHeaderView.Stretch)
|
|
||||||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents) """
|
|
||||||
|
|
||||||
def filter_tree(self):
|
|
||||||
text = self.search_input.text().strip().lower()
|
|
||||||
path_parts = text.split('.') if text else []
|
|
||||||
|
|
||||||
def hide_all(item):
|
|
||||||
item.setHidden(True)
|
|
||||||
for i in range(item.childCount()):
|
|
||||||
hide_all(item.child(i))
|
|
||||||
|
|
||||||
def path_matches_search(name, search_parts):
|
|
||||||
name_parts = name.lower().split('.')
|
|
||||||
if len(name_parts) < len(search_parts):
|
|
||||||
return False
|
|
||||||
for sp, np in zip(search_parts, name_parts):
|
|
||||||
if not np.startswith(sp):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def show_matching_path(item, level=0):
|
|
||||||
name = item.text(0).lower()
|
|
||||||
# Проверяем соответствие до длины path_parts
|
|
||||||
if not path_parts:
|
|
||||||
matched = True
|
|
||||||
else:
|
|
||||||
matched = False
|
|
||||||
# Проверяем совпадение по пути
|
|
||||||
if path_matches_search(name, path_parts[:level+1]):
|
|
||||||
matched = True
|
|
||||||
|
|
||||||
item.setHidden(not matched)
|
|
||||||
|
|
||||||
# Раскрываем, если это не последний уровень поиска
|
|
||||||
if matched and level < len(path_parts) - 1:
|
|
||||||
item.setExpanded(True)
|
|
||||||
else:
|
|
||||||
item.setExpanded(False)
|
|
||||||
|
|
||||||
matched_any_child = False
|
|
||||||
for i in range(item.childCount()):
|
|
||||||
child = item.child(i)
|
|
||||||
if show_matching_path(child, level + 1):
|
|
||||||
matched_any_child = True
|
|
||||||
|
|
||||||
return matched or matched_any_child
|
|
||||||
|
|
||||||
for i in range(self.tree.topLevelItemCount()):
|
|
||||||
item = self.tree.topLevelItem(i)
|
|
||||||
hide_all(item)
|
|
||||||
show_matching_path(item, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def on_add_clicked(self):
|
|
||||||
self.selected_names = []
|
|
||||||
|
|
||||||
for item in self.tree.selectedItems():
|
|
||||||
name = item.text(0) # имя переменной (в колонке 1)
|
|
||||||
type_str = item.text(1) # тип переменной (в колонке 2)
|
|
||||||
|
|
||||||
if not name:
|
|
||||||
continue
|
|
||||||
|
|
||||||
self.selected_names.append((name, type_str))
|
|
||||||
|
|
||||||
if name in self.var_map:
|
|
||||||
# Если переменная уже есть, просто включаем её и показываем
|
|
||||||
var = self.var_map[name]
|
|
||||||
var['show_var'] = 'true'
|
|
||||||
var['enable'] = 'true'
|
|
||||||
else:
|
|
||||||
# Создаём новый элемент переменной
|
|
||||||
# Получаем родительские параметры
|
|
||||||
file_val = item.data(0, Qt.UserRole + 1)
|
|
||||||
extern_val = item.data(0, Qt.UserRole + 2)
|
|
||||||
static_val = item.data(0, Qt.UserRole + 3)
|
|
||||||
|
|
||||||
new_var = {
|
|
||||||
'name': name,
|
|
||||||
'type': type_str,
|
|
||||||
'show_var': 'true',
|
|
||||||
'enable': 'true',
|
|
||||||
'shortname': name,
|
|
||||||
'pt_type': '',
|
|
||||||
'iq_type': '',
|
|
||||||
'return_type': 'iq_none',
|
|
||||||
'file': file_val,
|
|
||||||
'extern': str(extern_val).lower() if extern_val else 'false',
|
|
||||||
'static': str(static_val).lower() if static_val else 'false',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Добавляем в список переменных
|
|
||||||
self.all_vars.append(new_var)
|
|
||||||
self.var_map[name] = new_var # Чтобы в будущем не добавлялось повторно
|
|
||||||
|
|
||||||
self.accept()
|
|
||||||
|
|
||||||
def on_delete_clicked(self):
|
|
||||||
# Деактивируем (удаляем из видимых) выбранные переменные
|
|
||||||
for item in self.tree.selectedItems():
|
|
||||||
name = item.text(0)
|
|
||||||
if not name:
|
|
||||||
continue
|
|
||||||
if name in self.var_map:
|
|
||||||
var = self.var_map[name]
|
|
||||||
var['show_var'] = 'false'
|
|
||||||
var['enable'] = 'false'
|
|
||||||
self.accept()
|
|
||||||
|
|
||||||
|
|
||||||
def set_tool(self, item, text):
|
|
||||||
item.setToolTip(0, text)
|
|
||||||
item.setToolTip(1, text)
|
|
||||||
|
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
|
||||||
if event.key() == Qt.Key_Delete:
|
|
||||||
self.delete_selected_vars()
|
|
||||||
else:
|
|
||||||
super().keyPressEvent(event)
|
|
||||||
|
|
||||||
def delete_selected_vars(self):
|
|
||||||
# Деактивируем (удаляем из видимых) выбранные переменные
|
|
||||||
for item in self.tree.selectedItems():
|
|
||||||
name = item.text(0)
|
|
||||||
if not name:
|
|
||||||
continue
|
|
||||||
if name in self.var_map:
|
|
||||||
var = self.var_map[name]
|
|
||||||
var['show_var'] = 'false'
|
|
||||||
var['enable'] = 'false'
|
|
||||||
|
|
||||||
if not hasattr(self, 'xml_path') or not self.xml_path:
|
|
||||||
from PySide6.QtWidgets import QMessageBox
|
|
||||||
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно удалить переменные.")
|
|
||||||
return
|
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
tree = ET.parse(self.xml_path)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
if root is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
vars_section = root.find('variables')
|
|
||||||
if vars_section is None:
|
|
||||||
return # Нет секции variables — ничего удалять
|
|
||||||
|
|
||||||
selected_names = [item.text(0) for item in self.tree.selectedItems() if item.text(0)]
|
|
||||||
|
|
||||||
removed_any = False
|
|
||||||
for var_elem in vars_section.findall('var'):
|
|
||||||
name = var_elem.attrib.get('name')
|
|
||||||
if name in selected_names:
|
|
||||||
vars_section.remove(var_elem)
|
|
||||||
removed_any = True
|
|
||||||
if name in self.var_map:
|
|
||||||
del self.var_map[name]
|
|
||||||
# Удаляем элементы из списка на месте
|
|
||||||
self.all_vars[:] = [v for v in self.all_vars if v['name'] != name]
|
|
||||||
|
|
||||||
|
|
||||||
if removed_any:
|
|
||||||
ET.indent(tree, space=" ", level=0)
|
|
||||||
tree.write(self.xml_path, encoding='utf-8', xml_declaration=True)
|
|
||||||
|
|
||||||
|
|
||||||
self.populate_tree()
|
|
||||||
111
Src/build/build_and_clean.py
Normal file
111
Src/build/build_and_clean.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import PySide2
|
||||||
|
from PyInstaller.utils.hooks import collect_data_files
|
||||||
|
# install: pip install PySide2 lxml nuitka pyinstaller
|
||||||
|
# - PyInstaller
|
||||||
|
# - nuitka
|
||||||
|
# - PySide2
|
||||||
|
# - clang
|
||||||
|
|
||||||
|
# === Конфигурация ===
|
||||||
|
USE_NUITKA = True # True — сборка через Nuitka, False — через PyInstaller
|
||||||
|
|
||||||
|
SRC_PATH = Path("./Src/")
|
||||||
|
SCRIPT_PATH = SRC_PATH / "DebugVarEdit_GUI.py"
|
||||||
|
OUTPUT_NAME = "DebugVarEdit"
|
||||||
|
|
||||||
|
DIST_PATH = Path("./").resolve()
|
||||||
|
WORK_PATH = Path("./build_temp").resolve()
|
||||||
|
SPEC_PATH = WORK_PATH
|
||||||
|
ICON_PATH = SRC_PATH / "icon.png"
|
||||||
|
ICON_ICO_PATH = SRC_PATH / "icon.ico"
|
||||||
|
|
||||||
|
TEMP_FOLDERS = [
|
||||||
|
"build_temp",
|
||||||
|
"__pycache__",
|
||||||
|
"DebugVarEdit_GUI.build",
|
||||||
|
"DebugVarEdit_GUI.onefile-build",
|
||||||
|
"DebugVarEdit_GUI.dist"
|
||||||
|
]
|
||||||
|
# === Пути к DLL и прочим зависимостям ===
|
||||||
|
LIBS = {
|
||||||
|
"libclang.dll": SRC_PATH / "libclang.dll"
|
||||||
|
}
|
||||||
|
|
||||||
|
# === PySide2 плагины ===
|
||||||
|
PySide2_path = Path(PySide2.__file__).parent
|
||||||
|
datas = []
|
||||||
|
datas += collect_data_files('PySide2', includes=['plugins/platforms/*'])
|
||||||
|
datas += collect_data_files('PySide2', includes=['plugins/styles/*'])
|
||||||
|
datas += collect_data_files('PySide2', includes=['plugins/imageformats/*'])
|
||||||
|
|
||||||
|
add_data_list = [f"{src};{dest}" for src, dest in datas]
|
||||||
|
|
||||||
|
# Проверка наличия DLL и добавление
|
||||||
|
add_binary_list = []
|
||||||
|
for name, path in LIBS.items():
|
||||||
|
if path.exists():
|
||||||
|
add_binary_list.append(f"{str(path)};{name}")
|
||||||
|
else:
|
||||||
|
print(f"WARNING: {path.name} не найден — он не будет включён в сборку")
|
||||||
|
|
||||||
|
def clean_temp():
|
||||||
|
for folder in TEMP_FOLDERS:
|
||||||
|
path = Path(folder)
|
||||||
|
if path.exists():
|
||||||
|
shutil.rmtree(path, ignore_errors=True)
|
||||||
|
|
||||||
|
if USE_NUITKA:
|
||||||
|
# Формируем include-data-file только для DLL
|
||||||
|
include_data_files = [f"--include-data-file={str(path)}={name}" for name, path in LIBS.items() if path.exists()]
|
||||||
|
|
||||||
|
# Добавляем icon.ico как встроенный ресурс
|
||||||
|
if ICON_ICO_PATH.exists():
|
||||||
|
include_data_files.append(f"--include-data-file={ICON_ICO_PATH}=icon.ico")
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
"python", "-m", "nuitka",
|
||||||
|
"--standalone",
|
||||||
|
"--onefile",
|
||||||
|
"--enable-plugin=pyside2",
|
||||||
|
"--windows-console-mode=disable",
|
||||||
|
f"--output-dir={DIST_PATH}",
|
||||||
|
f"--output-filename={OUTPUT_NAME}.exe",
|
||||||
|
f"--windows-icon-from-ico={ICON_ICO_PATH}",
|
||||||
|
*include_data_files,
|
||||||
|
str(SCRIPT_PATH)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# PyInstaller
|
||||||
|
cmd = [
|
||||||
|
"pyinstaller",
|
||||||
|
"--name", OUTPUT_NAME,
|
||||||
|
"--distpath", str(DIST_PATH),
|
||||||
|
"--workpath", str(WORK_PATH),
|
||||||
|
"--specpath", str(SPEC_PATH),
|
||||||
|
"--windowed",
|
||||||
|
f"--icon={ICON_ICO_PATH}",
|
||||||
|
"--hidden-import=PySide2.QtWidgets",
|
||||||
|
"--hidden-import=PySide2.QtGui",
|
||||||
|
"--hidden-import=PySide2.QtCore",
|
||||||
|
*[arg for b in add_binary_list for arg in ("--add-binary", b)],
|
||||||
|
*[arg for d in add_data_list for arg in ("--add-data", d)],
|
||||||
|
str(SCRIPT_PATH)
|
||||||
|
]
|
||||||
|
|
||||||
|
# === Запуск сборки ===
|
||||||
|
print("Выполняется сборка с помощью " + ("Nuitka" if USE_NUITKA else "PyInstaller"))
|
||||||
|
print(" ".join(cmd))
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(cmd, check=True)
|
||||||
|
print("\nСборка успешно завершена!")
|
||||||
|
|
||||||
|
# Удаление временных папок после сборки
|
||||||
|
clean_temp()
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("\nОшибка при сборке.")
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
# build command
|
# build command
|
||||||
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build generateVars.py
|
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build generate_debug_vars.py
|
||||||
# start script
|
# start script
|
||||||
# generateVars.exe F:\Work\Projects\TMS\TMS_new_bus\ Src/DebugTools/vars.xml Src/DebugTools
|
# generate_debug_vars.exe F:\Work\Projects\TMS\TMS_new_bus\ Src/DebugTools/vars.xml Src/DebugTools
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import xml.etree.ElementTree as ET
|
import lxml.etree as ET
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from xml.dom import minidom
|
||||||
|
import myXML
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
shortnameSize = 10
|
||||||
|
|
||||||
# === Словарь соответствия типов XML → DebugVarType_t ===
|
# === Словарь соответствия типов XML → DebugVarType_t ===
|
||||||
type_map = dict([
|
type_map_tms = dict([
|
||||||
*[(k, 'pt_int8') for k in ('signed char', 'char')],
|
*[(k, 'pt_int8') for k in ('signed char', 'char')],
|
||||||
*[(k, 'pt_int16') for k in ('int', 'int16', 'short')],
|
*[(k, 'pt_int16') for k in ('int', 'int16', 'short')],
|
||||||
*[(k, 'pt_int32') for k in ('long', 'int32', '_iqx')],
|
*[(k, 'pt_int32') for k in ('long', 'int32', '_iqx')],
|
||||||
@@ -50,6 +53,150 @@ type_map = dict([
|
|||||||
('struct[]', 'pt_arr_struct'),
|
('struct[]', 'pt_arr_struct'),
|
||||||
('union[]', 'pt_arr_union'),
|
('union[]', 'pt_arr_union'),
|
||||||
])
|
])
|
||||||
|
# === Словарь соответствия типов XML → DebugVarType_t ===
|
||||||
|
type_map_stm32 = dict([
|
||||||
|
|
||||||
|
*[(k, 'pt_int8') for k in (
|
||||||
|
'int8_t', 'signed char', 'char'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- 8-bit unsigned ---
|
||||||
|
*[(k, 'pt_uint8') for k in (
|
||||||
|
'uint8_t', 'unsigned char'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- 16-bit signed ---
|
||||||
|
*[(k, 'pt_int16') for k in (
|
||||||
|
'int16_t', 'short', 'short int', 'signed short', 'signed short int'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- 16-bit unsigned ---
|
||||||
|
*[(k, 'pt_uint16') for k in (
|
||||||
|
'uint16_t', 'unsigned short', 'unsigned short int'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- 32-bit signed ---
|
||||||
|
*[(k, 'pt_int32') for k in (
|
||||||
|
'int32_t', 'int', 'signed', 'signed int'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- 32-bit unsigned ---
|
||||||
|
*[(k, 'pt_uint32') for k in (
|
||||||
|
'uint32_t', 'unsigned', 'unsigned int'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- 64-bit signed ---
|
||||||
|
*[(k, 'pt_int64') for k in (
|
||||||
|
'int64_t', 'long long', 'signed long long', 'signed long long int'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- 64-bit unsigned ---
|
||||||
|
*[(k, 'pt_uint64') for k in (
|
||||||
|
'uint64_t', 'unsigned long long', 'unsigned long long int'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- Float ---
|
||||||
|
*[(k, 'pt_float') for k in (
|
||||||
|
'float', 'float32_t'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# --- Struct and Union ---
|
||||||
|
('struct', 'pt_struct'),
|
||||||
|
('union', 'pt_union'),
|
||||||
|
('struct*', 'pt_ptr_struct'),
|
||||||
|
('union*', 'pt_ptr_union'),
|
||||||
|
('struct[]', 'pt_arr_struct'),
|
||||||
|
('union[]', 'pt_arr_union'),
|
||||||
|
|
||||||
|
# === POINTERS ===
|
||||||
|
|
||||||
|
# 8-bit
|
||||||
|
*[(k, 'pt_ptr_int8') for k in (
|
||||||
|
'int8_t*', 'signed char*', 'char*'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_ptr_uint8') for k in (
|
||||||
|
'uint8_t*', 'unsigned char*'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# 16-bit
|
||||||
|
*[(k, 'pt_ptr_int16') for k in (
|
||||||
|
'int16_t*', 'short*', 'short int*', 'signed short*', 'signed short int*'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_ptr_uint16') for k in (
|
||||||
|
'uint16_t*', 'unsigned short*', 'unsigned short int*'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# 32-bit
|
||||||
|
*[(k, 'pt_ptr_int32') for k in (
|
||||||
|
'int32_t*', 'int*', 'signed*', 'signed int*'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_ptr_uint32') for k in (
|
||||||
|
'uint32_t*', 'unsigned*', 'unsigned int*'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# 64-bit
|
||||||
|
*[(k, 'pt_ptr_int64') for k in (
|
||||||
|
'int64_t*', 'long long*', 'signed long long*', 'signed long long int*'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_ptr_uint64') for k in (
|
||||||
|
'uint64_t*', 'unsigned long long*', 'unsigned long long int*'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# float*
|
||||||
|
*[(k, 'pt_ptr_float') for k in (
|
||||||
|
'float*', 'float32_t*'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# === ARRAYS ===
|
||||||
|
|
||||||
|
# 8-bit
|
||||||
|
*[(k, 'pt_arr_int8') for k in (
|
||||||
|
'int8_t[]', 'signed char[]', 'char[]'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_arr_uint8') for k in (
|
||||||
|
'uint8_t[]', 'unsigned char[]'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# 16-bit
|
||||||
|
*[(k, 'pt_arr_int16') for k in (
|
||||||
|
'int16_t[]', 'short[]', 'short int[]', 'signed short[]', 'signed short int[]'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_arr_uint16') for k in (
|
||||||
|
'uint16_t[]', 'unsigned short[]', 'unsigned short int[]'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# 32-bit
|
||||||
|
*[(k, 'pt_arr_int32') for k in (
|
||||||
|
'int32_t[]', 'int[]', 'signed[]', 'signed int[]'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_arr_uint32') for k in (
|
||||||
|
'uint32_t[]', 'unsigned[]', 'unsigned int[]'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# 64-bit
|
||||||
|
*[(k, 'pt_arr_int64') for k in (
|
||||||
|
'int64_t[]', 'long long[]', 'signed long long[]', 'signed long long int[]'
|
||||||
|
)],
|
||||||
|
*[(k, 'pt_arr_uint64') for k in (
|
||||||
|
'uint64_t[]', 'unsigned long long[]', 'unsigned long long int[]'
|
||||||
|
)],
|
||||||
|
|
||||||
|
# float[]
|
||||||
|
*[(k, 'pt_arr_float') for k in (
|
||||||
|
'float[]', 'float32_t[]'
|
||||||
|
)],
|
||||||
|
])
|
||||||
|
type_map = type_map_tms
|
||||||
|
stm_flag_global = 0
|
||||||
|
def choose_type_map(stm_flag):
|
||||||
|
global type_map # объявляем, что будем менять глобальную переменную
|
||||||
|
global stm_flag_global # объявляем, что будем менять глобальную переменную
|
||||||
|
if stm_flag:
|
||||||
|
type_map = type_map_stm32
|
||||||
|
stm_flag_global = 1
|
||||||
|
else:
|
||||||
|
type_map = type_map_tms
|
||||||
|
stm_flag_global = 0
|
||||||
|
|
||||||
def map_type_to_pt(typename, varname=None, typedef_map=None):
|
def map_type_to_pt(typename, varname=None, typedef_map=None):
|
||||||
typename_orig = typename.strip()
|
typename_orig = typename.strip()
|
||||||
@@ -138,20 +285,26 @@ def add_new_vars_to_xml(proj_path, xml_rel_path, output_path):
|
|||||||
Возвращает True если что-то добавлено и XML перезаписан, иначе False.
|
Возвращает True если что-то добавлено и XML перезаписан, иначе False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pattern = re.compile(
|
||||||
|
r'{\s*\(uint8_t\s*\*\)\s*&([a-zA-Z_][a-zA-Z0-9_]*(?:\[.*?\])?(?:(?:\.|->)[a-zA-Z_][a-zA-Z0-9_]*(?:\[.*?\])?)*)\s*,\s*'
|
||||||
|
r'(pt_\w+)\s*,\s*'
|
||||||
|
r'(t?_?iq\w+)\s*,\s*'
|
||||||
|
r'(t?_?iq\w+)\s*,\s*'
|
||||||
|
r'"([^"]+)"'
|
||||||
|
)
|
||||||
# Считываем существующие переменные
|
# Считываем существующие переменные
|
||||||
parsed_vars = {}
|
parsed_vars = {}
|
||||||
if os.path.isfile(output_path):
|
if os.path.isfile(output_path):
|
||||||
with open(output_path, 'r', encoding='utf-8', errors='ignore') as f:
|
with open(output_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
# {(char *)&some.deep.var.name , pt_uint16 , t_iq15 , "ShortName"},
|
# {(uint8_t *)&some.deep.var.name , pt_uint16 , t_iq15 , t_iq10, "ShortName"},
|
||||||
m = re.match(
|
m = pattern.search(line)
|
||||||
r'{\s*\(char\s*\*\)\s*&([a-zA-Z_][a-zA-Z0-9_]*)\s*,\s*(pt_\w+)\s*,\s*(t?iq_\w+)\s*,\s*"([^"]+)"',
|
|
||||||
line)
|
|
||||||
if m:
|
if m:
|
||||||
full_varname = m.group(1) # e.g., some.deep.var.name
|
full_varname = m.group(1) # e.g., some.deep.var.name
|
||||||
pt_type = m.group(2)
|
pt_type = m.group(2)
|
||||||
iq_type = m.group(3)
|
iq_type = m.group(3)
|
||||||
shortname = m.group(4)
|
return_type = m.group(4)
|
||||||
|
shortname = m.group(5)
|
||||||
|
|
||||||
parsed_vars[full_varname] = {
|
parsed_vars[full_varname] = {
|
||||||
'pt_type': pt_type,
|
'pt_type': pt_type,
|
||||||
@@ -159,7 +312,7 @@ def add_new_vars_to_xml(proj_path, xml_rel_path, output_path):
|
|||||||
'enable': True,
|
'enable': True,
|
||||||
'show_var': True,
|
'show_var': True,
|
||||||
'shortname': shortname,
|
'shortname': shortname,
|
||||||
'return_type': 'int',
|
'return_type': return_type,
|
||||||
'type': '', # Можешь дополнить из externs
|
'type': '', # Можешь дополнить из externs
|
||||||
'file': '', # Можешь дополнить из externs
|
'file': '', # Можешь дополнить из externs
|
||||||
'extern': False,
|
'extern': False,
|
||||||
@@ -214,8 +367,8 @@ def add_new_vars_to_xml(proj_path, xml_rel_path, output_path):
|
|||||||
added_count += 1
|
added_count += 1
|
||||||
|
|
||||||
if added_count > 0:
|
if added_count > 0:
|
||||||
ET.indent(tree, space=" ", level=0)
|
myXML.fwrite(root, xml_full_path)
|
||||||
tree.write(xml_full_path, encoding="utf-8", xml_declaration=True)
|
|
||||||
print(f"[INFO] В XML добавлено новых переменных: {added_count}")
|
print(f"[INFO] В XML добавлено новых переменных: {added_count}")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -282,12 +435,27 @@ def read_vars_from_xml(proj_path, xml_rel_path):
|
|||||||
return unique_vars, include_files, vars_need_extern
|
return unique_vars, include_files, vars_need_extern
|
||||||
|
|
||||||
|
|
||||||
|
def read_file_try_encodings(filepath):
|
||||||
|
if not os.path.isfile(filepath):
|
||||||
|
# Файл не существует — просто вернуть пустую строку или None
|
||||||
|
return "", None
|
||||||
|
for enc in ['utf-8', 'cp1251']:
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding=enc) as f:
|
||||||
|
content = f.read()
|
||||||
|
return content, enc
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
continue
|
||||||
|
raise UnicodeDecodeError(f"Не удалось прочитать файл {filepath} с кодировками utf-8 и cp1251")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def generate_vars_file(proj_path, xml_path, output_dir):
|
def generate_vars_file(proj_path, xml_path, output_dir):
|
||||||
output_dir = os.path.join(proj_path, output_dir)
|
output_dir = os.path.join(proj_path, output_dir)
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
output_path = os.path.join(output_dir, 'debug_vars.c')
|
output_path = os.path.join(output_dir, 'debug_vars.c')
|
||||||
|
LIBC_path = os.path.join(output_dir, 'debug_tools.c')
|
||||||
|
LIBH_path = os.path.join(output_dir, 'debug_tools.h')
|
||||||
|
|
||||||
|
|
||||||
# Запись новых переменных для в XML
|
# Запись новых переменных для в XML
|
||||||
@@ -328,14 +496,24 @@ def generate_vars_file(proj_path, xml_path, output_dir):
|
|||||||
if not pt_type:
|
if not pt_type:
|
||||||
pt_type = map_type_to_pt(vtype, vname)
|
pt_type = map_type_to_pt(vtype, vname)
|
||||||
|
|
||||||
|
ret_type = info.get('return_type')
|
||||||
|
if not ret_type:
|
||||||
|
pt_type = 't_iq_none'
|
||||||
|
|
||||||
# Дополнительные поля, например комментарий
|
# Дополнительные поля, например комментарий
|
||||||
comment = info.get("comment", "")
|
comment = info.get("comment", "")
|
||||||
|
short_name = info.get("shortname", f'"{vname}"')
|
||||||
|
short_trimmed = short_name[:shortnameSize] # ограничиваем длину до 10
|
||||||
|
|
||||||
if pt_type not in ('pt_struct', 'pt_union'):
|
if pt_type not in ('pt_struct', 'pt_union'):
|
||||||
formated_name = f'"{vname}"'
|
f_name = f'{vname},'
|
||||||
|
f_type = f'{pt_type},'
|
||||||
|
f_iq = f'{iq_type},'
|
||||||
|
f_ret_iq = f'{ret_type},'
|
||||||
|
f_short_name = f'"{short_trimmed}"' # оборачиваем в кавычки
|
||||||
# Добавим комментарий после записи, если он есть
|
# Добавим комментарий после записи, если он есть
|
||||||
comment_str = f' // {comment}' if comment else ''
|
comment_str = f' // {comment}' if comment else ''
|
||||||
line = f'{{(char *)&{vname:<41} , {pt_type:<21} , {iq_type:<21} , {formated_name:<42}}}, \\{comment_str}'
|
line = f'{{(uint8_t *)&{f_name:<58} {f_type:<15} {f_iq:<15} {f_ret_iq:<15} {f_short_name:<21}}}, \\{comment_str}'
|
||||||
new_debug_vars[vname] = line
|
new_debug_vars[vname] = line
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -381,14 +559,19 @@ def generate_vars_file(proj_path, xml_path, output_dir):
|
|||||||
|
|
||||||
out_lines.append(f'\n\n// Определение массива с указателями на переменные для отладки')
|
out_lines.append(f'\n\n// Определение массива с указателями на переменные для отладки')
|
||||||
out_lines.append(f'int DebugVar_Qnt = {len(all_debug_lines)};')
|
out_lines.append(f'int DebugVar_Qnt = {len(all_debug_lines)};')
|
||||||
out_lines.append('#pragma DATA_SECTION(dbg_vars,".dbgvar_info")')
|
if stm_flag_global == 0:
|
||||||
|
out_lines.append('#pragma DATA_SECTION(dbg_vars,".dbgvar_info")')
|
||||||
|
out_lines.append('// pointer_type iq_type return_iq_type short_name')
|
||||||
out_lines.append('DebugVar_t dbg_vars[] = {\\')
|
out_lines.append('DebugVar_t dbg_vars[] = {\\')
|
||||||
out_lines.extend(all_debug_lines)
|
out_lines.extend(all_debug_lines)
|
||||||
out_lines.append('};')
|
out_lines.append('};')
|
||||||
out_lines.append('')
|
out_lines.append('')
|
||||||
# Выберем кодировку для записи файла
|
# Выберем кодировку для записи файла
|
||||||
# Если встречается несколько, возьмем первую из set
|
# Если встречается несколько, возьмем первую из set
|
||||||
enc_to_write = 'cp1251'
|
if stm_flag_global == 0:
|
||||||
|
enc_to_write = 'cp1251'
|
||||||
|
else:
|
||||||
|
enc_to_write = 'utf-8'
|
||||||
|
|
||||||
#print("== GLOBAL VARS FOUND ==")
|
#print("== GLOBAL VARS FOUND ==")
|
||||||
#for vname, (vtype, path) in vars_in_c.items():
|
#for vname, (vtype, path) in vars_in_c.items():
|
||||||
@@ -398,6 +581,16 @@ def generate_vars_file(proj_path, xml_path, output_dir):
|
|||||||
with open(output_path, 'w', encoding=enc_to_write) as f:
|
with open(output_path, 'w', encoding=enc_to_write) as f:
|
||||||
f.write('\n'.join(out_lines))
|
f.write('\n'.join(out_lines))
|
||||||
|
|
||||||
|
if os.path.isfile(LIBC_path):
|
||||||
|
libc_code, _ = read_file_try_encodings(LIBC_path)
|
||||||
|
with open(LIBC_path, 'w', encoding=enc_to_write) as f:
|
||||||
|
f.write(libc_code)
|
||||||
|
|
||||||
|
if os.path.isfile(LIBH_path):
|
||||||
|
libh_code, _ = read_file_try_encodings(LIBH_path)
|
||||||
|
with open(LIBH_path, 'w', encoding=enc_to_write) as f:
|
||||||
|
f.write(libh_code)
|
||||||
|
|
||||||
print(f'Файл debug_vars.c сгенерирован в кодировке, переменных: {len(all_debug_lines)}')
|
print(f'Файл debug_vars.c сгенерирован в кодировке, переменных: {len(all_debug_lines)}')
|
||||||
|
|
||||||
|
|
||||||
@@ -459,16 +652,17 @@ Usage example:
|
|||||||
print(f"Error: Project path '{proj_path}' не является директорией или не существует.")
|
print(f"Error: Project path '{proj_path}' не является директорией или не существует.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
generate_vars_file(proj_path, xml_path_rel, output_dir_rel)
|
generate_vars_file(proj_path, xml_path_rel, output_dir_rel, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
def run_generate(proj_path, xml_path, output_dir):
|
def run_generate(proj_path, xml_path, output_dir, shortname_size):
|
||||||
import os
|
import os
|
||||||
|
global shortnameSize
|
||||||
|
shortnameSize = shortname_size
|
||||||
# Normalize absolute paths
|
# Normalize absolute paths
|
||||||
proj_path = os.path.abspath(proj_path)
|
proj_path = os.path.abspath(proj_path)
|
||||||
xml_path_abs = os.path.abspath(xml_path)
|
xml_path_abs = os.path.abspath(xml_path)
|
||||||
BIN
Src/icon.ico
Normal file
BIN
Src/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
BIN
Src/icon.png
Normal file
BIN
Src/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
242
Src/makefile_parser.py
Normal file
242
Src/makefile_parser.py
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
from lxml import etree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def strip_single_line_comments(code):
|
||||||
|
# Удалим // ... до конца строки
|
||||||
|
return re.sub(r'//.*?$', '', code, flags=re.MULTILINE)
|
||||||
|
|
||||||
|
def read_file_try_encodings(filepath):
|
||||||
|
if not os.path.isfile(filepath):
|
||||||
|
# Файл не существует — просто вернуть пустую строку или None
|
||||||
|
return "", None
|
||||||
|
for enc in ['utf-8', 'cp1251']:
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding=enc) as f:
|
||||||
|
content = f.read()
|
||||||
|
content = strip_single_line_comments(content)
|
||||||
|
return content, enc
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
continue
|
||||||
|
raise UnicodeDecodeError(f"Не удалось прочитать файл {filepath} с кодировками utf-8 и cp1251")
|
||||||
|
|
||||||
|
def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
|
||||||
|
"""
|
||||||
|
Рекурсивно ищет все include-файлы начиная с заданных c_files.
|
||||||
|
Возвращает множество ПОЛНЫХ ПУТЕЙ к найденным include-файлам.
|
||||||
|
|
||||||
|
include_dirs — список директорий, в которых ищем include-файлы.
|
||||||
|
processed_files — множество уже обработанных файлов (для избежания циклов).
|
||||||
|
"""
|
||||||
|
if processed_files is None:
|
||||||
|
processed_files = set()
|
||||||
|
|
||||||
|
include_files = set()
|
||||||
|
include_pattern = re.compile(r'#include\s+"([^"]+)"')
|
||||||
|
|
||||||
|
for cfile in c_files:
|
||||||
|
norm_path = os.path.normpath(cfile)
|
||||||
|
if norm_path in processed_files:
|
||||||
|
continue
|
||||||
|
processed_files.add(norm_path)
|
||||||
|
|
||||||
|
content, _ = read_file_try_encodings(cfile)
|
||||||
|
if content is None:
|
||||||
|
continue
|
||||||
|
includes = include_pattern.findall(content)
|
||||||
|
for inc in includes:
|
||||||
|
# Ищем полный путь к include-файлу в include_dirs
|
||||||
|
inc_full_path = None
|
||||||
|
for dir_ in include_dirs:
|
||||||
|
candidate = os.path.normpath(os.path.join(dir_, inc))
|
||||||
|
if os.path.isfile(candidate):
|
||||||
|
inc_full_path = os.path.abspath(candidate)
|
||||||
|
break
|
||||||
|
|
||||||
|
if inc_full_path:
|
||||||
|
include_files.add(inc_full_path)
|
||||||
|
|
||||||
|
# Рекурсивный обход вложенных includes
|
||||||
|
if inc_full_path not in processed_files:
|
||||||
|
nested_includes = find_all_includes_recursive(
|
||||||
|
[inc_full_path], include_dirs, processed_files
|
||||||
|
)
|
||||||
|
include_files.update(nested_includes)
|
||||||
|
|
||||||
|
return include_files
|
||||||
|
|
||||||
|
|
||||||
|
def parse_objects_list(objects_list_path, project_root):
|
||||||
|
c_files = []
|
||||||
|
include_dirs = set()
|
||||||
|
|
||||||
|
if not os.path.isfile(objects_list_path):
|
||||||
|
return c_files, include_dirs
|
||||||
|
|
||||||
|
with open(objects_list_path, 'r', encoding='utf-8') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip().strip('"').replace("\\", "/")
|
||||||
|
if line.endswith(".o"):
|
||||||
|
c_file = re.sub(r"\.o$", ".c", line)
|
||||||
|
abs_path = os.path.normpath(os.path.join(project_root, c_file))
|
||||||
|
if os.path.isfile(abs_path):
|
||||||
|
if not any(x in abs_path for x in ["DebugTools", "v120", "v100"]):
|
||||||
|
c_files.append(abs_path)
|
||||||
|
include_dirs.add(os.path.dirname(abs_path))
|
||||||
|
|
||||||
|
return c_files, include_dirs
|
||||||
|
|
||||||
|
|
||||||
|
def parse_uvprojx(uvprojx_path):
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import os
|
||||||
|
|
||||||
|
tree = ET.parse(uvprojx_path)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
project_dir = os.path.dirname(os.path.abspath(uvprojx_path))
|
||||||
|
|
||||||
|
c_files = []
|
||||||
|
include_dirs = set()
|
||||||
|
defines = set()
|
||||||
|
|
||||||
|
# Найдём C-файлы и директории
|
||||||
|
for file_elem in root.findall(".//FilePath"):
|
||||||
|
file_path = file_elem.text
|
||||||
|
if file_path:
|
||||||
|
abs_path = os.path.normpath(os.path.join(project_dir, file_path))
|
||||||
|
if os.path.isfile(abs_path):
|
||||||
|
if abs_path.endswith(".c"):
|
||||||
|
c_files.append(abs_path)
|
||||||
|
include_dirs.add(os.path.dirname(abs_path))
|
||||||
|
|
||||||
|
# Включаем IncludePath
|
||||||
|
for inc_path_elem in root.findall(".//IncludePath"):
|
||||||
|
path_text = inc_path_elem.text
|
||||||
|
if path_text:
|
||||||
|
paths = path_text.split(';')
|
||||||
|
for p in paths:
|
||||||
|
p = p.strip()
|
||||||
|
if p:
|
||||||
|
abs_inc_path = os.path.normpath(os.path.join(project_dir, p))
|
||||||
|
if os.path.isdir(abs_inc_path):
|
||||||
|
include_dirs.add(abs_inc_path)
|
||||||
|
|
||||||
|
# Добавим <Define>
|
||||||
|
for define_elem in root.findall(".//Define"):
|
||||||
|
def_text = define_elem.text
|
||||||
|
if def_text:
|
||||||
|
for d in def_text.split(','):
|
||||||
|
d = d.strip()
|
||||||
|
if d:
|
||||||
|
defines.add(d)
|
||||||
|
|
||||||
|
h_files = find_all_includes_recursive(c_files, include_dirs)
|
||||||
|
|
||||||
|
return sorted(c_files), sorted(h_files), sorted(include_dirs), sorted(defines)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def parse_makefile(makefile_path, proj_path):
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
project_root = os.path.abspath(proj_path)
|
||||||
|
c_files = []
|
||||||
|
include_dirs = set()
|
||||||
|
defines = [] # Заглушка: нет define-параметров из Makefile
|
||||||
|
|
||||||
|
with open(makefile_path, 'r', encoding='utf-8') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
raw_entries = []
|
||||||
|
collecting = False
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
stripped = line.strip()
|
||||||
|
|
||||||
|
if (("ORDERED_OBJS" in stripped or "C_SOURCES" in stripped) and ("+=" in stripped or "=" in stripped)):
|
||||||
|
collecting = True
|
||||||
|
|
||||||
|
if collecting:
|
||||||
|
line_clean = stripped.rstrip("\\").strip()
|
||||||
|
if line_clean:
|
||||||
|
line_clean = re.sub(r"\$\([^)]+\)", "", line_clean)
|
||||||
|
line_clean = re.sub(r"\$\{[^}]+\}", "", line_clean)
|
||||||
|
raw_entries.append(line_clean)
|
||||||
|
|
||||||
|
if not stripped.endswith("\\"):
|
||||||
|
collecting = False
|
||||||
|
|
||||||
|
for entry in raw_entries:
|
||||||
|
for token in entry.split():
|
||||||
|
token = token.strip('"')
|
||||||
|
if not token:
|
||||||
|
continue
|
||||||
|
|
||||||
|
token = token.replace("\\", "/")
|
||||||
|
|
||||||
|
if token.endswith(".obj"):
|
||||||
|
token = re.sub(r"\.obj$", ".c", token)
|
||||||
|
elif token.endswith(".o"):
|
||||||
|
token = re.sub(r"\.o$", ".c", token)
|
||||||
|
|
||||||
|
if token.endswith(".c"):
|
||||||
|
abs_path = os.path.normpath(os.path.join(project_root, token))
|
||||||
|
if os.path.isfile(abs_path):
|
||||||
|
if not any(x in abs_path for x in ["DebugTools", "v120", "v100"]):
|
||||||
|
c_files.append(abs_path)
|
||||||
|
include_dirs.add(os.path.dirname(abs_path))
|
||||||
|
|
||||||
|
if not c_files:
|
||||||
|
makefile_dir = os.path.dirname(os.path.abspath(makefile_path))
|
||||||
|
objects_list_path = os.path.join(makefile_dir, "objects.list")
|
||||||
|
c_from_objects, inc_from_objects = parse_objects_list(objects_list_path, project_root)
|
||||||
|
c_files.extend(c_from_objects)
|
||||||
|
include_dirs.update(inc_from_objects)
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if "-I" in line or "C_INCLUDES" in line:
|
||||||
|
matches = re.findall(r"-I\s*([^\s\\]+)", line)
|
||||||
|
for match in matches:
|
||||||
|
match = match.strip('"').replace("\\", "/")
|
||||||
|
abs_include = os.path.normpath(os.path.join(project_root, match))
|
||||||
|
if os.path.isdir(abs_include):
|
||||||
|
include_dirs.add(abs_include)
|
||||||
|
|
||||||
|
# Добавляем пути с заменой 'Src' на 'Inc', если путь заканчивается на 'Src'
|
||||||
|
additional_includes = set()
|
||||||
|
for inc in include_dirs:
|
||||||
|
if inc.endswith(os.sep + "Src") or inc.endswith("/Src"):
|
||||||
|
inc_inc = inc[:-3] + "Inc" # заменяем 'Src' на 'Inc'
|
||||||
|
if os.path.isdir(inc_inc):
|
||||||
|
additional_includes.add(inc_inc)
|
||||||
|
|
||||||
|
include_dirs.update(additional_includes)
|
||||||
|
|
||||||
|
h_files = find_all_includes_recursive(c_files, include_dirs)
|
||||||
|
|
||||||
|
return sorted(c_files), sorted(h_files), sorted(include_dirs), sorted(defines)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_project(project_file_path, project_root=None):
|
||||||
|
"""
|
||||||
|
Выбирает парсер в зависимости от расширения project_file_path:
|
||||||
|
- для *.uvprojx и *.uvproj вызывается парсер Keil
|
||||||
|
- для остальных - parse_makefile
|
||||||
|
|
||||||
|
project_root нужен для parse_makefile, если не передан - берется из project_file_path
|
||||||
|
"""
|
||||||
|
ext = os.path.splitext(project_file_path)[1].lower()
|
||||||
|
|
||||||
|
if ext in ['.uvprojx', '.uvproj']:
|
||||||
|
# Парсим Keil проект
|
||||||
|
return parse_uvprojx(project_file_path)
|
||||||
|
else:
|
||||||
|
# Парсим makefile
|
||||||
|
if project_root is None:
|
||||||
|
project_root = os.path.dirname(os.path.abspath(project_file_path))
|
||||||
|
return parse_makefile(project_file_path, project_root)
|
||||||
72
Src/myXML.py
Normal file
72
Src/myXML.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import os
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
def make_absolute_path(path, base_path):
|
||||||
|
if not os.path.isabs(path) and os.path.isdir(base_path):
|
||||||
|
try:
|
||||||
|
return os.path.abspath(os.path.join(base_path, path))
|
||||||
|
except Exception:
|
||||||
|
pass # На случай сбоя в os.path.join или abspath
|
||||||
|
elif os.path.isabs(path):
|
||||||
|
return os.path.abspath(path)
|
||||||
|
else:
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def make_relative_path(abs_path, base_path):
|
||||||
|
abs_path = os.path.abspath(abs_path)
|
||||||
|
base_path = os.path.abspath(base_path)
|
||||||
|
|
||||||
|
# Разбиваем на списки директорий
|
||||||
|
abs_parts = abs_path.split(os.sep)
|
||||||
|
base_parts = base_path.split(os.sep)
|
||||||
|
|
||||||
|
# Проверяем, является ли base_path настоящим префиксом пути (по папкам)
|
||||||
|
if abs_parts[:len(base_parts)] == base_parts:
|
||||||
|
rel_parts = abs_parts[len(base_parts):]
|
||||||
|
return "/".join(rel_parts)
|
||||||
|
|
||||||
|
# Иначе пробуем relpath
|
||||||
|
try:
|
||||||
|
return os.path.relpath(abs_path, base_path).replace("\\", "/")
|
||||||
|
except Exception:
|
||||||
|
return abs_path.replace("\\", "/")
|
||||||
|
|
||||||
|
def indent_xml(elem, level=0):
|
||||||
|
# Убираем strip() — они медленные, и текст мы всё равно перезаписываем
|
||||||
|
i = "\n" + level * " "
|
||||||
|
if len(elem):
|
||||||
|
elem.text = elem.text or i + " "
|
||||||
|
for child in elem:
|
||||||
|
indent_xml(child, level + 1)
|
||||||
|
elem[-1].tail = elem[-1].tail or i
|
||||||
|
else:
|
||||||
|
elem.tail = elem.tail or i
|
||||||
|
|
||||||
|
|
||||||
|
def fwrite(root, xml_full_path):
|
||||||
|
#indent_xml(root)
|
||||||
|
#ET.ElementTree(root).write(xml_full_path, encoding="utf-8", xml_declaration=True)
|
||||||
|
rough_string = etree.tostring(root, encoding="utf-8")
|
||||||
|
parsed = etree.fromstring(rough_string)
|
||||||
|
with open(xml_full_path, "wb") as f:
|
||||||
|
f.write(etree.tostring(parsed, pretty_print=True, encoding="utf-8", xml_declaration=True))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def safe_parse_xml(xml_path):
|
||||||
|
if not xml_path or not os.path.isfile(xml_path):
|
||||||
|
print(f"Файл '{xml_path}' не найден или путь пустой")
|
||||||
|
return None, None
|
||||||
|
try:
|
||||||
|
if os.path.getsize(xml_path) == 0:
|
||||||
|
return None, None
|
||||||
|
tree = etree.parse(xml_path)
|
||||||
|
root = tree.getroot()
|
||||||
|
return root, tree
|
||||||
|
except etree .XMLSyntaxError as e:
|
||||||
|
print(f"Ошибка парсинга XML файла '{xml_path}': {e}")
|
||||||
|
return None, None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Неожиданная ошибка при чтении XML файла '{xml_path}': {e}")
|
||||||
|
return None, None
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
def strip_single_line_comments(code):
|
|
||||||
# Удалим // ... до конца строки
|
|
||||||
return re.sub(r'//.*?$', '', code, flags=re.MULTILINE)
|
|
||||||
|
|
||||||
def read_file_try_encodings(filepath):
|
|
||||||
for enc in ['utf-8', 'cp1251']:
|
|
||||||
try:
|
|
||||||
with open(filepath, 'r', encoding=enc) as f:
|
|
||||||
content = f.read()
|
|
||||||
content = strip_single_line_comments(content) # <=== ВАЖНО
|
|
||||||
return content, enc
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
continue
|
|
||||||
raise UnicodeDecodeError(f"Не удалось прочитать файл {filepath} с кодировками utf-8 и cp1251")
|
|
||||||
|
|
||||||
def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
|
|
||||||
"""
|
|
||||||
Рекурсивно ищет все include-файлы начиная с заданных c_files.
|
|
||||||
Возвращает множество ПОЛНЫХ ПУТЕЙ к найденным include-файлам.
|
|
||||||
|
|
||||||
include_dirs — список директорий, в которых ищем include-файлы.
|
|
||||||
processed_files — множество уже обработанных файлов (для избежания циклов).
|
|
||||||
"""
|
|
||||||
if processed_files is None:
|
|
||||||
processed_files = set()
|
|
||||||
|
|
||||||
include_files = set()
|
|
||||||
include_pattern = re.compile(r'#include\s+"([^"]+)"')
|
|
||||||
|
|
||||||
for cfile in c_files:
|
|
||||||
norm_path = os.path.normpath(cfile)
|
|
||||||
if norm_path in processed_files:
|
|
||||||
continue
|
|
||||||
processed_files.add(norm_path)
|
|
||||||
|
|
||||||
content, _ = read_file_try_encodings(cfile)
|
|
||||||
includes = include_pattern.findall(content)
|
|
||||||
for inc in includes:
|
|
||||||
# Ищем полный путь к include-файлу в include_dirs
|
|
||||||
inc_full_path = None
|
|
||||||
for dir_ in include_dirs:
|
|
||||||
candidate = os.path.normpath(os.path.join(dir_, inc))
|
|
||||||
if os.path.isfile(candidate):
|
|
||||||
inc_full_path = os.path.abspath(candidate)
|
|
||||||
break
|
|
||||||
|
|
||||||
if inc_full_path:
|
|
||||||
include_files.add(inc_full_path)
|
|
||||||
|
|
||||||
# Рекурсивный обход вложенных includes
|
|
||||||
if inc_full_path not in processed_files:
|
|
||||||
nested_includes = find_all_includes_recursive(
|
|
||||||
[inc_full_path], include_dirs, processed_files
|
|
||||||
)
|
|
||||||
include_files.update(nested_includes)
|
|
||||||
|
|
||||||
return include_files
|
|
||||||
|
|
||||||
|
|
||||||
def parse_makefile(makefile_path):
|
|
||||||
makefile_dir = os.path.dirname(makefile_path)
|
|
||||||
project_root = os.path.dirname(makefile_dir) # поднялись из Debug
|
|
||||||
|
|
||||||
with open(makefile_path, 'r', encoding='utf-8') as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
|
|
||||||
objs_lines = []
|
|
||||||
collecting = False
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
stripped = line.strip()
|
|
||||||
if stripped.startswith("ORDERED_OBJS") and "+=" in stripped:
|
|
||||||
parts = stripped.split("\\")
|
|
||||||
first_part = parts[0]
|
|
||||||
idx = first_part.find("+=")
|
|
||||||
tail = first_part[idx+2:].strip()
|
|
||||||
if tail:
|
|
||||||
objs_lines.append(tail)
|
|
||||||
collecting = True
|
|
||||||
if len(parts) > 1:
|
|
||||||
for p in parts[1:]:
|
|
||||||
p = p.strip()
|
|
||||||
if p:
|
|
||||||
objs_lines.append(p)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if collecting:
|
|
||||||
if stripped.endswith("\\"):
|
|
||||||
objs_lines.append(stripped[:-1].strip())
|
|
||||||
else:
|
|
||||||
objs_lines.append(stripped)
|
|
||||||
collecting = False
|
|
||||||
|
|
||||||
objs_str = ' '.join(objs_lines)
|
|
||||||
|
|
||||||
objs_str = re.sub(r"\$\([^)]+\)", "", objs_str)
|
|
||||||
|
|
||||||
objs = []
|
|
||||||
for part in objs_str.split():
|
|
||||||
part = part.strip()
|
|
||||||
if part.startswith('"') and part.endswith('"'):
|
|
||||||
part = part[1:-1]
|
|
||||||
if part:
|
|
||||||
objs.append(part)
|
|
||||||
|
|
||||||
c_files = []
|
|
||||||
include_dirs = set()
|
|
||||||
|
|
||||||
for obj_path in objs:
|
|
||||||
if "DebugTools" in obj_path:
|
|
||||||
continue
|
|
||||||
if "v120" in obj_path:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if obj_path.startswith("Debug\\") or obj_path.startswith("Debug/"):
|
|
||||||
rel_path = obj_path.replace("Debug\\", "Src\\").replace("Debug/", "Src/")
|
|
||||||
else:
|
|
||||||
rel_path = obj_path
|
|
||||||
|
|
||||||
abs_path = os.path.normpath(os.path.join(project_root, rel_path))
|
|
||||||
|
|
||||||
root, ext = os.path.splitext(abs_path)
|
|
||||||
if ext.lower() == ".obj":
|
|
||||||
c_path = root + ".c"
|
|
||||||
else:
|
|
||||||
c_path = abs_path
|
|
||||||
|
|
||||||
# Сохраняем только .c файлы
|
|
||||||
if c_path.lower().endswith(".c"):
|
|
||||||
c_files.append(c_path)
|
|
||||||
dir_path = os.path.dirname(c_path)
|
|
||||||
if dir_path and "DebugTools" not in dir_path:
|
|
||||||
include_dirs.add(dir_path)
|
|
||||||
|
|
||||||
|
|
||||||
h_files = find_all_includes_recursive(c_files, include_dirs)
|
|
||||||
|
|
||||||
|
|
||||||
return sorted(c_files), sorted(h_files), sorted(include_dirs)
|
|
||||||
Binary file not shown.
Binary file not shown.
219
Src/scan_progress_gui.py
Normal file
219
Src/scan_progress_gui.py
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import multiprocessing
|
||||||
|
import sys
|
||||||
|
import contextlib
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
from scan_vars import run_scan
|
||||||
|
from var_table import VariableTableWidget, rows
|
||||||
|
|
||||||
|
from PySide2.QtWidgets import (
|
||||||
|
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
||||||
|
QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||||
|
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit,
|
||||||
|
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView, QProgressBar
|
||||||
|
)
|
||||||
|
from PySide2.QtGui import QTextCursor, QKeyEvent
|
||||||
|
from PySide2.QtCore import Qt, QProcess, QObject, Signal, QTimer
|
||||||
|
|
||||||
|
|
||||||
|
class EmittingStream(QObject):
|
||||||
|
text_written = Signal(str)
|
||||||
|
progress_updated = Signal(str, int, int) # bar_name, current, total
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self._buffer = ""
|
||||||
|
self._current_bar_name = None
|
||||||
|
|
||||||
|
def write(self, text):
|
||||||
|
self._buffer += text
|
||||||
|
while '\n' in self._buffer:
|
||||||
|
line, self._buffer = self._buffer.split('\n', 1)
|
||||||
|
|
||||||
|
if line.startswith('Progress: "') and line.endswith('"'):
|
||||||
|
bar_name = self._extract_bar_name(line)
|
||||||
|
if bar_name:
|
||||||
|
self._current_bar_name = bar_name
|
||||||
|
continue # не выводим строку
|
||||||
|
elif self._is_progress_line(line):
|
||||||
|
current, total = self._extract_progress(line)
|
||||||
|
if current is not None and total is not None:
|
||||||
|
name = self._current_bar_name if self._current_bar_name else "Progress"
|
||||||
|
self.progress_updated.emit(name, current, total)
|
||||||
|
continue # не выводим строку
|
||||||
|
|
||||||
|
# если не прогресс и не имя — выводим
|
||||||
|
self.text_written.emit(line)
|
||||||
|
|
||||||
|
def _extract_bar_name(self, line):
|
||||||
|
# точно обрезаем вручную
|
||||||
|
prefix = 'Progress: "'
|
||||||
|
suffix = '"'
|
||||||
|
if line.startswith(prefix) and line.endswith(suffix):
|
||||||
|
return line[len(prefix):-1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _is_progress_line(self, line):
|
||||||
|
return re.match(r'^Progress:\s*\d+\s*/\s*\d+$', line) is not None
|
||||||
|
|
||||||
|
def _extract_progress(self, line):
|
||||||
|
match = re.match(r'^Progress:\s*(\d+)\s*/\s*(\d+)$', line)
|
||||||
|
if match:
|
||||||
|
return int(match.group(1)), int(match.group(2))
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
if self._buffer:
|
||||||
|
line = self._buffer.strip()
|
||||||
|
if not self._is_progress_line(line) and not self._extract_bar_name(line):
|
||||||
|
self.text_written.emit(line)
|
||||||
|
self._buffer = ""
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessOutputWindow(QDialog):
|
||||||
|
def __init__(self, proj_path, makefile_path, xml_path, on_done_callback=None, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setWindowTitle("Поиск переменных...")
|
||||||
|
self.resize(600, 480)
|
||||||
|
self.setModal(True)
|
||||||
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||||
|
|
||||||
|
self.proj_path = proj_path
|
||||||
|
self.makefile_path = makefile_path
|
||||||
|
self.xml_path = xml_path
|
||||||
|
self._on_done_callback = on_done_callback
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
|
||||||
|
self.output_edit = QTextEdit()
|
||||||
|
self.output_edit.setReadOnly(True)
|
||||||
|
self.layout.addWidget(self.output_edit)
|
||||||
|
|
||||||
|
self.progress_label = QLabel("Progress:")
|
||||||
|
self.layout.addWidget(self.progress_label)
|
||||||
|
|
||||||
|
self.progress_bar = QProgressBar()
|
||||||
|
self.progress_bar.setMinimum(0)
|
||||||
|
self.progress_bar.setValue(0)
|
||||||
|
self.layout.addWidget(self.progress_bar)
|
||||||
|
|
||||||
|
self.btn_close = QPushButton("Закрыть")
|
||||||
|
self.btn_close.setEnabled(False)
|
||||||
|
self.layout.addWidget(self.btn_close)
|
||||||
|
self.btn_close.clicked.connect(self.__handle_done)
|
||||||
|
|
||||||
|
self.queue = None
|
||||||
|
self.proc = None
|
||||||
|
|
||||||
|
|
||||||
|
def start_scan(self):
|
||||||
|
self.queue = multiprocessing.Queue()
|
||||||
|
self.proc = multiprocessing.Process(
|
||||||
|
target=run_scan_process,
|
||||||
|
args=(self.proj_path, self.makefile_path, self.xml_path, self.queue),
|
||||||
|
daemon=True)
|
||||||
|
self.proc.start()
|
||||||
|
|
||||||
|
self.timer = QTimer(self)
|
||||||
|
self.timer.timeout.connect(self.poll_queue)
|
||||||
|
self.timer.start(100)
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def poll_queue(self):
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
msg = self.queue.get_nowait()
|
||||||
|
if msg is None:
|
||||||
|
# Конец процесса
|
||||||
|
self.btn_close.setEnabled(True)
|
||||||
|
self.append_text("\n--- Анализ завершён ---")
|
||||||
|
self.timer.stop()
|
||||||
|
return
|
||||||
|
# Пытаемся разобрать JSON-сообщение
|
||||||
|
if isinstance(msg, str) and msg.startswith("PROGRESS_MSG:"):
|
||||||
|
try:
|
||||||
|
data = json.loads(msg[len("PROGRESS_MSG:"):])
|
||||||
|
self.update_progress(data["bar_name"], data["current"], data["total"])
|
||||||
|
except Exception:
|
||||||
|
# Если не удалось распарсить, выводим как текст
|
||||||
|
self.append_text(msg)
|
||||||
|
else:
|
||||||
|
self.append_text(msg)
|
||||||
|
except Exception:
|
||||||
|
pass # Очередь пустая
|
||||||
|
|
||||||
|
def append_text(self, text):
|
||||||
|
cursor = self.output_edit.textCursor()
|
||||||
|
cursor.movePosition(QTextCursor.End)
|
||||||
|
if not text.endswith('\n'):
|
||||||
|
text += '\n'
|
||||||
|
cursor.insertText(text)
|
||||||
|
self.output_edit.setTextCursor(cursor)
|
||||||
|
self.output_edit.ensureCursorVisible()
|
||||||
|
|
||||||
|
def update_progress(self, bar_name, current, total):
|
||||||
|
self.progress_label.setText(f"{bar_name}")
|
||||||
|
self.progress_bar.setMaximum(total)
|
||||||
|
self.progress_bar.setValue(current)
|
||||||
|
|
||||||
|
def __handle_done(self):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
if self.proc and self.proc.is_alive():
|
||||||
|
self.proc.terminate()
|
||||||
|
self.proc.join()
|
||||||
|
self.btn_close.setEnabled(True)
|
||||||
|
self.append_text("Сканирование прервано.")
|
||||||
|
|
||||||
|
|
||||||
|
def run_scan_process(proj_path, makefile_path, xml_path, queue):
|
||||||
|
class QueueWriter(io.TextIOBase):
|
||||||
|
def __init__(self):
|
||||||
|
self._buffer = ""
|
||||||
|
self._current_bar_name = None
|
||||||
|
|
||||||
|
def write(self, txt):
|
||||||
|
self._buffer += txt
|
||||||
|
while '\n' in self._buffer:
|
||||||
|
line, self._buffer = self._buffer.split('\n', 1)
|
||||||
|
# Обработка прогресса
|
||||||
|
if line.startswith('Progress: "') and line.endswith('"'):
|
||||||
|
# Название прогресс-бара
|
||||||
|
bar_name = line[len('Progress: "'):-1]
|
||||||
|
self._current_bar_name = bar_name
|
||||||
|
elif re.match(r'^Progress:\s*\d+\s*/\s*\d+$', line):
|
||||||
|
m = re.match(r'^Progress:\s*(\d+)\s*/\s*(\d+)$', line)
|
||||||
|
if m:
|
||||||
|
current = int(m.group(1))
|
||||||
|
total = int(m.group(2))
|
||||||
|
bar_name = self._current_bar_name or "Progress"
|
||||||
|
# Отправляем специальное сообщение в очередь в формате JSON
|
||||||
|
msg = {
|
||||||
|
"bar_name": bar_name,
|
||||||
|
"current": current,
|
||||||
|
"total": total
|
||||||
|
}
|
||||||
|
queue.put("PROGRESS_MSG:" + json.dumps(msg))
|
||||||
|
else:
|
||||||
|
# Обычный вывод
|
||||||
|
queue.put(line)
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
if self._buffer.strip():
|
||||||
|
queue.put(self._buffer.strip())
|
||||||
|
self._buffer = ""
|
||||||
|
|
||||||
|
sys.stdout = QueueWriter()
|
||||||
|
sys.stderr = sys.stdout
|
||||||
|
|
||||||
|
try:
|
||||||
|
run_scan(proj_path, makefile_path, xml_path)
|
||||||
|
except Exception as e:
|
||||||
|
queue.put(f"[ОШИБКА] {e}")
|
||||||
|
finally:
|
||||||
|
queue.put(None) # сигнал окончания
|
||||||
@@ -1,29 +1,69 @@
|
|||||||
# build command
|
# build command
|
||||||
# pyinstaller --onefile scanVars.py --add-binary "F:\Work\Projects\TMS\TMS_new_bus\Src\DebugTools/build/libclang.dll;." --distpath . --workpath ./build --specpath ./build
|
# pyinstaller --onefile scan_vars.py --add-binary "F:\Work\Projects\TMS\TMS_new_bus\Src\DebugTools/build/libclang.dll;." --distpath . --workpath ./build --specpath ./build
|
||||||
# start script
|
# start script
|
||||||
# scanVars.exe F:\Work\Projects\TMS\TMS_new_bus\ F:\Work\Projects\TMS\TMS_new_bus\Debug\makefile
|
# scan_vars.exe F:\Work\Projects\TMS\TMS_new_bus\ F:\Work\Projects\TMS\TMS_new_bus\Debug\makefile
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import clang.cindex
|
import clang.cindex
|
||||||
from clang import cindex
|
from clang import cindex
|
||||||
import xml.etree.ElementTree as ET
|
from clang.cindex import Config
|
||||||
|
import lxml.etree as ET
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
from parseMakefile import parse_makefile
|
from makefile_parser import parse_project
|
||||||
from collections import deque
|
from collections import deque
|
||||||
import argparse
|
import argparse
|
||||||
|
import myXML
|
||||||
BITFIELD_WIDTHS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
|
BITFIELD_WIDTHS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
|
||||||
|
|
||||||
|
def is_frozen():
|
||||||
|
# Для Nuitka --onefile
|
||||||
|
return getattr(sys, 'frozen', False)
|
||||||
|
|
||||||
|
def get_base_path():
|
||||||
|
if is_frozen():
|
||||||
|
# В Nuitka onefile распаковывается в папку с самим exe во временной директории
|
||||||
|
return os.path.dirname(sys.executable)
|
||||||
|
else:
|
||||||
|
# Режим разработки
|
||||||
|
return os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
# Укажи полный путь к libclang.dll — поменяй на свой путь или оставь относительный
|
def print_embedded_dlls():
|
||||||
dll_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "build/libclang.dll")
|
# Папка временной распаковки для onefile приложений Nuitka/PyInstaller
|
||||||
|
base_path = get_base_path()
|
||||||
|
print(f"Scanning DLLs in temporary folder: {base_path}")
|
||||||
|
|
||||||
if hasattr(sys, '_MEIPASS'):
|
dlls = []
|
||||||
dll_path = os.path.join(sys._MEIPASS, "libclang.dll")
|
for root, dirs, files in os.walk(base_path):
|
||||||
cindex.Config.set_library_file(dll_path)
|
for file in files:
|
||||||
|
if file.lower().endswith('.dll'):
|
||||||
|
full_path = os.path.join(root, file)
|
||||||
|
rel_path = os.path.relpath(full_path, base_path)
|
||||||
|
dlls.append(rel_path)
|
||||||
|
|
||||||
|
if dlls:
|
||||||
|
print("DLL files found:")
|
||||||
|
for d in dlls:
|
||||||
|
print(" -", d)
|
||||||
|
else:
|
||||||
|
print("No DLL files found in temporary folder.")
|
||||||
|
|
||||||
|
# Вызов при старте
|
||||||
|
print_embedded_dlls()
|
||||||
|
|
||||||
|
base_path = get_base_path()
|
||||||
|
print("Base path:", base_path)
|
||||||
|
|
||||||
|
# Указываем полный путь к libclang.dll внутри распакованного каталога
|
||||||
|
dll_path = os.path.join(base_path, "libclang.dll")
|
||||||
|
|
||||||
|
if os.path.exists(dll_path):
|
||||||
|
print("Loading libclang.dll from:", dll_path)
|
||||||
|
Config.set_library_file(dll_path)
|
||||||
else:
|
else:
|
||||||
cindex.Config.set_library_file(r"build\libclang.dll") # путь для запуска без упаковки
|
print("ERROR: libclang.dll not found at", dll_path)
|
||||||
|
|
||||||
|
|
||||||
index = cindex.Index.create()
|
index = cindex.Index.create()
|
||||||
PRINT_LEVEL = 2
|
PRINT_LEVEL = 2
|
||||||
@@ -78,11 +118,11 @@ def get_canonical_typedef_file(var_type, include_dirs):
|
|||||||
break
|
break
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def analyze_variables_across_files(c_files, h_files, include_dirs):
|
def analyze_variables_across_files(c_files, h_files, include_dirs, global_defs):
|
||||||
optional_printf(PRINT_STATUS, "Starting analysis of variables across files...")
|
optional_printf(PRINT_STATUS, "Starting analysis of variables across files...")
|
||||||
index = clang.cindex.Index.create()
|
index = clang.cindex.Index.create()
|
||||||
args = [f"-I{inc}" for inc in include_dirs]
|
define_args = [f"-D{d}" for d in global_defs]
|
||||||
|
args = [f"-I{inc}" for inc in include_dirs] + define_args
|
||||||
unique_vars = {} # имя переменной → словарь с инфой
|
unique_vars = {} # имя переменной → словарь с инфой
|
||||||
h_files_needed = set()
|
h_files_needed = set()
|
||||||
vars_need_extern = {} # имя переменной → словарь без поля 'extern'
|
vars_need_extern = {} # имя переменной → словарь без поля 'extern'
|
||||||
@@ -114,6 +154,7 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
|
|||||||
# Проверяем, начинается ли имя с "_" и содержит заглавные буквы или служебные символы
|
# Проверяем, начинается ли имя с "_" и содержит заглавные буквы или служебные символы
|
||||||
return bool(re.match(r"^_[_A-Z]", var_name))
|
return bool(re.match(r"^_[_A-Z]", var_name))
|
||||||
|
|
||||||
|
|
||||||
if node.kind == clang.cindex.CursorKind.VAR_DECL:
|
if node.kind == clang.cindex.CursorKind.VAR_DECL:
|
||||||
if node.semantic_parent.kind == clang.cindex.CursorKind.TRANSLATION_UNIT:
|
if node.semantic_parent.kind == clang.cindex.CursorKind.TRANSLATION_UNIT:
|
||||||
is_extern = (node.storage_class == clang.cindex.StorageClass.EXTERN)
|
is_extern = (node.storage_class == clang.cindex.StorageClass.EXTERN)
|
||||||
@@ -130,7 +171,12 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
|
|||||||
return # игнорируем только явно известные служебные переменные
|
return # игнорируем только явно известные служебные переменные
|
||||||
if node.spelling == 'HUGE': # еще одна служеюная, которую хз как выделять
|
if node.spelling == 'HUGE': # еще одна служеюная, которую хз как выделять
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if 'Drivers' in node.location.file.name:
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'uint' in node.spelling:
|
||||||
|
a = 1
|
||||||
# Проверяем, является ли тип указателем на функцию
|
# Проверяем, является ли тип указателем на функцию
|
||||||
# Признак: в типе есть '(' и ')' и '*', например: "void (*)(int)"
|
# Признак: в типе есть '(' и ')' и '*', например: "void (*)(int)"
|
||||||
if "(" in var_type and "*" in var_type and ")" in var_type:
|
if "(" in var_type and "*" in var_type and ")" in var_type:
|
||||||
@@ -163,7 +209,9 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
|
|||||||
return vars_in_file
|
return vars_in_file
|
||||||
|
|
||||||
optional_printf(PRINT_STATUS, "Parsing header files (.h)...")
|
optional_printf(PRINT_STATUS, "Parsing header files (.h)...")
|
||||||
for h in h_files:
|
optional_printf(PRINT_STATUS, 'Progress: "Parsing variables from headers..."')
|
||||||
|
total_h = len(h_files)
|
||||||
|
for i, h in enumerate(h_files, 1):
|
||||||
vars_in_h = parse_file(h)
|
vars_in_h = parse_file(h)
|
||||||
for v in vars_in_h:
|
for v in vars_in_h:
|
||||||
name = v["name"]
|
name = v["name"]
|
||||||
@@ -174,9 +222,12 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
|
|||||||
"static": v["static"],
|
"static": v["static"],
|
||||||
"file": v["file"]
|
"file": v["file"]
|
||||||
}
|
}
|
||||||
|
optional_printf(PRINT_STATUS, f"Progress: {i}/{total_h}")
|
||||||
|
|
||||||
optional_printf(PRINT_STATUS, "Parsing source files (.c)...")
|
optional_printf(PRINT_STATUS, "Parsing source files (.c)...")
|
||||||
for c in c_files:
|
optional_printf(PRINT_STATUS, 'Progress: "Parsing variables from sources files..."')
|
||||||
|
total_c = len(c_files)
|
||||||
|
for i, c in enumerate(c_files, 1):
|
||||||
vars_in_c = parse_file(c)
|
vars_in_c = parse_file(c)
|
||||||
for v in vars_in_c:
|
for v in vars_in_c:
|
||||||
name = v["name"]
|
name = v["name"]
|
||||||
@@ -194,9 +245,12 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
|
|||||||
"static": v["static"],
|
"static": v["static"],
|
||||||
"file": v["file"]
|
"file": v["file"]
|
||||||
}
|
}
|
||||||
|
optional_printf(PRINT_STATUS, f"Progress: {i}/{total_c}")
|
||||||
|
|
||||||
optional_printf(PRINT_STATUS, "Checking which variables need explicit extern declaration...")
|
optional_printf(PRINT_STATUS, "Checking which variables need explicit extern declaration...")
|
||||||
for name, info in unique_vars.items():
|
optional_printf(PRINT_STATUS, 'Progress: "Checking extern declarations..."')
|
||||||
|
total_vars = len(unique_vars)
|
||||||
|
for i, (name, info) in enumerate(unique_vars.items(), 1):
|
||||||
if not info["extern"] and not info["static"] and info["file"].endswith('.c'):
|
if not info["extern"] and not info["static"] and info["file"].endswith('.c'):
|
||||||
extern_declared = False
|
extern_declared = False
|
||||||
for h in h_files_needed:
|
for h in h_files_needed:
|
||||||
@@ -208,6 +262,7 @@ def analyze_variables_across_files(c_files, h_files, include_dirs):
|
|||||||
"type": info["type"],
|
"type": info["type"],
|
||||||
"file": info["file"]
|
"file": info["file"]
|
||||||
}
|
}
|
||||||
|
optional_printf(PRINT_STATUS, f"Progress: {i}/{total_vars}")
|
||||||
|
|
||||||
optional_printf(PRINT_STATUS, "Analysis complete.")
|
optional_printf(PRINT_STATUS, "Analysis complete.")
|
||||||
optional_printf(PRINT_STATUS, f"\tTotal unique variables found: {len(unique_vars)}")
|
optional_printf(PRINT_STATUS, f"\tTotal unique variables found: {len(unique_vars)}")
|
||||||
@@ -246,6 +301,8 @@ def strip_ptr_and_array(typename):
|
|||||||
|
|
||||||
return typename
|
return typename
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analyze_typedefs_and_struct(typedefs, structs):
|
def analyze_typedefs_and_struct(typedefs, structs):
|
||||||
optional_printf(PRINT_STATUS, "Resolving typedefs and expanding struct field types...")
|
optional_printf(PRINT_STATUS, "Resolving typedefs and expanding struct field types...")
|
||||||
|
|
||||||
@@ -314,9 +371,21 @@ def analyze_typedefs_and_struct(typedefs, structs):
|
|||||||
substituted_fields[fname] = resolved_type
|
substituted_fields[fname] = resolved_type
|
||||||
substituted_structs[resolved_sname] = substituted_fields """
|
substituted_structs[resolved_sname] = substituted_fields """
|
||||||
|
|
||||||
|
# Раскрываем typedef'ы
|
||||||
|
optional_printf(PRINT_STATUS, 'Progress: "Resolving typedefs..."')
|
||||||
|
total_typedefs = len(typedefs)
|
||||||
|
resolved_typedefs = {}
|
||||||
|
for i, tname in enumerate(typedefs, 1):
|
||||||
|
resolved = resolve_typedef_rec(tname)
|
||||||
|
resolved_typedefs[tname] = resolved
|
||||||
|
optional_printf(4, f"\tTypedef {tname} resolved")
|
||||||
|
optional_printf(PRINT_STATUS, f"Progress: {i}/{total_typedefs}")
|
||||||
|
|
||||||
# Теперь раскрываем вложенные структуры
|
# Теперь раскрываем вложенные структуры
|
||||||
|
optional_printf(PRINT_STATUS, 'Progress: "Resolving structs..."')
|
||||||
|
total_structs = len(structs)
|
||||||
resolved_structs = {}
|
resolved_structs = {}
|
||||||
for sname, fields in structs.items():
|
for i, (sname, fields) in enumerate(structs.items(), 1):
|
||||||
if "(unnamed" in sname:
|
if "(unnamed" in sname:
|
||||||
optional_printf(4, f" Skipping anonymous struct/union: {sname}")
|
optional_printf(4, f" Skipping anonymous struct/union: {sname}")
|
||||||
continue
|
continue
|
||||||
@@ -325,13 +394,7 @@ def analyze_typedefs_and_struct(typedefs, structs):
|
|||||||
resolved_fields = resolve_struct_fields(fields)
|
resolved_fields = resolve_struct_fields(fields)
|
||||||
resolved_structs[sname] = resolved_fields
|
resolved_structs[sname] = resolved_fields
|
||||||
optional_printf(PRINT_DEBUG, f"\tStruct {sname} resolved")
|
optional_printf(PRINT_DEBUG, f"\tStruct {sname} resolved")
|
||||||
|
optional_printf(PRINT_STATUS, f"Progress: {i}/{total_structs}")
|
||||||
# Раскрываем typedef'ы в отдельном шаге
|
|
||||||
resolved_typedefs = {}
|
|
||||||
for tname in typedefs:
|
|
||||||
resolved = resolve_typedef_rec(tname)
|
|
||||||
resolved_typedefs[tname] = resolved
|
|
||||||
optional_printf(4, f"\tTypedef {tname} resolved")
|
|
||||||
|
|
||||||
return resolved_typedefs, resolved_structs
|
return resolved_typedefs, resolved_structs
|
||||||
|
|
||||||
@@ -367,10 +430,28 @@ def contains_anywhere_in_node(node, target: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
|
|
||||||
|
def try_guess_std_include():
|
||||||
|
# Популярные места, где может лежать stdint.h
|
||||||
|
guesses = [
|
||||||
|
r"C:\Keil_v5\ARM\ARMCLANG\include",
|
||||||
|
r"C:\Program Files (x86)\GNU Arm Embedded Toolchain",
|
||||||
|
r"C:\Program Files (x86)\Arm GNU Toolchain"
|
||||||
|
]
|
||||||
|
|
||||||
|
found = []
|
||||||
|
for base in guesses:
|
||||||
|
for root, dirs, files in os.walk(base):
|
||||||
|
if "stdint.h" in files:
|
||||||
|
found.append(root)
|
||||||
|
return found
|
||||||
|
|
||||||
|
def analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs):
|
||||||
optional_printf(PRINT_STATUS, "Starting analysis of typedefs and structs across files...")
|
optional_printf(PRINT_STATUS, "Starting analysis of typedefs and structs across files...")
|
||||||
index = clang.cindex.Index.create()
|
index = clang.cindex.Index.create()
|
||||||
args = [f"-I{inc}" for inc in include_dirs]
|
define_args = [f"-D{d}" for d in global_defs]
|
||||||
|
extra_std_include_dirs = try_guess_std_include()
|
||||||
|
args = [f"-I{inc}" for inc in include_dirs] + extra_std_include_dirs + define_args
|
||||||
|
|
||||||
unique_typedefs_raw = {}
|
unique_typedefs_raw = {}
|
||||||
unique_structs_raw = {}
|
unique_structs_raw = {}
|
||||||
@@ -397,7 +478,6 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
|
|||||||
|
|
||||||
raw_name = node.spelling
|
raw_name = node.spelling
|
||||||
normalized_name = normalize_type_name(raw_name)
|
normalized_name = normalize_type_name(raw_name)
|
||||||
|
|
||||||
# struct_name всегда с префиксом
|
# struct_name всегда с префиксом
|
||||||
if node.spelling and "unnamed" not in normalized_name:
|
if node.spelling and "unnamed" not in normalized_name:
|
||||||
struct_name = f"{prefix}{normalized_name}"
|
struct_name = f"{prefix}{normalized_name}"
|
||||||
@@ -439,7 +519,9 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
|
|||||||
visit(tu.cursor)
|
visit(tu.cursor)
|
||||||
return typedefs, structs
|
return typedefs, structs
|
||||||
|
|
||||||
for c_file in c_files:
|
optional_printf(PRINT_STATUS, 'Progress: "Resolving structs and typedefs..."')
|
||||||
|
total_files = len(c_files)
|
||||||
|
for i, c_file in enumerate(c_files, 1):
|
||||||
typedefs_in_file, structs_in_file = parse_file(c_file)
|
typedefs_in_file, structs_in_file = parse_file(c_file)
|
||||||
for name, underlying in typedefs_in_file.items():
|
for name, underlying in typedefs_in_file.items():
|
||||||
if name not in unique_typedefs_raw:
|
if name not in unique_typedefs_raw:
|
||||||
@@ -447,6 +529,7 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
|
|||||||
for sname, fields in structs_in_file.items():
|
for sname, fields in structs_in_file.items():
|
||||||
if sname not in unique_structs_raw:
|
if sname not in unique_structs_raw:
|
||||||
unique_structs_raw[sname] = fields
|
unique_structs_raw[sname] = fields
|
||||||
|
optional_printf(PRINT_STATUS, f"Progress: {i}/{total_files}")
|
||||||
|
|
||||||
# Теперь раскроем typedef и структуры, учитывая вложения
|
# Теперь раскроем typedef и структуры, учитывая вложения
|
||||||
resolved_typedefs, resolved_structs = analyze_typedefs_and_struct(unique_typedefs_raw, unique_structs_raw)
|
resolved_typedefs, resolved_structs = analyze_typedefs_and_struct(unique_typedefs_raw, unique_structs_raw)
|
||||||
@@ -458,31 +541,6 @@ def analyze_typedefs_and_structs_across_files(c_files, include_dirs):
|
|||||||
return resolved_typedefs, resolved_structs
|
return resolved_typedefs, resolved_structs
|
||||||
|
|
||||||
|
|
||||||
def safe_parse_xml(xml_path):
|
|
||||||
"""
|
|
||||||
Безопасно парсит XML-файл.
|
|
||||||
|
|
||||||
Возвращает кортеж (root, tree) или (None, None) при ошибках.
|
|
||||||
"""
|
|
||||||
if not xml_path or not os.path.isfile(xml_path):
|
|
||||||
print(f"Файл '{xml_path}' не найден или путь пустой")
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
try:
|
|
||||||
if os.path.getsize(xml_path) == 0:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
tree = ET.parse(xml_path)
|
|
||||||
root = tree.getroot()
|
|
||||||
return root, tree
|
|
||||||
|
|
||||||
except ET.ParseError as e:
|
|
||||||
print(f"Ошибка парсинга XML файла '{xml_path}': {e}")
|
|
||||||
return None, None
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Неожиданная ошибка при чтении XML файла '{xml_path}': {e}")
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
def read_vars_from_xml(xml_path):
|
def read_vars_from_xml(xml_path):
|
||||||
xml_full_path = os.path.normpath(xml_path)
|
xml_full_path = os.path.normpath(xml_path)
|
||||||
vars_data = {}
|
vars_data = {}
|
||||||
@@ -490,7 +548,7 @@ def read_vars_from_xml(xml_path):
|
|||||||
if not os.path.exists(xml_full_path):
|
if not os.path.exists(xml_full_path):
|
||||||
return vars_data # пусто, если файла нет
|
return vars_data # пусто, если файла нет
|
||||||
|
|
||||||
root, tree = safe_parse_xml(xml_full_path)
|
root, tree = myXML.safe_parse_xml(xml_full_path)
|
||||||
if root is None:
|
if root is None:
|
||||||
return vars_data
|
return vars_data
|
||||||
|
|
||||||
@@ -512,7 +570,7 @@ def read_vars_from_xml(xml_path):
|
|||||||
'shortname': var_elem.findtext('shortname', name),
|
'shortname': var_elem.findtext('shortname', name),
|
||||||
'pt_type': var_elem.findtext('pt_type', ''),
|
'pt_type': var_elem.findtext('pt_type', ''),
|
||||||
'iq_type': var_elem.findtext('iq_type', ''),
|
'iq_type': var_elem.findtext('iq_type', ''),
|
||||||
'return_type': var_elem.findtext('return_type', 'int'),
|
'return_type': var_elem.findtext('return_type', 't_iq_none'),
|
||||||
'type': var_elem.findtext('type', 'unknown'),
|
'type': var_elem.findtext('type', 'unknown'),
|
||||||
'file': var_elem.findtext('file', ''),
|
'file': var_elem.findtext('file', ''),
|
||||||
'extern': get_bool('extern'),
|
'extern': get_bool('extern'),
|
||||||
@@ -521,9 +579,19 @@ def read_vars_from_xml(xml_path):
|
|||||||
|
|
||||||
return vars_data
|
return vars_data
|
||||||
|
|
||||||
|
def make_relative_if_possible(path, base):
|
||||||
|
if not path:
|
||||||
|
return ''
|
||||||
|
if not os.path.isabs(path):
|
||||||
|
return path # уже относительный
|
||||||
|
try:
|
||||||
|
rel = os.path.relpath(path, base)
|
||||||
|
return rel
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"[WARNING] relpath error between '{path}' and '{base}': {e}")
|
||||||
|
return path # оставляем абсолютным
|
||||||
|
|
||||||
def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_need_extern, structs_xml_path=None, makefile_path=None):
|
def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_need_extern, structs_xml_path=None, makefile_path=None):
|
||||||
|
|
||||||
xml_full_path = os.path.normpath(xml_path)
|
xml_full_path = os.path.normpath(xml_path)
|
||||||
|
|
||||||
# Проверяем, существует ли файл, только тогда читаем из него
|
# Проверяем, существует ли файл, только тогда читаем из него
|
||||||
@@ -531,12 +599,22 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
|
|||||||
if os.path.isfile(xml_full_path):
|
if os.path.isfile(xml_full_path):
|
||||||
existing_vars_data = read_vars_from_xml(xml_full_path)
|
existing_vars_data = read_vars_from_xml(xml_full_path)
|
||||||
|
|
||||||
# --- Новый блок: формируем атрибуты корневого тега ---
|
# --- Новый блок: формируем атрибуты корневого тега с относительными путями ---
|
||||||
analysis_attrs = {"proj_path": proj_path}
|
proj_path = os.path.abspath(proj_path)
|
||||||
|
analysis_attrs = {
|
||||||
|
"proj_path": proj_path.replace("\\", "/")
|
||||||
|
}
|
||||||
|
|
||||||
if makefile_path:
|
if makefile_path:
|
||||||
analysis_attrs["makefile_path"] = makefile_path
|
rel_makefile = myXML.make_relative_path(makefile_path, proj_path)
|
||||||
|
if not os.path.isabs(rel_makefile):
|
||||||
|
analysis_attrs["makefile_path"] = rel_makefile.replace("\\", "/")
|
||||||
|
|
||||||
if structs_xml_path:
|
if structs_xml_path:
|
||||||
analysis_attrs["structs_path"] = structs_xml_path
|
rel_struct = myXML.make_relative_path(structs_xml_path, proj_path)
|
||||||
|
if not os.path.isabs(rel_struct):
|
||||||
|
analysis_attrs["structs_path"] = rel_struct.replace("\\", "/")
|
||||||
|
|
||||||
|
|
||||||
root = ET.Element("analysis", attrib=analysis_attrs)
|
root = ET.Element("analysis", attrib=analysis_attrs)
|
||||||
|
|
||||||
@@ -555,7 +633,7 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
|
|||||||
'shortname': info.get('shortname', name),
|
'shortname': info.get('shortname', name),
|
||||||
'pt_type': info.get('pt_type', ''),
|
'pt_type': info.get('pt_type', ''),
|
||||||
'iq_type': info.get('iq_type', ''),
|
'iq_type': info.get('iq_type', ''),
|
||||||
'return_type': info.get('return_type', 'int'),
|
'return_type': info.get('return_type', 't_iq_none'),
|
||||||
'type': info.get('type', 'unknown'),
|
'type': info.get('type', 'unknown'),
|
||||||
'file': info.get('file', ''),
|
'file': info.get('file', ''),
|
||||||
'extern': info.get('extern', False),
|
'extern': info.get('extern', False),
|
||||||
@@ -574,10 +652,10 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
|
|||||||
ET.SubElement(var_elem, "shortname").text = info.get('shortname', name)
|
ET.SubElement(var_elem, "shortname").text = info.get('shortname', name)
|
||||||
ET.SubElement(var_elem, "pt_type").text = info.get('pt_type', '')
|
ET.SubElement(var_elem, "pt_type").text = info.get('pt_type', '')
|
||||||
ET.SubElement(var_elem, "iq_type").text = info.get('iq_type', '')
|
ET.SubElement(var_elem, "iq_type").text = info.get('iq_type', '')
|
||||||
ET.SubElement(var_elem, "return_type").text = info.get('return_type', 'int')
|
ET.SubElement(var_elem, "return_type").text = info.get('return_type', 't_iq_none')
|
||||||
|
|
||||||
ET.SubElement(var_elem, "type").text = info.get('type', 'unknown')
|
ET.SubElement(var_elem, "type").text = info.get('type', 'unknown')
|
||||||
rel_file = os.path.relpath(info.get('file', ''), proj_path) if info.get('file') else ''
|
rel_file = make_relative_if_possible(info.get('file', ''), proj_path).replace("\\", "/")
|
||||||
ET.SubElement(var_elem, "file").text = rel_file.replace("\\", "/") if rel_file else ''
|
ET.SubElement(var_elem, "file").text = rel_file.replace("\\", "/") if rel_file else ''
|
||||||
ET.SubElement(var_elem, "extern").text = str(info.get('extern', False)).lower()
|
ET.SubElement(var_elem, "extern").text = str(info.get('extern', False)).lower()
|
||||||
ET.SubElement(var_elem, "static").text = str(info.get('static', False)).lower()
|
ET.SubElement(var_elem, "static").text = str(info.get('static', False)).lower()
|
||||||
@@ -598,12 +676,7 @@ def generate_xml_output(proj_path, xml_path, unique_vars, h_files_needed, vars_n
|
|||||||
ET.SubElement(var_elem, "file").text = rel_file.replace("\\", "/")
|
ET.SubElement(var_elem, "file").text = rel_file.replace("\\", "/")
|
||||||
|
|
||||||
# Форматирование с отступами
|
# Форматирование с отступами
|
||||||
rough_string = ET.tostring(root, encoding="utf-8")
|
myXML.fwrite(root, xml_full_path)
|
||||||
reparsed = minidom.parseString(rough_string)
|
|
||||||
pretty_xml = reparsed.toprettyxml(indent=" ")
|
|
||||||
|
|
||||||
with open(xml_full_path, "w", encoding="utf-8") as f:
|
|
||||||
f.write(pretty_xml)
|
|
||||||
|
|
||||||
optional_printf(PRINT_STATUS, f"[XML] Variables saved to {xml_full_path}")
|
optional_printf(PRINT_STATUS, f"[XML] Variables saved to {xml_full_path}")
|
||||||
|
|
||||||
@@ -645,12 +718,7 @@ def write_typedefs_and_structs_to_xml(proj_path, xml_path, typedefs, structs):
|
|||||||
ET.SubElement(typedefs_elem, "typedef", name=name, type=underlying)
|
ET.SubElement(typedefs_elem, "typedef", name=name, type=underlying)
|
||||||
|
|
||||||
# Преобразуем в красиво отформатированную XML-строку
|
# Преобразуем в красиво отформатированную XML-строку
|
||||||
rough_string = ET.tostring(root, encoding="utf-8")
|
myXML.fwrite(root, xml_full_path)
|
||||||
reparsed = minidom.parseString(rough_string)
|
|
||||||
pretty_xml = reparsed.toprettyxml(indent=" ")
|
|
||||||
|
|
||||||
with open(xml_full_path, "w", encoding="utf-8") as f:
|
|
||||||
f.write(pretty_xml)
|
|
||||||
|
|
||||||
print(f"[XML] Typedefs and structs saved to: {xml_full_path}")
|
print(f"[XML] Typedefs and structs saved to: {xml_full_path}")
|
||||||
|
|
||||||
@@ -812,10 +880,10 @@ Usage example:
|
|||||||
print(f"Error: Makefile path '{makefile_path}' does not exist.")
|
print(f"Error: Makefile path '{makefile_path}' does not exist.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
c_files, h_files, include_dirs = parse_makefile(makefile_path)
|
c_files, h_files, include_dirs, global_defs = parse_project(makefile_path, proj_path)
|
||||||
|
|
||||||
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs)
|
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs, global_defs)
|
||||||
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs)
|
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs)
|
||||||
|
|
||||||
vars = dict(sorted(vars.items()))
|
vars = dict(sorted(vars.items()))
|
||||||
includes = get_sorted_headers(c_files, includes, include_dirs)
|
includes = get_sorted_headers(c_files, includes, include_dirs)
|
||||||
@@ -855,10 +923,10 @@ def run_scan(proj_path, makefile_path, output_xml, verbose=2):
|
|||||||
if not os.path.isfile(makefile_path):
|
if not os.path.isfile(makefile_path):
|
||||||
raise FileNotFoundError(f"Makefile path '{makefile_path}' does not exist.")
|
raise FileNotFoundError(f"Makefile path '{makefile_path}' does not exist.")
|
||||||
|
|
||||||
c_files, h_files, include_dirs = parse_makefile(makefile_path)
|
c_files, h_files, include_dirs, global_defs = parse_project(makefile_path, proj_path)
|
||||||
|
|
||||||
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs)
|
vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs, global_defs)
|
||||||
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs)
|
typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs, global_defs)
|
||||||
|
|
||||||
vars = dict(sorted(vars.items()))
|
vars = dict(sorted(vars.items()))
|
||||||
includes = get_sorted_headers(c_files, includes, include_dirs)
|
includes = get_sorted_headers(c_files, includes, include_dirs)
|
||||||
@@ -866,9 +934,14 @@ def run_scan(proj_path, makefile_path, output_xml, verbose=2):
|
|||||||
typedefs = dict(sorted(typedefs.items()))
|
typedefs = dict(sorted(typedefs.items()))
|
||||||
structs = dict(sorted(structs.items()))
|
structs = dict(sorted(structs.items()))
|
||||||
|
|
||||||
|
print('Progress: "Writting XML..."')
|
||||||
|
print("Progress: 0/2")
|
||||||
print("[XML] Creating structs.xml...")
|
print("[XML] Creating structs.xml...")
|
||||||
structs_xml = os.path.join(os.path.dirname(output_xml), "structs.xml")
|
structs_xml = os.path.join(os.path.dirname(output_xml), "structs.xml")
|
||||||
write_typedefs_and_structs_to_xml(proj_path, structs_xml, typedefs, structs)
|
write_typedefs_and_structs_to_xml(proj_path, structs_xml, typedefs, structs)
|
||||||
|
print("Progress: 1/2")
|
||||||
|
|
||||||
print("[XML] Creating vars.xml...")
|
print("[XML] Creating vars.xml...")
|
||||||
generate_xml_output(proj_path, output_xml, vars, includes, externs, structs_xml, makefile_path)
|
generate_xml_output(proj_path, output_xml, vars, includes, externs, structs_xml, makefile_path)
|
||||||
|
print('Progress: "Done"')
|
||||||
|
print("Progress: 2/2")
|
||||||
250
Src/setupVars.py
250
Src/setupVars.py
@@ -1,250 +0,0 @@
|
|||||||
import sys
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
from generateVars import map_type_to_pt, get_iq_define, type_map
|
|
||||||
from enum import IntEnum
|
|
||||||
from scanVars import *
|
|
||||||
from generateVars import *
|
|
||||||
|
|
||||||
|
|
||||||
def make_absolute_path(path, base_path):
|
|
||||||
if not os.path.isabs(path) and os.path.isdir(base_path):
|
|
||||||
try:
|
|
||||||
return os.path.abspath(os.path.join(base_path, path))
|
|
||||||
except Exception:
|
|
||||||
pass # На случай сбоя в os.path.join или abspath
|
|
||||||
elif os.path.isabs(path):
|
|
||||||
return os.path.abspath(path)
|
|
||||||
else:
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def make_relative_path(abs_path, base_path):
|
|
||||||
abs_path = os.path.abspath(abs_path)
|
|
||||||
base_path = os.path.abspath(base_path)
|
|
||||||
|
|
||||||
# Разбиваем на списки директорий
|
|
||||||
abs_parts = abs_path.split(os.sep)
|
|
||||||
base_parts = base_path.split(os.sep)
|
|
||||||
|
|
||||||
# Проверяем, является ли base_path настоящим префиксом пути (по папкам)
|
|
||||||
if abs_parts[:len(base_parts)] == base_parts:
|
|
||||||
rel_parts = abs_parts[len(base_parts):]
|
|
||||||
return "/".join(rel_parts)
|
|
||||||
|
|
||||||
# Иначе пробуем relpath
|
|
||||||
try:
|
|
||||||
return os.path.relpath(abs_path, base_path).replace("\\", "/")
|
|
||||||
except Exception:
|
|
||||||
return abs_path.replace("\\", "/")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_vars(filename, typedef_map=None):
|
|
||||||
root, tree = safe_parse_xml(filename)
|
|
||||||
if root is None:
|
|
||||||
return []
|
|
||||||
|
|
||||||
if typedef_map is None:
|
|
||||||
typedef_map = {}
|
|
||||||
|
|
||||||
vars_list = []
|
|
||||||
variables_elem = root.find('variables')
|
|
||||||
if variables_elem is not None:
|
|
||||||
for var in variables_elem.findall('var'):
|
|
||||||
name = var.attrib.get('name', '')
|
|
||||||
var_type = var.findtext('type', 'unknown').strip()
|
|
||||||
|
|
||||||
# Вычисляем pt_type и iq_type
|
|
||||||
pt_type = var.findtext('pt_type')
|
|
||||||
if not pt_type:
|
|
||||||
pt_type = map_type_to_pt(var_type, name, typedef_map)
|
|
||||||
|
|
||||||
iq_type = var.findtext('iq_type')
|
|
||||||
if not iq_type:
|
|
||||||
iq_type = get_iq_define(var_type)
|
|
||||||
|
|
||||||
vars_list.append({
|
|
||||||
'name': name,
|
|
||||||
'show_var': var.findtext('show_var', 'false'),
|
|
||||||
'enable': var.findtext('enable', 'false'),
|
|
||||||
'shortname': var.findtext('shortname', name),
|
|
||||||
'pt_type': pt_type,
|
|
||||||
'iq_type': iq_type,
|
|
||||||
'return_type': var.findtext('return_type', 'int'),
|
|
||||||
'type': var_type,
|
|
||||||
'file': var.findtext('file', ''),
|
|
||||||
'extern': var.findtext('extern', 'false') == 'true',
|
|
||||||
'static': var.findtext('static', 'false') == 'true',
|
|
||||||
})
|
|
||||||
|
|
||||||
return vars_list
|
|
||||||
|
|
||||||
|
|
||||||
# 2. Парсим structSup.xml
|
|
||||||
def parse_structs(filename):
|
|
||||||
root, tree = safe_parse_xml(filename)
|
|
||||||
if root is None:
|
|
||||||
return {}, {}
|
|
||||||
|
|
||||||
structs = {}
|
|
||||||
typedef_map = {}
|
|
||||||
|
|
||||||
def parse_struct_element(elem):
|
|
||||||
fields = {}
|
|
||||||
|
|
||||||
for field in elem.findall("field"):
|
|
||||||
fname = field.attrib.get("name")
|
|
||||||
ftype = field.attrib.get("type", "")
|
|
||||||
|
|
||||||
# Проверка на вложенную структуру
|
|
||||||
nested_struct_elem = field.find("struct")
|
|
||||||
|
|
||||||
if nested_struct_elem is not None:
|
|
||||||
# Рекурсивно парсим вложенную структуру и вставляем её как подсловарь
|
|
||||||
nested_fields = parse_struct_element(nested_struct_elem)
|
|
||||||
|
|
||||||
# Оборачиваем в dict с ключом 'type' для хранения типа из XML
|
|
||||||
fields[fname] = {
|
|
||||||
'type': ftype, # здесь тип, например "BENDER_ERROR"
|
|
||||||
**nested_fields # развёрнутые поля вложенной структуры
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# Обычное поле
|
|
||||||
fields[fname] = ftype
|
|
||||||
|
|
||||||
return fields
|
|
||||||
|
|
||||||
structs_elem = root.find("structs")
|
|
||||||
if structs_elem is not None:
|
|
||||||
for struct in structs_elem.findall("struct"):
|
|
||||||
name = struct.attrib.get("name")
|
|
||||||
if name and name not in structs:
|
|
||||||
fields = parse_struct_element(struct)
|
|
||||||
structs[name] = fields
|
|
||||||
|
|
||||||
# typedefs без изменений
|
|
||||||
typedefs_elem = root.find("typedefs")
|
|
||||||
if typedefs_elem is not None:
|
|
||||||
for typedef in typedefs_elem.findall("typedef"):
|
|
||||||
name = typedef.attrib.get('name')
|
|
||||||
target_type = typedef.attrib.get('type')
|
|
||||||
if name and target_type:
|
|
||||||
typedef_map[name.strip()] = target_type.strip()
|
|
||||||
|
|
||||||
return structs, typedef_map
|
|
||||||
|
|
||||||
|
|
||||||
def safe_parse_xml(xml_path):
|
|
||||||
"""
|
|
||||||
Безопасно парсит XML-файл.
|
|
||||||
|
|
||||||
Возвращает кортеж (root, tree) или (None, None) при ошибках.
|
|
||||||
"""
|
|
||||||
if not xml_path or not os.path.isfile(xml_path):
|
|
||||||
#print(f"Файл '{xml_path}' не найден или путь пустой")
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
try:
|
|
||||||
if os.path.getsize(xml_path) == 0:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
tree = ET.parse(xml_path)
|
|
||||||
root = tree.getroot()
|
|
||||||
return root, tree
|
|
||||||
|
|
||||||
except ET.ParseError as e:
|
|
||||||
print(f"Ошибка парсинга XML файла '{xml_path}': {e}")
|
|
||||||
return None, None
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Неожиданная ошибка при чтении XML файла '{xml_path}': {e}")
|
|
||||||
return None, None
|
|
||||||
def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, depth=0):
|
|
||||||
if depth > 10:
|
|
||||||
return []
|
|
||||||
|
|
||||||
# Если type_str — словарь структуры
|
|
||||||
if isinstance(type_str, dict):
|
|
||||||
fields = type_str
|
|
||||||
else:
|
|
||||||
base_type = strip_ptr_and_array(type_str)
|
|
||||||
fields = structs.get(base_type)
|
|
||||||
if not isinstance(fields, dict):
|
|
||||||
return []
|
|
||||||
|
|
||||||
children = []
|
|
||||||
for field_name, field_value in fields.items():
|
|
||||||
# Пропускаем поле 'type', оно служит для хранения имени типа
|
|
||||||
if field_name == 'type':
|
|
||||||
continue
|
|
||||||
|
|
||||||
full_name = f"{prefix}.{field_name}"
|
|
||||||
|
|
||||||
if isinstance(field_value, dict):
|
|
||||||
# Если вложенная структура — берем её имя типа из поля 'type' или пустую строку
|
|
||||||
type_name = field_value.get('type', '')
|
|
||||||
child = {
|
|
||||||
'name': full_name,
|
|
||||||
'type': type_name,
|
|
||||||
'pt_type': '',
|
|
||||||
'file': var_attrs.get('file'),
|
|
||||||
'extern': var_attrs.get('extern'),
|
|
||||||
'static': var_attrs.get('static'),
|
|
||||||
}
|
|
||||||
# Рекурсивно раскрываем вложенные поля
|
|
||||||
subchildren = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1)
|
|
||||||
if subchildren:
|
|
||||||
child['children'] = subchildren
|
|
||||||
else:
|
|
||||||
# Простое поле — строка типа
|
|
||||||
# Пропускаем указатели на функции
|
|
||||||
if isinstance(field_value, str) and "(" in field_value and "*" in field_value and ")" in field_value:
|
|
||||||
continue
|
|
||||||
|
|
||||||
child = {
|
|
||||||
'name': full_name,
|
|
||||||
'type': field_value,
|
|
||||||
'pt_type': '',
|
|
||||||
'file': var_attrs.get('file'),
|
|
||||||
'extern': var_attrs.get('extern'),
|
|
||||||
'static': var_attrs.get('static'),
|
|
||||||
}
|
|
||||||
|
|
||||||
children.append(child)
|
|
||||||
|
|
||||||
return children
|
|
||||||
|
|
||||||
|
|
||||||
def expand_vars(vars_list, structs, typedefs):
|
|
||||||
"""
|
|
||||||
Раскрывает структуры и массивы структур в деревья.
|
|
||||||
"""
|
|
||||||
expanded = []
|
|
||||||
|
|
||||||
for var in vars_list:
|
|
||||||
pt_type = var.get('pt_type', '')
|
|
||||||
raw_type = var.get('type', '')
|
|
||||||
base_type = strip_ptr_and_array(raw_type)
|
|
||||||
|
|
||||||
fields = structs.get(base_type)
|
|
||||||
|
|
||||||
if pt_type.startswith('pt_arr_') and isinstance(fields, dict):
|
|
||||||
new_var = var.copy()
|
|
||||||
new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var)
|
|
||||||
expanded.append(new_var)
|
|
||||||
|
|
||||||
elif pt_type == 'pt_struct' and isinstance(fields, dict):
|
|
||||||
new_var = var.copy()
|
|
||||||
new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var)
|
|
||||||
expanded.append(new_var)
|
|
||||||
|
|
||||||
elif pt_type == 'pt_union' and isinstance(fields, dict):
|
|
||||||
new_var = var.copy()
|
|
||||||
new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var)
|
|
||||||
expanded.append(new_var)
|
|
||||||
|
|
||||||
else:
|
|
||||||
expanded.append(var)
|
|
||||||
|
|
||||||
return expanded
|
|
||||||
|
|
||||||
@@ -1,753 +0,0 @@
|
|||||||
# build command
|
|
||||||
# pyinstaller --onefile --name DebugVarEdit --add-binary "build/libclang.dll;build" --distpath ./ --workpath ./build_temp --specpath ./build_temp setupVars_GUI.py
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
from generateVars import type_map
|
|
||||||
from enum import IntEnum
|
|
||||||
import threading
|
|
||||||
from scanVars import run_scan
|
|
||||||
from generateVars import run_generate
|
|
||||||
from setupVars import *
|
|
||||||
from VariableSelector import *
|
|
||||||
|
|
||||||
from PySide6.QtWidgets import (
|
|
||||||
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
|
||||||
QCheckBox, QComboBox, QLineEdit, QVBoxLayout, QHBoxLayout, QPushButton,
|
|
||||||
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit,
|
|
||||||
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy
|
|
||||||
)
|
|
||||||
from PySide6.QtGui import QTextCursor, QKeyEvent
|
|
||||||
from PySide6.QtCore import Qt, QProcess, QObject, Signal, QTimer
|
|
||||||
|
|
||||||
|
|
||||||
class rows(IntEnum):
|
|
||||||
No = 0
|
|
||||||
include = 1
|
|
||||||
name = 2
|
|
||||||
type = 3
|
|
||||||
pt_type = 4
|
|
||||||
iq_type = 5
|
|
||||||
ret_type = 6
|
|
||||||
short_name = 7
|
|
||||||
|
|
||||||
|
|
||||||
class EmittingStream(QObject):
|
|
||||||
text_written = Signal(str)
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self._buffer = ""
|
|
||||||
|
|
||||||
def write(self, text):
|
|
||||||
self._buffer += text
|
|
||||||
while '\n' in self._buffer:
|
|
||||||
line, self._buffer = self._buffer.split('\n', 1)
|
|
||||||
# Отправляем строку без '\n'
|
|
||||||
self.text_written.emit(line)
|
|
||||||
|
|
||||||
def flush(self):
|
|
||||||
if self._buffer:
|
|
||||||
self.text_written.emit(self._buffer)
|
|
||||||
self._buffer = ""
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessOutputWindowDummy(QWidget):
|
|
||||||
def __init__(self, on_done_callback):
|
|
||||||
super().__init__()
|
|
||||||
self.setWindowTitle("Поиск переменных...")
|
|
||||||
self.resize(600, 400)
|
|
||||||
|
|
||||||
self.layout = QVBoxLayout(self)
|
|
||||||
self.output_edit = QTextEdit()
|
|
||||||
self.output_edit.setReadOnly(True)
|
|
||||||
self.layout.addWidget(self.output_edit)
|
|
||||||
|
|
||||||
self.btn_close = QPushButton("Закрыть")
|
|
||||||
self.btn_close.setEnabled(False)
|
|
||||||
self.layout.addWidget(self.btn_close)
|
|
||||||
|
|
||||||
self.btn_close.clicked.connect(self.__handle_done)
|
|
||||||
self._on_done_callback = on_done_callback
|
|
||||||
|
|
||||||
def __handle_done(self):
|
|
||||||
if self._on_done_callback:
|
|
||||||
self._on_done_callback()
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def append_text(self, text):
|
|
||||||
cursor = self.output_edit.textCursor()
|
|
||||||
cursor.movePosition(QTextCursor.End)
|
|
||||||
for line in text.splitlines():
|
|
||||||
self.output_edit.append(line)
|
|
||||||
self.output_edit.setTextCursor(cursor)
|
|
||||||
self.output_edit.ensureCursorVisible()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 3. UI: таблица с переменными
|
|
||||||
class VarEditor(QWidget):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.vars_list = []
|
|
||||||
self.structs = {}
|
|
||||||
self.typedef_map = {}
|
|
||||||
|
|
||||||
self.proj_path = None
|
|
||||||
self.xml_path = None
|
|
||||||
self.makefile_path = None
|
|
||||||
self.structs_path = None
|
|
||||||
self.output_path = None
|
|
||||||
self._updating = False # Флаг блокировки рекурсии
|
|
||||||
self._resizing = False # флаг блокировки повторного вызова
|
|
||||||
self.initUI()
|
|
||||||
|
|
||||||
def initUI(self):
|
|
||||||
self.setWindowTitle("Variable Editor")
|
|
||||||
|
|
||||||
# --- Поля ввода пути проекта и XML ---
|
|
||||||
|
|
||||||
# XML Output
|
|
||||||
xml_layout = QHBoxLayout()
|
|
||||||
xml_layout.addWidget(QLabel("XML Output:"))
|
|
||||||
self.xml_output_edit = QLineEdit()
|
|
||||||
self.xml_output_edit.returnPressed.connect(self.update)
|
|
||||||
self.xml_output_edit.textChanged.connect(self.__on_xml_path_changed)
|
|
||||||
xml_layout.addWidget(self.xml_output_edit)
|
|
||||||
btn_xml_browse = QPushButton("...")
|
|
||||||
btn_xml_browse.setFixedWidth(30)
|
|
||||||
xml_layout.addWidget(btn_xml_browse)
|
|
||||||
btn_xml_browse.clicked.connect(self.__browse_xml_output)
|
|
||||||
|
|
||||||
# Project Path
|
|
||||||
proj_layout = QHBoxLayout()
|
|
||||||
proj_layout.addWidget(QLabel("Project Path:"))
|
|
||||||
self.proj_path_edit = QLineEdit()
|
|
||||||
self.proj_path_edit.returnPressed.connect(self.update)
|
|
||||||
self.proj_path_edit.textChanged.connect(self.__on_proj_path_changed)
|
|
||||||
proj_layout.addWidget(self.proj_path_edit)
|
|
||||||
btn_proj_browse = QPushButton("...")
|
|
||||||
btn_proj_browse.setFixedWidth(30)
|
|
||||||
proj_layout.addWidget(btn_proj_browse)
|
|
||||||
btn_proj_browse.clicked.connect(self.__browse_proj_path)
|
|
||||||
|
|
||||||
# Makefile Path
|
|
||||||
makefile_layout = QHBoxLayout()
|
|
||||||
makefile_layout.addWidget(QLabel("Makefile Path (relative path):"))
|
|
||||||
self.makefile_edit = QLineEdit()
|
|
||||||
self.makefile_edit.returnPressed.connect(self.update)
|
|
||||||
self.makefile_edit.textChanged.connect(self.__on_makefile_path_changed)
|
|
||||||
makefile_layout.addWidget(self.makefile_edit)
|
|
||||||
btn_makefile_browse = QPushButton("...")
|
|
||||||
btn_makefile_browse.setFixedWidth(30)
|
|
||||||
makefile_layout.addWidget(btn_makefile_browse)
|
|
||||||
btn_makefile_browse.clicked.connect(self.__browse_makefile)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Source Output File/Directory
|
|
||||||
source_output_layout = QHBoxLayout()
|
|
||||||
source_output_layout.addWidget(QLabel("Source Output File:"))
|
|
||||||
self.source_output_edit = QLineEdit()
|
|
||||||
source_output_layout.addWidget(self.source_output_edit)
|
|
||||||
btn_source_output_browse = QPushButton("...")
|
|
||||||
btn_source_output_browse.setFixedWidth(30)
|
|
||||||
source_output_layout.addWidget(btn_source_output_browse)
|
|
||||||
btn_source_output_browse.clicked.connect(self.__browse_source_output)
|
|
||||||
|
|
||||||
|
|
||||||
self.btn_update_vars = QPushButton("Обновить данные о переменных")
|
|
||||||
self.btn_update_vars.clicked.connect(self.update_vars_data)
|
|
||||||
|
|
||||||
# Таблица переменных
|
|
||||||
self.table = QTableWidget(len(self.vars_list), 8)
|
|
||||||
self.table.setHorizontalHeaderLabels([
|
|
||||||
'№', # новый столбец
|
|
||||||
'En',
|
|
||||||
'Name',
|
|
||||||
'Origin Type',
|
|
||||||
'Pointer Type',
|
|
||||||
'IQ Type',
|
|
||||||
'Return Type',
|
|
||||||
'Short Name'
|
|
||||||
])
|
|
||||||
self.table.setEditTriggers(QAbstractItemView.AllEditTriggers)
|
|
||||||
|
|
||||||
# Кнопка сохранения
|
|
||||||
btn_save = QPushButton("Build")
|
|
||||||
btn_save.clicked.connect(self.save_build)
|
|
||||||
|
|
||||||
# Кнопка добавления переменных
|
|
||||||
self.btn_add_vars = QPushButton("Add Variables")
|
|
||||||
self.btn_add_vars.clicked.connect(self.__open_variable_selector)
|
|
||||||
|
|
||||||
|
|
||||||
# Основной layout
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.addLayout(xml_layout)
|
|
||||||
layout.addLayout(proj_layout)
|
|
||||||
layout.addLayout(makefile_layout)
|
|
||||||
layout.addWidget(self.btn_update_vars)
|
|
||||||
layout.addWidget(self.table)
|
|
||||||
layout.addWidget(self.btn_add_vars)
|
|
||||||
layout.addLayout(source_output_layout)
|
|
||||||
layout.addWidget(btn_save)
|
|
||||||
|
|
||||||
|
|
||||||
header = self.table.horizontalHeader()
|
|
||||||
# Для остальных колонок — растяжение (Stretch), чтобы они заняли всю оставшуюся ширину
|
|
||||||
|
|
||||||
for col in range(self.table.columnCount()):
|
|
||||||
if col == self.table.columnCount() - 1:
|
|
||||||
header.setSectionResizeMode(col, QHeaderView.Stretch)
|
|
||||||
else:
|
|
||||||
header.setSectionResizeMode(col, QHeaderView.Interactive)
|
|
||||||
|
|
||||||
parent_widget = self.table.parentWidget()
|
|
||||||
if parent_widget:
|
|
||||||
w = parent_widget.width()
|
|
||||||
h = parent_widget.height()
|
|
||||||
viewport_width = self.table.viewport().width()
|
|
||||||
# Сделаем колонки с номерами фиксированной ширины
|
|
||||||
self.table.setColumnWidth(rows.No, 30)
|
|
||||||
self.table.setColumnWidth(rows.include, 30)
|
|
||||||
self.table.setColumnWidth(rows.pt_type, 85)
|
|
||||||
self.table.setColumnWidth(rows.iq_type, 85)
|
|
||||||
self.table.setColumnWidth(rows.ret_type, 85)
|
|
||||||
|
|
||||||
self.table.setColumnWidth(rows.name, 300)
|
|
||||||
self.table.setColumnWidth(rows.type, 100)
|
|
||||||
|
|
||||||
self.table.horizontalHeader().sectionResized.connect(self.on_section_resized)
|
|
||||||
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
|
|
||||||
def on_section_resized(self, logicalIndex, oldSize, newSize):
|
|
||||||
if self._resizing:
|
|
||||||
return # предотвращаем рекурсию
|
|
||||||
|
|
||||||
min_width = 50
|
|
||||||
delta = newSize - oldSize
|
|
||||||
right_index = logicalIndex + 1
|
|
||||||
|
|
||||||
if right_index >= self.table.columnCount():
|
|
||||||
# Если правая колока - нет соседа, ограничиваем минимальную ширину
|
|
||||||
if newSize < min_width:
|
|
||||||
self._resizing = True
|
|
||||||
self.table.setColumnWidth(logicalIndex, min_width)
|
|
||||||
self._resizing = False
|
|
||||||
return
|
|
||||||
|
|
||||||
self._resizing = True
|
|
||||||
try:
|
|
||||||
right_width = self.table.columnWidth(right_index)
|
|
||||||
new_right_width = right_width - delta
|
|
||||||
|
|
||||||
# Если соседняя колонка станет уже минимальной - подкорректируем левую
|
|
||||||
if new_right_width < min_width:
|
|
||||||
new_right_width = min_width
|
|
||||||
newSize = oldSize + (right_width - min_width)
|
|
||||||
self.table.setColumnWidth(logicalIndex, newSize)
|
|
||||||
|
|
||||||
self.table.setColumnWidth(right_index, new_right_width)
|
|
||||||
finally:
|
|
||||||
self._resizing = False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_xml_path(self):
|
|
||||||
xml_path = self.xml_output_edit.text().strip()
|
|
||||||
return xml_path
|
|
||||||
|
|
||||||
def get_proj_path(self):
|
|
||||||
proj_path = self.proj_path_edit.text().strip()
|
|
||||||
return proj_path
|
|
||||||
|
|
||||||
def get_makefile_path(self):
|
|
||||||
proj_path = self.get_proj_path()
|
|
||||||
makefile_path = make_absolute_path(self.makefile_edit.text().strip(), proj_path)
|
|
||||||
return makefile_path
|
|
||||||
|
|
||||||
def get_struct_path(self):
|
|
||||||
proj_path = self.get_proj_path()
|
|
||||||
xml_path = self.get_xml_path()
|
|
||||||
root, tree = safe_parse_xml(xml_path)
|
|
||||||
if root is None:
|
|
||||||
return
|
|
||||||
# --- structs_path из атрибута ---
|
|
||||||
structs_path = root.attrib.get('structs_path', '').strip()
|
|
||||||
structs_path_full = make_absolute_path(structs_path, proj_path)
|
|
||||||
if structs_path_full and os.path.isfile(structs_path_full):
|
|
||||||
structs_path = structs_path_full
|
|
||||||
else:
|
|
||||||
structs_path = None
|
|
||||||
return structs_path
|
|
||||||
|
|
||||||
def get_output_path(self):
|
|
||||||
output_path = os.path.abspath(self.source_output_edit.text().strip())
|
|
||||||
return output_path
|
|
||||||
|
|
||||||
def update_all_paths(self):
|
|
||||||
self.proj_path = self.get_proj_path()
|
|
||||||
self.xml_path = self.get_xml_path()
|
|
||||||
self.makefile_path = self.get_makefile_path()
|
|
||||||
self.structs_path = self.get_struct_path()
|
|
||||||
self.output_path = self.get_output_path()
|
|
||||||
|
|
||||||
|
|
||||||
def update_vars_data(self):
|
|
||||||
self.update_all_paths()
|
|
||||||
|
|
||||||
if not self.proj_path or not self.xml_path:
|
|
||||||
QMessageBox.warning(self, "Ошибка", "Укажите пути проекта и XML.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not os.path.isfile(self.makefile_path):
|
|
||||||
QMessageBox.warning(self, "Ошибка", f"Makefile не найден:\n{self.makefile_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# Создаём окно с кнопкой "Готово"
|
|
||||||
self.proc_win = ProcessOutputWindowDummy(self.__after_scanvars_finished)
|
|
||||||
self.proc_win.show()
|
|
||||||
|
|
||||||
self.emitting_stream = EmittingStream()
|
|
||||||
self.emitting_stream.text_written.connect(self.proc_win.append_text)
|
|
||||||
|
|
||||||
def run_scan_wrapper():
|
|
||||||
try:
|
|
||||||
old_stdout = sys.stdout
|
|
||||||
sys.stdout = self.emitting_stream
|
|
||||||
|
|
||||||
run_scan(self.proj_path, self.makefile_path, self.xml_path)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.emitting_stream.text_written.emit(f"\n[ОШИБКА] {e}")
|
|
||||||
finally:
|
|
||||||
sys.stdout = old_stdout
|
|
||||||
self.emitting_stream.text_written.emit("\n--- Анализ завершён ---")
|
|
||||||
self.proc_win.btn_close.setEnabled(True)
|
|
||||||
|
|
||||||
threading.Thread(target=run_scan_wrapper, daemon=True).start()
|
|
||||||
|
|
||||||
|
|
||||||
def save_build(self):
|
|
||||||
vars_out = []
|
|
||||||
for row in range(self.table.rowCount()):
|
|
||||||
include_cb = self.table.cellWidget(row, rows.include)
|
|
||||||
if not include_cb.isChecked():
|
|
||||||
continue
|
|
||||||
name_edit = self.table.cellWidget(row, rows.name)
|
|
||||||
pt_type_combo = self.table.cellWidget(row, rows.pt_type)
|
|
||||||
iq_combo = self.table.cellWidget(row, rows.iq_type)
|
|
||||||
ret_combo = self.table.cellWidget(row, rows.ret_type)
|
|
||||||
short_name_edit = self.table.cellWidget(row, rows.short_name)
|
|
||||||
|
|
||||||
var_data = {
|
|
||||||
'name': name_edit.text(),
|
|
||||||
'type': 'pt_' + pt_type_combo.currentText(),
|
|
||||||
'iq_type': iq_combo.currentText(),
|
|
||||||
'return_type': ret_combo.currentText() if ret_combo.currentText() else 'int',
|
|
||||||
'short_name': short_name_edit.text(),
|
|
||||||
}
|
|
||||||
vars_out.append(var_data)
|
|
||||||
|
|
||||||
self.update_all_paths()
|
|
||||||
|
|
||||||
if not self.proj_path or not self.xml_path or not self.output_path:
|
|
||||||
QMessageBox.warning(self, "Ошибка", "Заполните все пути: проект, XML и output.")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
run_generate(self.proj_path, self.xml_path, self.output_path)
|
|
||||||
QMessageBox.information(self, "Готово", "Файл debug_vars.c успешно сгенерирован.")
|
|
||||||
self.update()
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.critical(self, "Ошибка при генерации", str(e))
|
|
||||||
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
if self._updating:
|
|
||||||
return # Уже в процессе обновления — выходим, чтобы избежать рекурсии
|
|
||||||
self._updating = True
|
|
||||||
|
|
||||||
self.update_all_paths()
|
|
||||||
try:
|
|
||||||
if self.xml_path and not os.path.isfile(self.xml_path):
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
root, tree = safe_parse_xml(self.xml_path)
|
|
||||||
if root is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
if not self.proj_path:
|
|
||||||
# Если в поле ничего нет, пробуем взять из XML
|
|
||||||
proj_path_from_xml = root.attrib.get('proj_path', '').strip()
|
|
||||||
if proj_path_from_xml and os.path.isdir(proj_path_from_xml):
|
|
||||||
self.proj_path = proj_path_from_xml
|
|
||||||
self.proj_path_edit.setText(proj_path_from_xml)
|
|
||||||
else:
|
|
||||||
QMessageBox.warning(
|
|
||||||
self,
|
|
||||||
"Внимание",
|
|
||||||
"Путь к проекту (proj_path) не найден или не существует.\n"
|
|
||||||
"Пожалуйста, укажите его вручную в поле 'Project Path'."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if not os.path.isdir(self.proj_path):
|
|
||||||
QMessageBox.warning(
|
|
||||||
self,
|
|
||||||
"Внимание",
|
|
||||||
f"Указанный путь к проекту не существует:\n{self.proj_path}\n"
|
|
||||||
"Пожалуйста, исправьте путь в поле 'Project Path'."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if not self.makefile_path:
|
|
||||||
# --- makefile_path из атрибута ---
|
|
||||||
makefile_path = root.attrib.get('makefile_path', '').strip()
|
|
||||||
makefile_path_full = make_absolute_path(makefile_path, self.proj_path)
|
|
||||||
if makefile_path_full and os.path.isfile(makefile_path_full):
|
|
||||||
self.makefile_edit.setText(makefile_path)
|
|
||||||
else:
|
|
||||||
self.makefile_path = None
|
|
||||||
|
|
||||||
if not self.structs_path:
|
|
||||||
# --- structs_path из атрибута ---
|
|
||||||
structs_path = root.attrib.get('structs_path', '').strip()
|
|
||||||
structs_path_full = make_absolute_path(structs_path, self.proj_path)
|
|
||||||
if structs_path_full and os.path.isfile(structs_path_full):
|
|
||||||
self.structs_path = structs_path_full
|
|
||||||
self.structs, self.typedef_map = parse_structs(structs_path_full)
|
|
||||||
else:
|
|
||||||
self.structs_path = None
|
|
||||||
|
|
||||||
self.vars_list = parse_vars(self.xml_path, self.typedef_map)
|
|
||||||
self.update_table()
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
|
|
||||||
|
|
||||||
|
|
||||||
finally:
|
|
||||||
self._updating = False # Снимаем блокировку при выходе из функции
|
|
||||||
|
|
||||||
def __browse_proj_path(self):
|
|
||||||
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку проекта")
|
|
||||||
if dir_path:
|
|
||||||
self.proj_path_edit.setText(dir_path)
|
|
||||||
self.proj_path = dir_path
|
|
||||||
|
|
||||||
if self.makefile_path and self.proj_path:
|
|
||||||
path = make_relative_path(self.makefile_path, self.proj_path)
|
|
||||||
self.makefile_edit.setText(path)
|
|
||||||
self.makefile_path = path
|
|
||||||
|
|
||||||
def __browse_xml_output(self):
|
|
||||||
file_path, _ = QFileDialog.getSaveFileName(
|
|
||||||
self,
|
|
||||||
"Выберите XML файл",
|
|
||||||
filter="XML files (*.xml);;All Files (*)"
|
|
||||||
)
|
|
||||||
self.xml_output_edit.setText(file_path)
|
|
||||||
self.xml_path = file_path
|
|
||||||
|
|
||||||
def keyPressEvent(self, event: QKeyEvent):
|
|
||||||
if event.key() == Qt.Key_Delete:
|
|
||||||
self.delete_selected_rows()
|
|
||||||
else:
|
|
||||||
super().keyPressEvent(event)
|
|
||||||
|
|
||||||
def __browse_makefile(self):
|
|
||||||
file_path, _ = QFileDialog.getOpenFileName(
|
|
||||||
self, "Выберите Makefile", filter="Makefile (makefile);;All Files (*)"
|
|
||||||
)
|
|
||||||
if file_path and self.proj_path:
|
|
||||||
path = make_relative_path(file_path, self.proj_path)
|
|
||||||
else:
|
|
||||||
path = file_path
|
|
||||||
self.makefile_edit.setText(path)
|
|
||||||
self.makefile_path = path
|
|
||||||
|
|
||||||
def __browse_source_output(self):
|
|
||||||
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку для debug_vars.c")
|
|
||||||
if dir_path:
|
|
||||||
self.source_output_edit.setText(dir_path)
|
|
||||||
self.output_path = dir_path
|
|
||||||
else:
|
|
||||||
self.output_path = ''
|
|
||||||
|
|
||||||
|
|
||||||
def __on_xml_path_changed(self):
|
|
||||||
self.xml_path = self.get_xml_path()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def __on_proj_path_changed(self):
|
|
||||||
self.proj_path = self.get_proj_path()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def __on_makefile_path_changed(self):
|
|
||||||
self.makefile_path = self.get_makefile_path()
|
|
||||||
if self.makefile_path and self.proj_path:
|
|
||||||
path = make_relative_path(self.makefile_path, self.proj_path)
|
|
||||||
self.makefile_edit.setText(path)
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
|
|
||||||
def __after_scanvars_finished(self):
|
|
||||||
self.update_all_paths()
|
|
||||||
if not os.path.isfile(self.xml_path):
|
|
||||||
QMessageBox.critical(self, "Ошибка", f"Файл не найден: {self.xml_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.makefile_path = None
|
|
||||||
self.structs_path = None
|
|
||||||
self.proj_path = None
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.critical(self, "Ошибка", f"Не удалось загрузить переменные:\n{e}")
|
|
||||||
|
|
||||||
def delete_selected_rows(self):
|
|
||||||
selected_rows = sorted(set(index.row() for index in self.table.selectedIndexes()), reverse=True)
|
|
||||||
if not selected_rows:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Удаляем из vars_list те, у кого show_var == true и имя совпадает
|
|
||||||
filtered_vars = [v for v in self.vars_list if v.get('show_var', 'false') == 'true']
|
|
||||||
for row in selected_rows:
|
|
||||||
if 0 <= row < len(filtered_vars):
|
|
||||||
var_to_remove = filtered_vars[row]
|
|
||||||
for v in self.vars_list:
|
|
||||||
if v['name'] == var_to_remove['name']:
|
|
||||||
v['show_var'] = 'false'
|
|
||||||
break
|
|
||||||
|
|
||||||
self.update_table()
|
|
||||||
|
|
||||||
|
|
||||||
def __open_variable_selector(self):
|
|
||||||
if not self.vars_list:
|
|
||||||
QMessageBox.warning(self, "Нет переменных", "Сначала загрузите или обновите переменные.")
|
|
||||||
return
|
|
||||||
|
|
||||||
dlg = VariableSelectorDialog(self.vars_list, self.structs, self.typedef_map, self.xml_path, self)
|
|
||||||
if dlg.exec():
|
|
||||||
self.write_to_xml()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_table(self):
|
|
||||||
self.type_options = list(dict.fromkeys(type_map.values()))
|
|
||||||
self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
|
|
||||||
iq_types = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
|
|
||||||
filtered_vars = [v for v in self.vars_list if v.get('show_var', 'false') == 'true']
|
|
||||||
self.table.setRowCount(len(filtered_vars))
|
|
||||||
self.table.verticalHeader().setVisible(False)
|
|
||||||
|
|
||||||
for row, var in enumerate(filtered_vars):
|
|
||||||
# Добавляем номер строки в колонку No (0)
|
|
||||||
no_item = QTableWidgetItem(str(row))
|
|
||||||
no_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) # readonly
|
|
||||||
self.table.setItem(row, rows.No, no_item)
|
|
||||||
|
|
||||||
cb = QCheckBox()
|
|
||||||
enable_str = var.get('enable', 'false')
|
|
||||||
cb.setChecked(enable_str.lower() == 'true')
|
|
||||||
self.table.setCellWidget(row, rows.include, cb)
|
|
||||||
|
|
||||||
name_edit = QLineEdit(var['name'])
|
|
||||||
if var['type'] in self.structs:
|
|
||||||
completer = QCompleter(self.structs[var['type']].keys())
|
|
||||||
completer.setCaseSensitivity(Qt.CaseInsensitive)
|
|
||||||
name_edit.setCompleter(completer)
|
|
||||||
self.table.setCellWidget(row, rows.name, name_edit)
|
|
||||||
|
|
||||||
# Type (origin)
|
|
||||||
origin_type = var.get('type', '').strip()
|
|
||||||
origin_item = QTableWidgetItem(origin_type)
|
|
||||||
origin_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) # read-only
|
|
||||||
self.table.setItem(row, rows.type, origin_item)
|
|
||||||
|
|
||||||
pt_type_combo = QComboBox()
|
|
||||||
pt_type_combo.addItems(self.display_type_options)
|
|
||||||
internal_type = var['pt_type'].replace('pt_', '')
|
|
||||||
if internal_type in self.display_type_options:
|
|
||||||
pt_type_combo.setCurrentText(internal_type)
|
|
||||||
else:
|
|
||||||
pt_type_combo.addItem(internal_type)
|
|
||||||
pt_type_combo.setCurrentText(internal_type)
|
|
||||||
self.table.setCellWidget(row, rows.pt_type, pt_type_combo)
|
|
||||||
|
|
||||||
iq_combo = QComboBox()
|
|
||||||
iq_combo.addItems(iq_types)
|
|
||||||
iq_type = var['iq_type'].replace('t_', '')
|
|
||||||
if iq_type in iq_types:
|
|
||||||
iq_combo.setCurrentText(iq_type)
|
|
||||||
else:
|
|
||||||
iq_combo.addItem(iq_type)
|
|
||||||
iq_combo.setCurrentText(iq_type)
|
|
||||||
self.table.setCellWidget(row, rows.iq_type, iq_combo)
|
|
||||||
|
|
||||||
ret_combo = QComboBox()
|
|
||||||
ret_combo.addItems(iq_types)
|
|
||||||
self.table.setCellWidget(row, rows.ret_type, ret_combo)
|
|
||||||
|
|
||||||
short_name_edit = QLineEdit(var['name'])
|
|
||||||
self.table.setCellWidget(row, rows.short_name, short_name_edit)
|
|
||||||
|
|
||||||
cb.stateChanged.connect(self.write_to_xml)
|
|
||||||
name_edit.textChanged.connect(self.write_to_xml)
|
|
||||||
pt_type_combo.currentTextChanged.connect(self.write_to_xml)
|
|
||||||
iq_combo.currentTextChanged.connect(self.write_to_xml)
|
|
||||||
ret_combo.currentTextChanged.connect(self.write_to_xml)
|
|
||||||
short_name_edit.textChanged.connect(self.write_to_xml)
|
|
||||||
|
|
||||||
|
|
||||||
self.write_to_xml()
|
|
||||||
|
|
||||||
|
|
||||||
def read_table(self):
|
|
||||||
vars_data = []
|
|
||||||
for row in range(self.table.rowCount()):
|
|
||||||
cb = self.table.cellWidget(row, rows.include)
|
|
||||||
name_edit = self.table.cellWidget(row, rows.name)
|
|
||||||
pt_type_combo = self.table.cellWidget(row, rows.pt_type)
|
|
||||||
iq_combo = self.table.cellWidget(row, rows.iq_type)
|
|
||||||
ret_combo = self.table.cellWidget(row, rows.ret_type)
|
|
||||||
short_name_edit = self.table.cellWidget(row, rows.short_name)
|
|
||||||
origin_item = self.table.item(row, rows.type)
|
|
||||||
|
|
||||||
vars_data.append({
|
|
||||||
'show_var': True,
|
|
||||||
'enable': cb.isChecked() if cb else False,
|
|
||||||
'name': name_edit.text() if name_edit else '',
|
|
||||||
'pt_type': 'pt_' + pt_type_combo.currentText() if pt_type_combo else '',
|
|
||||||
'iq_type': iq_combo.currentText() if iq_combo else '',
|
|
||||||
'return_type': ret_combo.currentText() if ret_combo else '',
|
|
||||||
'shortname': short_name_edit.text() if short_name_edit else '',
|
|
||||||
'type': origin_item.text() if origin_item else '',
|
|
||||||
})
|
|
||||||
return vars_data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def write_to_xml(self):
|
|
||||||
self.update_all_paths()
|
|
||||||
|
|
||||||
if not self.xml_path or not os.path.isfile(self.xml_path):
|
|
||||||
print("XML файл не найден или путь пустой")
|
|
||||||
return
|
|
||||||
if not self.proj_path or not os.path.isdir(self.proj_path):
|
|
||||||
print("Project path не найден или путь пустой")
|
|
||||||
return
|
|
||||||
if not self.makefile_path or not os.path.isfile(self.makefile_path):
|
|
||||||
print("makefile файл не найден или путь пустой")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
root, tree = safe_parse_xml(self.xml_path)
|
|
||||||
if root is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
root.set("proj_path", self.proj_path.replace("\\", "/"))
|
|
||||||
|
|
||||||
if self.makefile_path and os.path.isfile(self.makefile_path):
|
|
||||||
rel_makefile = make_relative_path(self.makefile_path, self.proj_path)
|
|
||||||
root.set("makefile_path", rel_makefile)
|
|
||||||
|
|
||||||
if self.structs_path and os.path.isfile(self.structs_path):
|
|
||||||
rel_struct = make_relative_path(self.structs_path, self.proj_path)
|
|
||||||
root.set("structs_path", rel_struct)
|
|
||||||
|
|
||||||
vars_elem = root.find('variables')
|
|
||||||
if vars_elem is None:
|
|
||||||
vars_elem = ET.SubElement(root, 'variables')
|
|
||||||
|
|
||||||
original_info = {}
|
|
||||||
for var_elem in vars_elem.findall('var'):
|
|
||||||
name = var_elem.attrib.get('name')
|
|
||||||
if name:
|
|
||||||
original_info[name] = {
|
|
||||||
'file': var_elem.findtext('file', ''),
|
|
||||||
'extern': var_elem.findtext('extern', ''),
|
|
||||||
'static': var_elem.findtext('static', '')
|
|
||||||
}
|
|
||||||
|
|
||||||
# Читаем переменные из таблицы (активные/изменённые)
|
|
||||||
table_vars = {v['name']: v for v in self.read_table()}
|
|
||||||
# Все переменные (в том числе новые, которых нет в таблице)
|
|
||||||
all_vars_by_name = {v['name']: v for v in self.vars_list}
|
|
||||||
|
|
||||||
# Объединённый список переменных для записи
|
|
||||||
all_names = list(all_vars_by_name.keys())
|
|
||||||
for name in all_names:
|
|
||||||
v = all_vars_by_name[name]
|
|
||||||
v_table = table_vars.get(name)
|
|
||||||
var_elem = None
|
|
||||||
|
|
||||||
# Ищем уже существующий <var> в XML
|
|
||||||
for ve in vars_elem.findall('var'):
|
|
||||||
if ve.attrib.get('name') == name:
|
|
||||||
var_elem = ve
|
|
||||||
break
|
|
||||||
if var_elem is None:
|
|
||||||
var_elem = ET.SubElement(vars_elem, 'var', {'name': name})
|
|
||||||
|
|
||||||
def set_sub_elem_text(parent, tag, text):
|
|
||||||
el = parent.find(tag)
|
|
||||||
if el is None:
|
|
||||||
el = ET.SubElement(parent, tag)
|
|
||||||
el.text = str(text)
|
|
||||||
|
|
||||||
set_sub_elem_text(var_elem, 'show_var', v.get('show_var', 'false'))
|
|
||||||
set_sub_elem_text(var_elem, 'enable', v.get('enable', 'false'))
|
|
||||||
|
|
||||||
# Тут подтягиваем из таблицы, если есть, иначе из v
|
|
||||||
shortname_val = v_table['shortname'] if v_table and 'shortname' in v_table else v.get('shortname', '')
|
|
||||||
pt_type_val = v_table['pt_type'] if v_table and 'pt_type' in v_table else v.get('pt_type', '')
|
|
||||||
iq_type_val = v_table['iq_type'] if v_table and 'iq_type' in v_table else v.get('iq_type', '')
|
|
||||||
ret_type_val = v_table['return_type'] if v_table and 'return_type' in v_table else v.get('return_type', '')
|
|
||||||
|
|
||||||
set_sub_elem_text(var_elem, 'shortname', shortname_val)
|
|
||||||
set_sub_elem_text(var_elem, 'pt_type', pt_type_val)
|
|
||||||
set_sub_elem_text(var_elem, 'iq_type', iq_type_val)
|
|
||||||
set_sub_elem_text(var_elem, 'return_type', ret_type_val)
|
|
||||||
set_sub_elem_text(var_elem, 'type', v.get('type', ''))
|
|
||||||
|
|
||||||
# file/extern/static: из original_info, либо из v
|
|
||||||
file_val = v.get('file') or original_info.get(name, {}).get('file', '')
|
|
||||||
extern_val = v.get('extern') or original_info.get(name, {}).get('extern', '')
|
|
||||||
static_val = v.get('static') or original_info.get(name, {}).get('static', '')
|
|
||||||
|
|
||||||
set_sub_elem_text(var_elem, 'file', file_val)
|
|
||||||
set_sub_elem_text(var_elem, 'extern', extern_val)
|
|
||||||
set_sub_elem_text(var_elem, 'static', static_val)
|
|
||||||
|
|
||||||
|
|
||||||
ET.indent(tree, space=" ", level=0)
|
|
||||||
tree.write(self.xml_path, encoding='utf-8', xml_declaration=True)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Ошибка при сохранении XML: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
|
|
||||||
editor = VarEditor()
|
|
||||||
editor.resize(900, 600)
|
|
||||||
editor.show()
|
|
||||||
|
|
||||||
sys.exit(app.exec())
|
|
||||||
|
|
||||||
606
Src/var_selector_table.py
Normal file
606
Src/var_selector_table.py
Normal file
@@ -0,0 +1,606 @@
|
|||||||
|
import re
|
||||||
|
from PySide2.QtWidgets import (
|
||||||
|
QWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QLineEdit,
|
||||||
|
QHeaderView, QCompleter
|
||||||
|
)
|
||||||
|
from PySide2.QtGui import QKeyEvent
|
||||||
|
from PySide2.QtCore import Qt, QStringListModel
|
||||||
|
import pickle
|
||||||
|
import time
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
def compute_vars_hash(vars_list):
|
||||||
|
return hashlib.sha1(pickle.dumps(vars_list)).hexdigest()
|
||||||
|
|
||||||
|
# Вспомогательные функции, которые теперь будут использоваться виджетом
|
||||||
|
def split_path(path):
|
||||||
|
"""
|
||||||
|
Разбивает путь на компоненты:
|
||||||
|
- 'foo[2].bar[1]->baz' → ['foo', '[2]', 'bar', '[1]', 'baz']
|
||||||
|
Если видит '-' в конце строки (без '>' после) — обрезает этот '-'
|
||||||
|
"""
|
||||||
|
tokens = []
|
||||||
|
token = ''
|
||||||
|
i = 0
|
||||||
|
length = len(path)
|
||||||
|
while i < length:
|
||||||
|
c = path[i]
|
||||||
|
# Разделители: '->' и '.'
|
||||||
|
if c == '-' and i + 1 < length and path[i:i+2] == '->':
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
elif c == '-' and i == length - 1:
|
||||||
|
# '-' на конце строки без '>' после — просто пропускаем его
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
elif c == '.':
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
elif c == '[':
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
idx = ''
|
||||||
|
while i < length and path[i] != ']':
|
||||||
|
idx += path[i]
|
||||||
|
i += 1
|
||||||
|
if i < length and path[i] == ']':
|
||||||
|
idx += ']'
|
||||||
|
i += 1
|
||||||
|
tokens.append(idx)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
token += c
|
||||||
|
i += 1
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def is_lazy_item(item):
|
||||||
|
return item.childCount() == 1 and item.child(0).text(0) == 'lazy_marker'
|
||||||
|
|
||||||
|
|
||||||
|
class VariableSelectWidget(QWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.expanded_vars = []
|
||||||
|
self.node_index = {}
|
||||||
|
self.is_autocomplete_on = True # <--- ДОБАВИТЬ ЭТУ СТРОКУ
|
||||||
|
self._bckspc_pressed = False
|
||||||
|
self.manual_completion_active = False
|
||||||
|
self._vars_hash = None
|
||||||
|
|
||||||
|
# --- UI Элементы ---
|
||||||
|
self.search_input = QLineEdit(self)
|
||||||
|
self.search_input.setPlaceholderText("Поиск...")
|
||||||
|
|
||||||
|
self.tree = QTreeWidget(self)
|
||||||
|
self.tree.setHeaderLabels(["Имя переменной", "Тип"])
|
||||||
|
self.tree.setSelectionMode(QTreeWidget.ExtendedSelection)
|
||||||
|
self.tree.setRootIsDecorated(True)
|
||||||
|
self.tree.setUniformRowHeights(True)
|
||||||
|
self.tree.setStyleSheet("""
|
||||||
|
QTreeWidget::item:selected { background-color: #87CEFA; color: black; }
|
||||||
|
QTreeWidget::item:hover { background-color: #D3D3D3; }
|
||||||
|
""")
|
||||||
|
self.tree.itemExpanded.connect(self.on_item_expanded)
|
||||||
|
|
||||||
|
self.completer = QCompleter(self)
|
||||||
|
self.completer.setCompletionMode(QCompleter.PopupCompletion)
|
||||||
|
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
|
||||||
|
self.completer.setFilterMode(Qt.MatchContains)
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
|
|
||||||
|
# --- Layout ---
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.addWidget(self.search_input)
|
||||||
|
layout.addWidget(self.tree)
|
||||||
|
|
||||||
|
# --- Соединения ---
|
||||||
|
#self.search_input.textChanged.connect(self.on_search_text_changed)
|
||||||
|
self.search_input.textChanged.connect(lambda text: self.on_search_text_changed(text))
|
||||||
|
self.search_input.installEventFilter(self)
|
||||||
|
self.completer.activated[str].connect(lambda text: self.insert_completion(text))
|
||||||
|
|
||||||
|
# --- Публичные методы для управления виджетом снаружи ---
|
||||||
|
|
||||||
|
def set_autocomplete(self, enabled: bool):
|
||||||
|
"""Включает или выключает режим автодополнения."""
|
||||||
|
self.is_autocomplete_on = enabled
|
||||||
|
|
||||||
|
def set_data(self, vars_list):
|
||||||
|
"""Основной метод для загрузки данных в виджет."""
|
||||||
|
self.expanded_vars = pickle.loads(pickle.dumps(vars_list, protocol=pickle.HIGHEST_PROTOCOL))
|
||||||
|
# self.build_completion_list() # Если нужна полная перестройка списка
|
||||||
|
self.populate_tree()
|
||||||
|
|
||||||
|
|
||||||
|
def populate_tree(self, vars_list=None):
|
||||||
|
if vars_list is None:
|
||||||
|
vars_list = self.expanded_vars
|
||||||
|
|
||||||
|
new_hash = compute_vars_hash(vars_list)
|
||||||
|
if self._vars_hash == new_hash:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._vars_hash = new_hash
|
||||||
|
self.tree.setUpdatesEnabled(False)
|
||||||
|
self.tree.blockSignals(True)
|
||||||
|
self.tree.clear()
|
||||||
|
self.node_index.clear()
|
||||||
|
|
||||||
|
for var in vars_list:
|
||||||
|
self.add_tree_item_lazy(None, var)
|
||||||
|
|
||||||
|
self.tree.setUpdatesEnabled(True)
|
||||||
|
self.tree.blockSignals(False)
|
||||||
|
header = self.tree.header()
|
||||||
|
header.setSectionResizeMode(QHeaderView.Interactive)
|
||||||
|
header.setSectionResizeMode(1, QHeaderView.Stretch)
|
||||||
|
self.tree.setColumnWidth(0, 400)
|
||||||
|
|
||||||
|
def on_item_expanded(self, item):
|
||||||
|
if is_lazy_item(item):
|
||||||
|
item.removeChild(item.child(0))
|
||||||
|
var = item.data(0, Qt.UserRole + 100)
|
||||||
|
if var:
|
||||||
|
for child_var in var.get('children', []):
|
||||||
|
self.add_tree_item_lazy(item, child_var)
|
||||||
|
|
||||||
|
|
||||||
|
def get_full_item_name(self, item):
|
||||||
|
fullname = item.text(0)
|
||||||
|
# Заменяем '->' на '.'
|
||||||
|
fullname = fullname.replace('->', '.')
|
||||||
|
fullname = fullname.replace('[', '.[')
|
||||||
|
return fullname
|
||||||
|
|
||||||
|
def add_tree_item_lazy(self, parent, var):
|
||||||
|
name = var['name']
|
||||||
|
type_str = var.get('type', '')
|
||||||
|
item = QTreeWidgetItem([name, type_str])
|
||||||
|
item.setData(0, Qt.UserRole, name)
|
||||||
|
full_name = self.get_full_item_name(item)
|
||||||
|
self.node_index[full_name.lower()] = item
|
||||||
|
|
||||||
|
if "(bitfield:" in type_str:
|
||||||
|
item.setDisabled(True)
|
||||||
|
self.set_tool(item, "Битовые поля недоступны для выбора")
|
||||||
|
|
||||||
|
for i, attr in enumerate(['file', 'extern', 'static']):
|
||||||
|
item.setData(0, Qt.UserRole + 1 + i, var.get(attr))
|
||||||
|
|
||||||
|
if parent is None:
|
||||||
|
self.tree.addTopLevelItem(item)
|
||||||
|
else:
|
||||||
|
parent.addChild(item)
|
||||||
|
|
||||||
|
# Если есть дети — добавляем заглушку (чтобы можно было раскрыть)
|
||||||
|
if var.get('children'):
|
||||||
|
dummy = QTreeWidgetItem(["lazy_marker"])
|
||||||
|
item.addChild(dummy)
|
||||||
|
|
||||||
|
# Кэшируем детей для подгрузки по событию
|
||||||
|
item.setData(0, Qt.UserRole + 100, var) # Сохраняем var целиком
|
||||||
|
|
||||||
|
|
||||||
|
def show_matching_path(self, item, path_parts, level=0):
|
||||||
|
node_name = item.text(0).lower()
|
||||||
|
node_parts = split_path(node_name)
|
||||||
|
|
||||||
|
if 'project' in node_name:
|
||||||
|
a = 1
|
||||||
|
|
||||||
|
if level >= len(path_parts):
|
||||||
|
# Путь полностью пройден — показываем только этот узел (без раскрытия всех детей)
|
||||||
|
item.setHidden(False)
|
||||||
|
item.setExpanded(False)
|
||||||
|
return True
|
||||||
|
|
||||||
|
if level >= len(node_parts):
|
||||||
|
# Уровень поиска больше длины пути узла — скрываем
|
||||||
|
item.setHidden(False)
|
||||||
|
|
||||||
|
search_part = path_parts[level]
|
||||||
|
node_part = node_parts[level]
|
||||||
|
|
||||||
|
if search_part == node_part:
|
||||||
|
# Точное совпадение — показываем узел, идём вглубь только по совпадениям
|
||||||
|
item.setHidden(False)
|
||||||
|
matched_any = False
|
||||||
|
self.on_item_expanded(item)
|
||||||
|
for i in range(item.childCount()):
|
||||||
|
child = item.child(i)
|
||||||
|
if self.show_matching_path(child, path_parts, level + 1):
|
||||||
|
matched_any = True
|
||||||
|
item.setExpanded(matched_any)
|
||||||
|
return matched_any or item.childCount() == 0
|
||||||
|
|
||||||
|
elif node_part.startswith(search_part):
|
||||||
|
# Неполное совпадение — показываем только этот узел, детей скрываем, не раскрываем
|
||||||
|
item.setHidden(False)
|
||||||
|
item.setExpanded(False)
|
||||||
|
return True
|
||||||
|
|
||||||
|
elif search_part in node_part and (level == len(path_parts)-1):
|
||||||
|
# Неполное совпадение — показываем только этот узел, детей скрываем, не раскрываем
|
||||||
|
item.setHidden(False)
|
||||||
|
item.setExpanded(False)
|
||||||
|
return True
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Несовпадение — скрываем
|
||||||
|
item.setHidden(True)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def filter_tree(self):
|
||||||
|
text = self.search_input.text().strip().lower()
|
||||||
|
path_parts = split_path(text) if text else []
|
||||||
|
|
||||||
|
if '.' not in text and '->' not in text and '[' not in text and text != '':
|
||||||
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
|
item = self.tree.topLevelItem(i)
|
||||||
|
name = item.text(0).lower()
|
||||||
|
if text in name:
|
||||||
|
item.setHidden(False)
|
||||||
|
# Не сбрасываем expanded, чтобы можно было раскрывать вручную
|
||||||
|
else:
|
||||||
|
item.setHidden(True)
|
||||||
|
else:
|
||||||
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
|
item = self.tree.topLevelItem(i)
|
||||||
|
self.show_matching_path(item, path_parts, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def find_node_by_path(self, root_vars, path_list):
|
||||||
|
current_level = root_vars
|
||||||
|
node = None
|
||||||
|
for part in path_list:
|
||||||
|
node = None
|
||||||
|
for var in current_level:
|
||||||
|
if var['name'] == part:
|
||||||
|
node = var
|
||||||
|
break
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
|
current_level = node.get('children', [])
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
def update_completions(self, text=None):
|
||||||
|
if text is None:
|
||||||
|
text = self.search_input.text().strip()
|
||||||
|
else:
|
||||||
|
text = text.strip()
|
||||||
|
|
||||||
|
normalized_text = text.replace('->', '.')
|
||||||
|
parts = split_path(text)
|
||||||
|
path_parts = parts[:-1] if parts else []
|
||||||
|
prefix = parts[-1].lower() if parts else ''
|
||||||
|
ends_with_sep = text.endswith('.') or text.endswith('->') or text.endswith('[')
|
||||||
|
is_index_suggestion = text.endswith('[')
|
||||||
|
|
||||||
|
completions = []
|
||||||
|
|
||||||
|
def find_exact_node(parts):
|
||||||
|
if not parts:
|
||||||
|
return None
|
||||||
|
fullname = parts[0]
|
||||||
|
for p in parts[1:]:
|
||||||
|
fullname += '.' + p
|
||||||
|
return self.node_index.get(fullname.lower())
|
||||||
|
|
||||||
|
if is_index_suggestion:
|
||||||
|
base_text = text[:-1] # убираем '['
|
||||||
|
parent_node = self.find_node_by_fullname(base_text)
|
||||||
|
if not parent_node:
|
||||||
|
base_text_clean = re.sub(r'\[\d+\]$', '', base_text)
|
||||||
|
parent_node = self.find_node_by_fullname(base_text_clean)
|
||||||
|
if parent_node:
|
||||||
|
seen = set()
|
||||||
|
for i in range(parent_node.childCount()):
|
||||||
|
child = parent_node.child(i)
|
||||||
|
if child.isHidden():
|
||||||
|
continue
|
||||||
|
cname = child.text(0)
|
||||||
|
m = re.match(rf'^{re.escape(base_text)}\[(\d+)\]$', cname)
|
||||||
|
if m and cname not in seen:
|
||||||
|
completions.append(cname)
|
||||||
|
seen.add(cname)
|
||||||
|
self.completer.setModel(QStringListModel(completions))
|
||||||
|
return completions
|
||||||
|
|
||||||
|
if ends_with_sep:
|
||||||
|
node = self.find_node_by_fullname(text[:-1])
|
||||||
|
if node:
|
||||||
|
for i in range(node.childCount()):
|
||||||
|
child = node.child(i)
|
||||||
|
if child.isHidden():
|
||||||
|
continue
|
||||||
|
completions.append(child.text(0))
|
||||||
|
elif not path_parts:
|
||||||
|
# Первый уровень — только если имя начинается с prefix
|
||||||
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
|
item = self.tree.topLevelItem(i)
|
||||||
|
if item.isHidden():
|
||||||
|
continue
|
||||||
|
name = item.text(0)
|
||||||
|
if name.lower().startswith(prefix):
|
||||||
|
completions.append(name)
|
||||||
|
else:
|
||||||
|
node = find_exact_node(path_parts)
|
||||||
|
if node:
|
||||||
|
for i in range(node.childCount()):
|
||||||
|
child = node.child(i)
|
||||||
|
if child.isHidden():
|
||||||
|
continue
|
||||||
|
name = child.text(0)
|
||||||
|
name_parts = child.data(0, Qt.UserRole + 10)
|
||||||
|
if name_parts is None:
|
||||||
|
name_parts = split_path(name)
|
||||||
|
child.setData(0, Qt.UserRole + 10, name_parts)
|
||||||
|
if not name_parts:
|
||||||
|
continue
|
||||||
|
last_part = name_parts[-1].lower()
|
||||||
|
if prefix == '' or prefix in last_part: # ← строго startswith
|
||||||
|
completions.append(name)
|
||||||
|
|
||||||
|
self.completer.setModel(QStringListModel(completions))
|
||||||
|
self.completer.complete()
|
||||||
|
return completions
|
||||||
|
|
||||||
|
|
||||||
|
# Функция для поиска узла с полным именем
|
||||||
|
def find_node_by_fullname(self, name):
|
||||||
|
if name is None:
|
||||||
|
return None
|
||||||
|
normalized_name = name.replace('->', '.').lower()
|
||||||
|
normalized_name = normalized_name.replace('[', '.[').lower()
|
||||||
|
return self.node_index.get(normalized_name)
|
||||||
|
|
||||||
|
def insert_completion(self, text):
|
||||||
|
node = self.find_node_by_fullname(text)
|
||||||
|
if node and node.childCount() > 0 and not (text.endswith('.') or text.endswith('->') or text.endswith('[')):
|
||||||
|
# Определяем разделитель по имени первого ребёнка
|
||||||
|
child_name = node.child(0).text(0)
|
||||||
|
if child_name.startswith(text + '->'):
|
||||||
|
text += '->'
|
||||||
|
elif child_name.startswith(text + '.'):
|
||||||
|
text += '.'
|
||||||
|
elif '[' in child_name:
|
||||||
|
text += '[' # для массивов
|
||||||
|
else:
|
||||||
|
text += '.' # fallback
|
||||||
|
|
||||||
|
if not self._bckspc_pressed:
|
||||||
|
self.search_input.setText(text)
|
||||||
|
self.search_input.setCursorPosition(len(text))
|
||||||
|
|
||||||
|
self.run_completions(text)
|
||||||
|
else:
|
||||||
|
self.search_input.setText(text)
|
||||||
|
self.search_input.setCursorPosition(len(text))
|
||||||
|
|
||||||
|
def eventFilter(self, obj, event):
|
||||||
|
if obj == self.search_input and isinstance(event, QKeyEvent):
|
||||||
|
if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier:
|
||||||
|
self.manual_completion_active = True
|
||||||
|
text = self.search_input.text().strip()
|
||||||
|
self.run_completions(text)
|
||||||
|
elif event.key() == Qt.Key_Escape:
|
||||||
|
# Esc — выключаем ручной режим и скрываем подсказки, если autocomplete выключен
|
||||||
|
if not self.is_autocomplete_on:
|
||||||
|
self.manual_completion_active = False
|
||||||
|
self.completer.popup().hide()
|
||||||
|
return True
|
||||||
|
|
||||||
|
if event.key() == Qt.Key_Backspace:
|
||||||
|
self._bckspc_pressed = True
|
||||||
|
else:
|
||||||
|
self._bckspc_pressed = False
|
||||||
|
|
||||||
|
return super().eventFilter(obj, event)
|
||||||
|
|
||||||
|
def run_completions(self, text):
|
||||||
|
completions = self.update_completions(text)
|
||||||
|
|
||||||
|
if not self.is_autocomplete_on and self._bckspc_pressed:
|
||||||
|
text = text[:-1]
|
||||||
|
|
||||||
|
if len(completions) == 1 and completions[0].lower() == text.lower():
|
||||||
|
# Найдем узел с таким именем
|
||||||
|
def find_exact_item(name):
|
||||||
|
stack = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
|
||||||
|
while stack:
|
||||||
|
node = stack.pop()
|
||||||
|
if node.text(0).lower() == name.lower():
|
||||||
|
return node
|
||||||
|
for i in range(node.childCount()):
|
||||||
|
stack.append(node.child(i))
|
||||||
|
return None
|
||||||
|
|
||||||
|
node = find_exact_item(completions[0])
|
||||||
|
if node and node.childCount() > 0:
|
||||||
|
# Используем первую подсказку, чтобы определить нужный разделитель
|
||||||
|
completions = self.update_completions(text + '.')
|
||||||
|
if not completions:
|
||||||
|
return
|
||||||
|
suggestion = completions[0]
|
||||||
|
|
||||||
|
# Ищем, какой символ идёт после текущего текста
|
||||||
|
separator = '.'
|
||||||
|
if suggestion.startswith(text):
|
||||||
|
rest = suggestion[len(text):]
|
||||||
|
if rest.startswith(text + '->'):
|
||||||
|
separator += '->'
|
||||||
|
elif rest.startswith(text + '.'):
|
||||||
|
separator += '.'
|
||||||
|
elif '[' in rest:
|
||||||
|
separator += '[' # для массивов
|
||||||
|
else:
|
||||||
|
separator += '.' # fallback
|
||||||
|
|
||||||
|
if not self._bckspc_pressed:
|
||||||
|
self.search_input.setText(text + separator)
|
||||||
|
completions = self.update_completions(text)
|
||||||
|
self.completer.setModel(QStringListModel(completions))
|
||||||
|
self.completer.complete()
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Иначе просто показываем подсказки
|
||||||
|
self.completer.setModel(QStringListModel(completions))
|
||||||
|
if completions:
|
||||||
|
self.completer.complete()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def on_search_text_changed(self, text):
|
||||||
|
sender_widget = self.sender()
|
||||||
|
sender_name = sender_widget.objectName() if sender_widget else "Unknown Sender"
|
||||||
|
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
|
self.filter_tree()
|
||||||
|
if text == None:
|
||||||
|
text = self.search_input.text().strip()
|
||||||
|
if self.is_autocomplete_on:
|
||||||
|
self.run_completions(text)
|
||||||
|
else:
|
||||||
|
# Если выключено, показываем подсказки только если флаг ручного вызова True
|
||||||
|
if self.manual_completion_active:
|
||||||
|
self.run_completions(text)
|
||||||
|
else:
|
||||||
|
self.completer.popup().hide()
|
||||||
|
|
||||||
|
def focusInEvent(self, event):
|
||||||
|
if self.completer.widget() != self.search_input:
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
|
super().focusInEvent(event)
|
||||||
|
|
||||||
|
def _custom_focus_in_event(self, event):
|
||||||
|
# Принудительно установить виджет для completer при получении фокуса
|
||||||
|
if self.completer.widget() != self.search_input:
|
||||||
|
self.completer.setWidget(self.search_input)
|
||||||
|
super(QLineEdit, self.search_input).focusInEvent(event) # Вызвать оригинальный обработчик
|
||||||
|
|
||||||
|
|
||||||
|
def build_completion_list(self):
|
||||||
|
completions = []
|
||||||
|
|
||||||
|
def recurse(var, prefix=''):
|
||||||
|
fullname = f"{prefix}.{var['name']}" if prefix else var['name']
|
||||||
|
completions.append(fullname)
|
||||||
|
for child in var.get('children', []):
|
||||||
|
recurse(child, fullname)
|
||||||
|
|
||||||
|
for v in self.expanded_vars:
|
||||||
|
recurse(v)
|
||||||
|
self.all_completions = completions
|
||||||
|
|
||||||
|
def set_tool(self, item, text):
|
||||||
|
item.setToolTip(0, text)
|
||||||
|
item.setToolTip(1, text)
|
||||||
|
|
||||||
|
def get_all_items(self):
|
||||||
|
"""Возвращает все конечные (leaf) элементы, исключая битовые поля и элементы с детьми (реальными)."""
|
||||||
|
def collect_leaf_items(parent):
|
||||||
|
leaf_items = []
|
||||||
|
for i in range(parent.childCount()):
|
||||||
|
child = parent.child(i)
|
||||||
|
if child.isHidden():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Если есть заглушка — раскрываем
|
||||||
|
self.on_item_expanded(child)
|
||||||
|
|
||||||
|
if child.childCount() == 0:
|
||||||
|
item_type = child.text(1)
|
||||||
|
if item_type and 'bitfield' in str(item_type).lower():
|
||||||
|
continue
|
||||||
|
leaf_items.append(child)
|
||||||
|
else:
|
||||||
|
leaf_items.extend(collect_leaf_items(child))
|
||||||
|
return leaf_items
|
||||||
|
|
||||||
|
all_leaf_items = []
|
||||||
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
|
top = self.tree.topLevelItem(i)
|
||||||
|
|
||||||
|
# Раскрываем lazy, если надо
|
||||||
|
self.on_item_expanded(top)
|
||||||
|
|
||||||
|
if top.childCount() == 0:
|
||||||
|
item_type = top.text(1)
|
||||||
|
if item_type and 'bitfield' in str(item_type).lower():
|
||||||
|
continue
|
||||||
|
all_leaf_items.append(top)
|
||||||
|
else:
|
||||||
|
all_leaf_items.extend(collect_leaf_items(top))
|
||||||
|
return all_leaf_items
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _get_internal_selected_items(self):
|
||||||
|
"""Возвращает выделенные элементы и всех их потомков, включая lazy."""
|
||||||
|
selected = self.tree.selectedItems()
|
||||||
|
all_items = []
|
||||||
|
|
||||||
|
def collect_children(item):
|
||||||
|
# Раскрываем при необходимости
|
||||||
|
# Раскрываем lazy, если надо
|
||||||
|
self.on_item_expanded(item)
|
||||||
|
|
||||||
|
items = [item]
|
||||||
|
for i in range(item.childCount()):
|
||||||
|
child = item.child(i)
|
||||||
|
items.extend(collect_children(child))
|
||||||
|
return items
|
||||||
|
|
||||||
|
for item in selected:
|
||||||
|
all_items.extend(collect_children(item))
|
||||||
|
|
||||||
|
return all_items
|
||||||
|
|
||||||
|
def get_selected_items(self):
|
||||||
|
"""Возвращает только конечные (leaf) выделенные элементы, исключая bitfield."""
|
||||||
|
selected = self.tree.selectedItems()
|
||||||
|
leaf_items = []
|
||||||
|
for item in selected:
|
||||||
|
# Раскрываем lazy, если надо
|
||||||
|
self.on_item_expanded(item)
|
||||||
|
|
||||||
|
# Если у узла нет видимых/выделенных детей — он лист
|
||||||
|
if all(item.child(i).isHidden() or not item.child(i).isSelected() for i in range(item.childCount())):
|
||||||
|
item_type = item.data(0, Qt.UserRole)
|
||||||
|
if item_type and 'bitfield' in str(item_type).lower():
|
||||||
|
continue
|
||||||
|
leaf_items.append(item)
|
||||||
|
return leaf_items
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_var_names(self):
|
||||||
|
"""Возвращает имена всех конечных (leaf) переменных, исключая битовые поля и группы."""
|
||||||
|
return [item.text(0) for item in self.get_all_items() if item.text(0)]
|
||||||
|
|
||||||
|
|
||||||
|
def _get_internal_selected_var_names(self):
|
||||||
|
"""Возвращает имена выделенных переменных."""
|
||||||
|
return [item.text(0) for item in self._get_internal_selected_items() if item.text(0)]
|
||||||
|
|
||||||
|
|
||||||
|
def get_selected_var_names(self):
|
||||||
|
"""Возвращает имена только конечных (leaf) переменных из выделенных."""
|
||||||
|
return [item.text(0) for item in self.get_selected_items() if item.text(0)]
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self.completer.setWidget(None)
|
||||||
|
self.completer.deleteLater()
|
||||||
|
super().closeEvent(event)
|
||||||
392
Src/var_selector_window.py
Normal file
392
Src/var_selector_window.py
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
import re
|
||||||
|
import lxml.etree as ET
|
||||||
|
from PySide2.QtWidgets import (
|
||||||
|
QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
|
||||||
|
QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout, QSizePolicy
|
||||||
|
)
|
||||||
|
from PySide2.QtGui import QKeySequence, QKeyEvent
|
||||||
|
from PySide2.QtCore import Qt, QStringListModel, QSettings
|
||||||
|
import var_table
|
||||||
|
import var_setup
|
||||||
|
import myXML
|
||||||
|
import time
|
||||||
|
import var_selector_table
|
||||||
|
|
||||||
|
|
||||||
|
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
|
||||||
|
|
||||||
|
class VariableSelectorDialog(QDialog):
|
||||||
|
def __init__(self, table, all_vars, structs, typedefs, xml_path=None, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setWindowTitle("Выбор переменных")
|
||||||
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||||
|
self.resize(1200, 500)
|
||||||
|
self.selected_names = []
|
||||||
|
self._bckspc_pressed = False # флаг подавления добавления разделителя
|
||||||
|
self.table = table
|
||||||
|
self.all_vars = all_vars
|
||||||
|
self.structs = structs
|
||||||
|
self.typedefs = typedefs
|
||||||
|
self.expanded_vars = []
|
||||||
|
self.var_map = {v['name']: v for v in all_vars}
|
||||||
|
self.node_index = {}
|
||||||
|
self.xml_path = xml_path # сохраняем путь к xml
|
||||||
|
self.manual_completion_active = False
|
||||||
|
|
||||||
|
# --- Добавляем чекбокс для автодополнения ---
|
||||||
|
self.autocomplete_checkbox = QCheckBox("Включить автодополнение")
|
||||||
|
self.autocomplete_checkbox.setChecked(True)
|
||||||
|
|
||||||
|
# Инициализируем QSettings с именем организации и приложения
|
||||||
|
self.settings = QSettings("SET", "DebugVarEdit_VarsSelector")
|
||||||
|
# Восстанавливаем сохранённое состояние чекбокса, если есть
|
||||||
|
checked = self.settings.value("autocomplete_enabled", True, type=bool)
|
||||||
|
self.autocomplete_checkbox.setChecked(checked)
|
||||||
|
# При изменении состояния чекбокса сохраняем его
|
||||||
|
self.autocomplete_checkbox.stateChanged.connect(self.save_checkbox_state)
|
||||||
|
|
||||||
|
# Кнопки между таблицами
|
||||||
|
self.btn_right = QPushButton(">")
|
||||||
|
self.btn_right.clicked.connect(self.on_move_right)
|
||||||
|
self.btn_left = QPushButton("<")
|
||||||
|
self.btn_left.clicked.connect(self.on_move_left)
|
||||||
|
|
||||||
|
# Создаем кнопки, они остаются в диалоге
|
||||||
|
self.btn_accept = QPushButton("Применить")
|
||||||
|
|
||||||
|
# Создаем экземпляр вашего готового виджета
|
||||||
|
self.vars_widget = var_selector_table.VariableSelectWidget(self)
|
||||||
|
self.vars_widget.tree.itemDoubleClicked.connect(self.on_left_tree_double_click)
|
||||||
|
self.vars_widget.setObjectName("LeftTable")
|
||||||
|
self.selected_vars_widget = var_selector_table.VariableSelectWidget(self)
|
||||||
|
self.selected_vars_widget.tree.itemDoubleClicked.connect(self.on_rigth_tree_double_click)
|
||||||
|
self.selected_vars_widget.setObjectName("RightTable")
|
||||||
|
|
||||||
|
# Подписи над таблицами
|
||||||
|
label_all = QLabel("Все переменные")
|
||||||
|
label_all.setStyleSheet("font-weight: bold; font-size: 14px;")
|
||||||
|
|
||||||
|
label_selected = QLabel("Выбранные переменные")
|
||||||
|
label_selected.setStyleSheet("font-weight: bold; font-size: 14px;")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Лэйауты ---
|
||||||
|
main_layout = QVBoxLayout(self) # главный вертикальный layout окна
|
||||||
|
|
||||||
|
# Чекбокс автодополнения — первый в главном layout
|
||||||
|
main_layout.addWidget(self.autocomplete_checkbox)
|
||||||
|
|
||||||
|
# Подписи над таблицами
|
||||||
|
labels_layout = QHBoxLayout()
|
||||||
|
labels_layout.addWidget(label_all)
|
||||||
|
labels_layout.addStretch()
|
||||||
|
labels_layout.addWidget(label_selected)
|
||||||
|
main_layout.addLayout(labels_layout)
|
||||||
|
|
||||||
|
# Горизонтальный layout с таблицами и кнопками
|
||||||
|
tables_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
# Левая таблица
|
||||||
|
self.vars_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
tables_layout.addWidget(self.vars_widget)
|
||||||
|
|
||||||
|
# Кнопки ">" и "<" между таблицами
|
||||||
|
middle_buttons_layout = QVBoxLayout()
|
||||||
|
middle_buttons_layout.addStretch()
|
||||||
|
middle_buttons_layout.addWidget(self.btn_right)
|
||||||
|
middle_buttons_layout.addWidget(self.btn_left)
|
||||||
|
middle_buttons_layout.addStretch()
|
||||||
|
tables_layout.addLayout(middle_buttons_layout)
|
||||||
|
|
||||||
|
# Правая таблица
|
||||||
|
self.selected_vars_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
tables_layout.addWidget(self.selected_vars_widget)
|
||||||
|
|
||||||
|
# Добавляем горизонтальный layout с таблицами в главный вертикальный
|
||||||
|
main_layout.addLayout(tables_layout)
|
||||||
|
|
||||||
|
# Кнопки "Добавить выбранные" и "Удалить выбранные" под таблицами
|
||||||
|
buttons_layout = QVBoxLayout()
|
||||||
|
buttons_layout.addWidget(self.btn_accept)
|
||||||
|
main_layout.addLayout(buttons_layout)
|
||||||
|
|
||||||
|
# Важно, если окно — QDialog или QWidget, установи layout
|
||||||
|
self.setLayout(main_layout)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Соединяем сигналы кнопок с методами диалога
|
||||||
|
self.btn_accept.clicked.connect(self.on_apply_clicked)
|
||||||
|
|
||||||
|
# Соединяем чекбокс с методом виджета
|
||||||
|
self.autocomplete_checkbox.stateChanged.connect(self.set_autocomplete_tables)
|
||||||
|
# Устанавливаем начальное состояние автодополнения в виджете
|
||||||
|
self.vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
||||||
|
self.selected_vars_widget.set_autocomplete(self.autocomplete_checkbox.isChecked())
|
||||||
|
|
||||||
|
# --- Код в конце __init__ ---
|
||||||
|
self.expanded_vars = var_setup.expand_vars(self.all_vars, self.structs, self.typedefs)
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
def on_move_right(self):
|
||||||
|
# Устанавливаем show_var=True для всех выбранных переменных из ЛЕВОЙ таблицы
|
||||||
|
selected = self.vars_widget._get_internal_selected_var_names()
|
||||||
|
if not selected:
|
||||||
|
return
|
||||||
|
|
||||||
|
def mark_selected_show_var(data):
|
||||||
|
for var in data:
|
||||||
|
if var['name'] in selected:
|
||||||
|
var['show_var'] = 'true'
|
||||||
|
var['enable'] = 'true'
|
||||||
|
if 'children' in var:
|
||||||
|
mark_selected_show_var(var['children'])
|
||||||
|
mark_selected_show_var(self.expanded_vars)
|
||||||
|
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
def on_move_left(self):
|
||||||
|
# Сбрасываем show_var=False для всех выбранных переменных из ПРАВОЙ таблицы
|
||||||
|
selected = self.selected_vars_widget._get_internal_selected_var_names()
|
||||||
|
if not selected:
|
||||||
|
return
|
||||||
|
|
||||||
|
def mark_selected_hide_var(data):
|
||||||
|
for var in data:
|
||||||
|
if var['name'] in selected:
|
||||||
|
var['show_var'] = 'false'
|
||||||
|
if 'children' in var:
|
||||||
|
mark_selected_hide_var(var['children'])
|
||||||
|
mark_selected_hide_var(self.expanded_vars)
|
||||||
|
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
def update_vars_widget(self):
|
||||||
|
t_start = time.perf_counter()
|
||||||
|
|
||||||
|
t1 = time.perf_counter()
|
||||||
|
self.selected_vars, self.unselected_vars = var_setup.split_vars_by_show_flag(self.expanded_vars)
|
||||||
|
|
||||||
|
t2 = time.perf_counter()
|
||||||
|
self.vars_widget.set_data(self.unselected_vars)
|
||||||
|
|
||||||
|
t3 = time.perf_counter()
|
||||||
|
self.vars_widget.filter_tree()
|
||||||
|
|
||||||
|
t4 = time.perf_counter()
|
||||||
|
self.selected_vars_widget.set_data(self.selected_vars)
|
||||||
|
|
||||||
|
t5 = time.perf_counter()
|
||||||
|
self.selected_vars_widget.filter_tree()
|
||||||
|
|
||||||
|
def on_apply_clicked(self):
|
||||||
|
# Получаем имена всех переменных из правой таблицы (selected_vars_widget)
|
||||||
|
right_var_names = set(self.selected_vars_widget.get_all_var_names())
|
||||||
|
all_items = self.selected_vars_widget.get_all_items()
|
||||||
|
if not all_items:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Устанавливаем show_var=true и enable=true для переменных из правой таблицы
|
||||||
|
def add_or_update_var(item):
|
||||||
|
name = item.text(0)
|
||||||
|
type_str = item.text(1)
|
||||||
|
|
||||||
|
if name in self.var_map:
|
||||||
|
var = self.var_map[name]
|
||||||
|
var['show_var'] = 'true'
|
||||||
|
var['enable'] = 'true'
|
||||||
|
else:
|
||||||
|
file_val = item.data(0, Qt.UserRole + 1)
|
||||||
|
extern_val = item.data(0, Qt.UserRole + 2)
|
||||||
|
static_val = item.data(0, Qt.UserRole + 3)
|
||||||
|
new_var = {
|
||||||
|
'name': name,
|
||||||
|
'type': type_str,
|
||||||
|
'show_var': 'true',
|
||||||
|
'enable': 'true',
|
||||||
|
'shortname': name,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': 't_iq_none',
|
||||||
|
'file': file_val,
|
||||||
|
'extern': str(extern_val).lower() if extern_val else 'false',
|
||||||
|
'static': str(static_val).lower() if static_val else 'false',
|
||||||
|
}
|
||||||
|
self.all_vars.append(new_var)
|
||||||
|
self.var_map[name] = new_var
|
||||||
|
|
||||||
|
for item in all_items:
|
||||||
|
add_or_update_var(item)
|
||||||
|
|
||||||
|
# Сбрасываем show_var и enable у всех переменных, которых нет в правой таблице
|
||||||
|
for var in self.all_vars:
|
||||||
|
if var['name'] not in right_var_names:
|
||||||
|
var['show_var'] = 'false'
|
||||||
|
var['enable'] = 'false'
|
||||||
|
|
||||||
|
# Обновляем expanded_vars чтобы отразить новые show_var и enable
|
||||||
|
def update_expanded_vars(data):
|
||||||
|
for v in data:
|
||||||
|
name = v['name']
|
||||||
|
if name in self.var_map:
|
||||||
|
v['show_var'] = self.var_map[name]['show_var']
|
||||||
|
v['enable'] = self.var_map[name]['enable']
|
||||||
|
if 'children' in v:
|
||||||
|
update_expanded_vars(v['children'])
|
||||||
|
update_expanded_vars(self.expanded_vars)
|
||||||
|
|
||||||
|
# Обновляем отображение в виджетах
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
# Закрываем диалог
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
|
# Обнови on_left_tree_double_click:
|
||||||
|
def on_left_tree_double_click(self, item, column):
|
||||||
|
selected_names = [item.text(0)]
|
||||||
|
if not selected_names:
|
||||||
|
return
|
||||||
|
|
||||||
|
def mark_selected_show_var(data):
|
||||||
|
for var in data:
|
||||||
|
if var['name'] in selected_names:
|
||||||
|
var['show_var'] = 'true'
|
||||||
|
var['enable'] = 'true'
|
||||||
|
if 'children' in var:
|
||||||
|
mark_selected_show_var(var['children'])
|
||||||
|
mark_selected_show_var(self.expanded_vars)
|
||||||
|
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
# Добавь обработчик двойного клика справа (если нужно):
|
||||||
|
def on_rigth_tree_double_click(self, item, column):
|
||||||
|
selected_names = [item.text(0)]
|
||||||
|
if not selected_names:
|
||||||
|
return
|
||||||
|
|
||||||
|
def mark_selected_hide_var(data):
|
||||||
|
for var in data:
|
||||||
|
if var['name'] in selected_names:
|
||||||
|
var['show_var'] = 'false'
|
||||||
|
if 'children' in var:
|
||||||
|
mark_selected_hide_var(var['children'])
|
||||||
|
mark_selected_hide_var(self.expanded_vars)
|
||||||
|
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def keyPressEvent(self, event):
|
||||||
|
if event.key() == Qt.Key_Delete:
|
||||||
|
self.delete_selected_vars()
|
||||||
|
else:
|
||||||
|
super().keyPressEvent(event)
|
||||||
|
|
||||||
|
def delete_selected_vars(self):
|
||||||
|
selected_names = self._get_selected_var_names()
|
||||||
|
if not selected_names:
|
||||||
|
print("nothing selected")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Обновляем var_map и all_vars
|
||||||
|
for name in selected_names:
|
||||||
|
if name in self.var_map:
|
||||||
|
self.var_map[name]['show_var'] = 'false'
|
||||||
|
self.var_map[name]['enable'] = 'false'
|
||||||
|
|
||||||
|
for v in self.all_vars:
|
||||||
|
if v['name'] == name:
|
||||||
|
v['show_var'] = 'false'
|
||||||
|
v['enable'] = 'false'
|
||||||
|
break
|
||||||
|
|
||||||
|
# Проверка пути к XML
|
||||||
|
if not hasattr(self, 'xml_path') or not self.xml_path:
|
||||||
|
from PySide2.QtWidgets import QMessageBox
|
||||||
|
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
|
||||||
|
return
|
||||||
|
|
||||||
|
root, tree = myXML.safe_parse_xml(self.xml_path)
|
||||||
|
if root is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
vars_section = root.find('variables')
|
||||||
|
if vars_section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
for var_elem in vars_section.findall('var'):
|
||||||
|
name = var_elem.attrib.get('name')
|
||||||
|
if name in selected_names:
|
||||||
|
def set_text(tag, value):
|
||||||
|
el = var_elem.find(tag)
|
||||||
|
if el is None:
|
||||||
|
el = ET.SubElement(var_elem, tag)
|
||||||
|
el.text = value
|
||||||
|
set_text('show_var', 'false')
|
||||||
|
set_text('enable', 'false')
|
||||||
|
|
||||||
|
myXML.fwrite(root, self.xml_path)
|
||||||
|
|
||||||
|
self.table.populate(self.all_vars, self.structs, None)
|
||||||
|
|
||||||
|
# Проверка пути к XML
|
||||||
|
if not hasattr(self, 'xml_path') or not self.xml_path:
|
||||||
|
from PySide2.QtWidgets import QMessageBox
|
||||||
|
QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно удалить переменные.")
|
||||||
|
return
|
||||||
|
|
||||||
|
root, tree = myXML.safe_parse_xml(self.xml_path)
|
||||||
|
if root is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
vars_section = root.find('variables')
|
||||||
|
if vars_section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
removed_any = False
|
||||||
|
for var_elem in list(vars_section.findall('var')):
|
||||||
|
name = var_elem.attrib.get('name')
|
||||||
|
if name in selected_names:
|
||||||
|
vars_section.remove(var_elem)
|
||||||
|
removed_any = True
|
||||||
|
self.var_map.pop(name, None)
|
||||||
|
|
||||||
|
# Удаляем из all_vars (глобально)
|
||||||
|
self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names]
|
||||||
|
|
||||||
|
# Удаляем из expanded_vars (тоже глобально)
|
||||||
|
def filter_out_selected(vars_list):
|
||||||
|
filtered = []
|
||||||
|
for v in vars_list:
|
||||||
|
if v['name'] not in selected_names:
|
||||||
|
# Рекурсивно фильтруем детей, если есть
|
||||||
|
if 'children' in v:
|
||||||
|
v = v.copy()
|
||||||
|
v['children'] = filter_out_selected(v['children'])
|
||||||
|
filtered.append(v)
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
self.expanded_vars[:] = filter_out_selected(self.expanded_vars)
|
||||||
|
if removed_any:
|
||||||
|
myXML.fwrite(root, self.xml_path)
|
||||||
|
|
||||||
|
self.update_vars_widget()
|
||||||
|
|
||||||
|
def _get_selected_var_names(self):
|
||||||
|
focused = self.focusWidget()
|
||||||
|
if focused and focused is self.vars_widget.tree:
|
||||||
|
return self.vars_widget.get_selected_var_names()
|
||||||
|
elif focused and focused is self.selected_vars_widget.tree:
|
||||||
|
return self.selected_vars_widget.get_selected_var_names()
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def save_checkbox_state(self):
|
||||||
|
self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def set_autocomplete_tables(self, state):
|
||||||
|
self.vars_widget.set_autocomplete(state)
|
||||||
|
self.selected_vars_widget.set_autocomplete(state)
|
||||||
619
Src/var_setup.py
Normal file
619
Src/var_setup.py
Normal file
@@ -0,0 +1,619 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import lxml.etree as ET
|
||||||
|
from generate_debug_vars import map_type_to_pt, get_iq_define, type_map
|
||||||
|
from enum import IntEnum
|
||||||
|
import scan_vars
|
||||||
|
import myXML
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
|
# Вспомогательные функции, которые теперь будут использоваться виджетом
|
||||||
|
def split_path(path):
|
||||||
|
"""
|
||||||
|
Разбивает путь на компоненты:
|
||||||
|
- 'foo[2].bar[1]->baz' → ['foo', '[2]', 'bar', '[1]', 'baz']
|
||||||
|
Если видит '-' в конце строки (без '>' после) — обрезает этот '-'
|
||||||
|
"""
|
||||||
|
tokens = []
|
||||||
|
token = ''
|
||||||
|
i = 0
|
||||||
|
length = len(path)
|
||||||
|
while i < length:
|
||||||
|
c = path[i]
|
||||||
|
# Разделители: '->' и '.'
|
||||||
|
if c == '-' and i + 1 < length and path[i:i+2] == '->':
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
elif c == '-' and i == length - 1:
|
||||||
|
# '-' на конце строки без '>' после — просто пропускаем его
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
elif c == '.':
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
elif c == '[':
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
token = ''
|
||||||
|
idx = ''
|
||||||
|
while i < length and path[i] != ']':
|
||||||
|
idx += path[i]
|
||||||
|
i += 1
|
||||||
|
if i < length and path[i] == ']':
|
||||||
|
idx += ']'
|
||||||
|
i += 1
|
||||||
|
tokens.append(idx)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
token += c
|
||||||
|
i += 1
|
||||||
|
if token:
|
||||||
|
tokens.append(token)
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def make_absolute_path(path, base_path):
|
||||||
|
if not os.path.isabs(path) and os.path.isdir(base_path):
|
||||||
|
try:
|
||||||
|
return os.path.abspath(os.path.join(base_path, path))
|
||||||
|
except Exception:
|
||||||
|
pass # На случай сбоя в os.path.join или abspath
|
||||||
|
elif os.path.isabs(path):
|
||||||
|
return os.path.abspath(path)
|
||||||
|
else:
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def make_relative_path(abs_path, base_path):
|
||||||
|
abs_path = os.path.abspath(abs_path)
|
||||||
|
base_path = os.path.abspath(base_path)
|
||||||
|
|
||||||
|
# Разбиваем на списки директорий
|
||||||
|
abs_parts = abs_path.split(os.sep)
|
||||||
|
base_parts = base_path.split(os.sep)
|
||||||
|
|
||||||
|
# Проверяем, является ли base_path настоящим префиксом пути (по папкам)
|
||||||
|
if abs_parts[:len(base_parts)] == base_parts:
|
||||||
|
rel_parts = abs_parts[len(base_parts):]
|
||||||
|
return "/".join(rel_parts)
|
||||||
|
|
||||||
|
# Иначе пробуем relpath
|
||||||
|
try:
|
||||||
|
return os.path.relpath(abs_path, base_path).replace("\\", "/")
|
||||||
|
except Exception:
|
||||||
|
return abs_path.replace("\\", "/")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_vars(filename, typedef_map=None):
|
||||||
|
root, tree = myXML.safe_parse_xml(filename)
|
||||||
|
if root is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
if typedef_map is None:
|
||||||
|
typedef_map = {}
|
||||||
|
|
||||||
|
vars_list = []
|
||||||
|
variables_elem = root.find('variables')
|
||||||
|
if variables_elem is not None:
|
||||||
|
for var in variables_elem.findall('var'):
|
||||||
|
name = var.attrib.get('name', '')
|
||||||
|
var_type = var.findtext('type', 'unknown').strip()
|
||||||
|
|
||||||
|
# Вычисляем pt_type и iq_type
|
||||||
|
pt_type = var.findtext('pt_type')
|
||||||
|
if not pt_type:
|
||||||
|
pt_type = map_type_to_pt(var_type, name, typedef_map)
|
||||||
|
|
||||||
|
iq_type = var.findtext('iq_type')
|
||||||
|
if not iq_type:
|
||||||
|
iq_type = get_iq_define(var_type)
|
||||||
|
# Записываем iq_type в XML
|
||||||
|
iq_type_elem = var.find('iq_type')
|
||||||
|
if iq_type_elem is None:
|
||||||
|
iq_type_elem = ET.SubElement(var, 'iq_type')
|
||||||
|
iq_type_elem.text = iq_type
|
||||||
|
|
||||||
|
# Вычисляем pt_type и iq_type
|
||||||
|
pt_type = var.findtext('pt_type')
|
||||||
|
if not pt_type:
|
||||||
|
pt_type = map_type_to_pt(var_type, name, typedef_map)
|
||||||
|
# Записываем pt_type в XML
|
||||||
|
pt_type_elem = var.find('pt_type')
|
||||||
|
if pt_type_elem is None:
|
||||||
|
pt_type_elem = ET.SubElement(var, 'pt_type')
|
||||||
|
pt_type_elem.text = pt_type
|
||||||
|
|
||||||
|
vars_list.append({
|
||||||
|
'name': name,
|
||||||
|
'show_var': var.findtext('show_var', 'false'),
|
||||||
|
'enable': var.findtext('enable', 'false'),
|
||||||
|
'shortname': var.findtext('shortname', name),
|
||||||
|
'pt_type': pt_type,
|
||||||
|
'iq_type': iq_type,
|
||||||
|
'return_type': var.findtext('return_type', 't_iq_none'),
|
||||||
|
'type': var_type,
|
||||||
|
'file': var.findtext('file', ''),
|
||||||
|
'extern': var.findtext('extern', 'false') == 'true',
|
||||||
|
'static': var.findtext('static', 'false') == 'true',
|
||||||
|
})
|
||||||
|
|
||||||
|
myXML.fwrite(root, filename)
|
||||||
|
|
||||||
|
return vars_list
|
||||||
|
|
||||||
|
|
||||||
|
# 2. Парсим structSup.xml
|
||||||
|
def parse_structs(filename):
|
||||||
|
root, tree = myXML.safe_parse_xml(filename)
|
||||||
|
if root is None:
|
||||||
|
return {}, {}
|
||||||
|
|
||||||
|
structs = {}
|
||||||
|
typedef_map = {}
|
||||||
|
|
||||||
|
def parse_struct_element(elem):
|
||||||
|
fields = {}
|
||||||
|
|
||||||
|
for field in elem.findall("field"):
|
||||||
|
fname = field.attrib.get("name")
|
||||||
|
ftype = field.attrib.get("type", "")
|
||||||
|
|
||||||
|
# Проверка на вложенную структуру
|
||||||
|
nested_struct_elem = field.find("struct")
|
||||||
|
|
||||||
|
if nested_struct_elem is not None:
|
||||||
|
# Рекурсивно парсим вложенную структуру и вставляем её как подсловарь
|
||||||
|
nested_fields = parse_struct_element(nested_struct_elem)
|
||||||
|
|
||||||
|
# Оборачиваем в dict с ключом 'type' для хранения типа из XML
|
||||||
|
fields[fname] = {
|
||||||
|
'type': ftype, # здесь тип, например "BENDER_ERROR"
|
||||||
|
**nested_fields # развёрнутые поля вложенной структуры
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# Обычное поле
|
||||||
|
fields[fname] = ftype
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
structs_elem = root.find("structs")
|
||||||
|
if structs_elem is not None:
|
||||||
|
for struct in structs_elem.findall("struct"):
|
||||||
|
name = struct.attrib.get("name")
|
||||||
|
if name and name not in structs:
|
||||||
|
fields = parse_struct_element(struct)
|
||||||
|
structs[name] = fields
|
||||||
|
|
||||||
|
# typedefs без изменений
|
||||||
|
typedefs_elem = root.find("typedefs")
|
||||||
|
if typedefs_elem is not None:
|
||||||
|
for typedef in typedefs_elem.findall("typedef"):
|
||||||
|
name = typedef.attrib.get('name')
|
||||||
|
target_type = typedef.attrib.get('type')
|
||||||
|
if name and target_type:
|
||||||
|
typedef_map[name.strip()] = target_type.strip()
|
||||||
|
|
||||||
|
return structs, typedef_map
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def parse_array_dims(type_str):
|
||||||
|
"""Возвращает базовый тип и список размеров массива"""
|
||||||
|
dims = list(map(int, re.findall(r'\[(\d+)\]', type_str)))
|
||||||
|
base_type = re.sub(r'\[\d+\]', '', type_str).strip()
|
||||||
|
return base_type, dims
|
||||||
|
|
||||||
|
def generate_array_names(prefix, dims, depth=0):
|
||||||
|
"""Рекурсивно генерирует имена для всех элементов многомерного массива"""
|
||||||
|
if not dims:
|
||||||
|
return [prefix]
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for i in range(dims[0]):
|
||||||
|
new_prefix = f"{prefix}[{i}]"
|
||||||
|
children = generate_array_names(new_prefix, dims[1:], depth + 1)
|
||||||
|
result.append({
|
||||||
|
'name': new_prefix,
|
||||||
|
'children': children if len(dims) > 1 else None
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
|
||||||
|
def flatten_array_tree(array_tree):
|
||||||
|
"""Разворачивает дерево массивов в линейный список с вложенными children"""
|
||||||
|
result = []
|
||||||
|
for node in array_tree:
|
||||||
|
entry = {'name': node['name']}
|
||||||
|
if node['children']:
|
||||||
|
entry['children'] = flatten_array_tree(node['children'])
|
||||||
|
result.append(entry)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, depth=0):
|
||||||
|
if depth > 10:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Вспомогательная функция для обработки массивов
|
||||||
|
def process_array(prefix, type_str, structs, typedefs, var_attrs, depth=0):
|
||||||
|
base_type, array_dims = parse_array_dims(type_str)
|
||||||
|
if not array_dims:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# На текущем уровне берем первый размер массива
|
||||||
|
current_dim = array_dims[0]
|
||||||
|
# Оставшиеся размеры — все, кроме первого
|
||||||
|
remaining_dims = array_dims[1:]
|
||||||
|
|
||||||
|
# Для создания типа с оставшимися размерами:
|
||||||
|
if remaining_dims:
|
||||||
|
# Формируем строку типа для оставшихся измерений массива, например int[16]
|
||||||
|
remaining_type_str = f"{base_type}{''.join(f'[{d}]' for d in remaining_dims)}"
|
||||||
|
else:
|
||||||
|
remaining_type_str = base_type
|
||||||
|
|
||||||
|
array_tree = []
|
||||||
|
for i in range(current_dim):
|
||||||
|
name = f"{prefix}[{i}]"
|
||||||
|
# Для каждого элемента передаем уже оставшийся тип массива
|
||||||
|
children = expand_struct_recursively(name, remaining_type_str, structs, typedefs, var_attrs, depth + 1)
|
||||||
|
node = {
|
||||||
|
'name': name,
|
||||||
|
'type': remaining_type_str if remaining_dims else base_type,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
if children:
|
||||||
|
node['children'] = children
|
||||||
|
array_tree.append(node)
|
||||||
|
|
||||||
|
return array_tree
|
||||||
|
|
||||||
|
|
||||||
|
# Если type_str — уже распарсенная структура (dict)
|
||||||
|
if isinstance(type_str, dict):
|
||||||
|
fields = type_str
|
||||||
|
else:
|
||||||
|
# Проверяем, массив ли это
|
||||||
|
base_type, array_dims = parse_array_dims(type_str)
|
||||||
|
if array_dims:
|
||||||
|
return process_array(prefix, type_str, structs, typedefs, var_attrs, depth)
|
||||||
|
|
||||||
|
# Ищем структуру по имени типа
|
||||||
|
base_type = scan_vars.strip_ptr_and_array(type_str)
|
||||||
|
fields = structs.get(base_type)
|
||||||
|
if not isinstance(fields, dict):
|
||||||
|
# Не структура и не массив — просто возвращаем пустой список
|
||||||
|
return []
|
||||||
|
|
||||||
|
children = []
|
||||||
|
for field_name, field_value in fields.items():
|
||||||
|
if field_name == 'type':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Формируем полное имя поля
|
||||||
|
if prefix.endswith('*'):
|
||||||
|
separator = '->'
|
||||||
|
full_name = f"{prefix[:-1]}{separator}{field_name}"
|
||||||
|
else:
|
||||||
|
separator = '.'
|
||||||
|
full_name = f"{prefix}{separator}{field_name}"
|
||||||
|
|
||||||
|
# Определяем тип поля
|
||||||
|
if isinstance(field_value, dict) and isinstance(field_value.get('type'), str):
|
||||||
|
field_type_str = field_value['type']
|
||||||
|
elif isinstance(field_value, str):
|
||||||
|
field_type_str = field_value
|
||||||
|
else:
|
||||||
|
field_type_str = None
|
||||||
|
|
||||||
|
|
||||||
|
if '*' in field_type_str:
|
||||||
|
full_name_prefix = full_name + '*'
|
||||||
|
else:
|
||||||
|
full_name_prefix = full_name
|
||||||
|
|
||||||
|
# Обработка, если поле — строка (тип или массив)
|
||||||
|
if field_type_str:
|
||||||
|
base_subtype, sub_dims = parse_array_dims(field_type_str)
|
||||||
|
if sub_dims:
|
||||||
|
# Массив — раскрываем элементы
|
||||||
|
array_parent = {
|
||||||
|
'name': full_name,
|
||||||
|
'type': field_type_str,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
|
||||||
|
array_children = []
|
||||||
|
flat_names = generate_array_names(full_name, sub_dims)
|
||||||
|
for node in flat_names:
|
||||||
|
# node — dict с ключом 'name' и (возможно) 'children'
|
||||||
|
sub_items = expand_struct_recursively(node['name'], base_subtype, structs, typedefs, var_attrs, depth + 1)
|
||||||
|
child_node = {
|
||||||
|
'name': node['name'],
|
||||||
|
'type': base_subtype,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
if sub_items:
|
||||||
|
child_node['children'] = sub_items
|
||||||
|
array_children.append(child_node)
|
||||||
|
|
||||||
|
array_parent['children'] = array_children
|
||||||
|
children.append(array_parent)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Игнорируем указатели на функции
|
||||||
|
if "(" in field_type_str and "*" in field_type_str and ")" in field_type_str:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(field_value, dict):
|
||||||
|
# Это одиночная структура — раскрываем рекурсивно
|
||||||
|
sub_items = expand_struct_recursively(full_name_prefix, field_value, structs, typedefs, var_attrs, depth + 1)
|
||||||
|
child = {
|
||||||
|
'name': full_name,
|
||||||
|
'type': field_type_str,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
if sub_items:
|
||||||
|
child['children'] = sub_items
|
||||||
|
children.append(child)
|
||||||
|
else:
|
||||||
|
# Обычное поле (int, float, etc.)
|
||||||
|
child = {
|
||||||
|
'name': full_name,
|
||||||
|
'type': field_type_str,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
children.append(child)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Если поле — dict без 'type' или со сложной структурой, обрабатываем как вложенную структуру
|
||||||
|
if isinstance(field_value, dict):
|
||||||
|
type_name = field_value.get('type', '')
|
||||||
|
child = {
|
||||||
|
'name': full_name,
|
||||||
|
'type': type_name,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
subchildren = expand_struct_recursively(full_name_prefix, field_value, structs, typedefs, var_attrs, depth + 1)
|
||||||
|
if subchildren:
|
||||||
|
child['children'] = subchildren
|
||||||
|
children.append(child)
|
||||||
|
|
||||||
|
return children
|
||||||
|
|
||||||
|
|
||||||
|
def expand_vars(vars_list, structs, typedefs):
|
||||||
|
"""
|
||||||
|
Раскрывает структуры и массивы структур в деревья.
|
||||||
|
"""
|
||||||
|
expanded = []
|
||||||
|
|
||||||
|
for var in vars_list:
|
||||||
|
pt_type = var.get('pt_type', '')
|
||||||
|
raw_type = var.get('type', '')
|
||||||
|
|
||||||
|
if var['name'] == 'project':
|
||||||
|
a = 1
|
||||||
|
|
||||||
|
if pt_type.startswith('pt_ptr_'):
|
||||||
|
new_var = var.copy()
|
||||||
|
new_var['children'] = expand_struct_recursively(var['name']+'*', raw_type, structs, typedefs, var)
|
||||||
|
expanded.append(new_var)
|
||||||
|
|
||||||
|
if pt_type.startswith('pt_arr_'):
|
||||||
|
new_var = var.copy()
|
||||||
|
new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var)
|
||||||
|
expanded.append(new_var)
|
||||||
|
|
||||||
|
elif pt_type == 'pt_struct':
|
||||||
|
new_var = var.copy()
|
||||||
|
new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var)
|
||||||
|
expanded.append(new_var)
|
||||||
|
|
||||||
|
elif pt_type == 'pt_union':
|
||||||
|
new_var = var.copy()
|
||||||
|
new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var)
|
||||||
|
expanded.append(new_var)
|
||||||
|
|
||||||
|
else:
|
||||||
|
expanded.append(var)
|
||||||
|
|
||||||
|
return expanded
|
||||||
|
|
||||||
|
|
||||||
|
def build_full_names(parts, full_name):
|
||||||
|
"""
|
||||||
|
Восстанавливает вложенные полные имена из списка частей,
|
||||||
|
ориентируясь на оригинальное полное имя (с '.', '->' и индексами).
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
parts = ['arr', '[0]', '[1]', 'ptr', 'val']
|
||||||
|
full_name = 'arr[0][1].ptr->val'
|
||||||
|
|
||||||
|
→ [
|
||||||
|
'arr',
|
||||||
|
'arr[0]',
|
||||||
|
'arr[0][1]',
|
||||||
|
'arr[0][1].ptr',
|
||||||
|
'arr[0][1].ptr->val'
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
names = []
|
||||||
|
acc = ''
|
||||||
|
idx = 0
|
||||||
|
for part in parts:
|
||||||
|
pos = full_name.find(part, idx)
|
||||||
|
if pos == -1:
|
||||||
|
acc += part
|
||||||
|
else:
|
||||||
|
acc = full_name[:pos + len(part)]
|
||||||
|
idx = pos + len(part)
|
||||||
|
names.append(acc)
|
||||||
|
return names
|
||||||
|
|
||||||
|
def find_var_by_name(tree, name):
|
||||||
|
for var in tree:
|
||||||
|
if var.get('name') == name:
|
||||||
|
return var
|
||||||
|
if 'children' in var:
|
||||||
|
found = find_var_by_name(var['children'], name)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def add_to_nested_tree(tree, var, path_parts, full_names=None, depth=0, source_tree=None):
|
||||||
|
if not path_parts:
|
||||||
|
return
|
||||||
|
|
||||||
|
if full_names is None:
|
||||||
|
full_names = build_full_names(path_parts, var['name'])
|
||||||
|
|
||||||
|
current_name = full_names[depth]
|
||||||
|
|
||||||
|
for child in tree:
|
||||||
|
if child.get('name') == current_name:
|
||||||
|
if depth == len(path_parts) - 1:
|
||||||
|
child.update(var)
|
||||||
|
return
|
||||||
|
if 'children' not in child:
|
||||||
|
child['children'] = []
|
||||||
|
add_to_nested_tree(child['children'], var, path_parts, full_names, depth + 1, source_tree)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ищем в source_tree (expanded_vars) родительский узел по current_name
|
||||||
|
parent_data = {}
|
||||||
|
if source_tree:
|
||||||
|
parent_var = find_var_by_name(source_tree, current_name)
|
||||||
|
if parent_var:
|
||||||
|
# Копируем все поля кроме детей (children)
|
||||||
|
parent_data = {k: v for k, v in parent_var.items() if k != 'children'}
|
||||||
|
|
||||||
|
new_node = {
|
||||||
|
'name': current_name,
|
||||||
|
'children': []
|
||||||
|
}
|
||||||
|
|
||||||
|
# Обновляем new_node данными родителя
|
||||||
|
new_node.update(parent_data)
|
||||||
|
|
||||||
|
if depth == len(path_parts) - 1:
|
||||||
|
new_node.update(var)
|
||||||
|
else:
|
||||||
|
add_to_nested_tree(new_node['children'], var, path_parts, full_names, depth + 1, source_tree)
|
||||||
|
|
||||||
|
tree.append(new_node)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def split_vars_by_show_flag(expanded_vars):
|
||||||
|
unselected_vars = pickle.loads(pickle.dumps(expanded_vars, protocol=pickle.HIGHEST_PROTOCOL))
|
||||||
|
selected_vars = []
|
||||||
|
|
||||||
|
def find_and_remove(var_list, target_name):
|
||||||
|
"""Удаляет элемент по полному имени и возвращает его"""
|
||||||
|
for i, var in enumerate(var_list):
|
||||||
|
if var.get("name") == target_name:
|
||||||
|
return var_list.pop(i)
|
||||||
|
if 'children' in var:
|
||||||
|
found = find_and_remove(var['children'], target_name)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
return None
|
||||||
|
|
||||||
|
def collect_selected_nodes(var):
|
||||||
|
"""Рекурсивно возвращает все show_var=true узлы (включая поддерево)"""
|
||||||
|
nodes = []
|
||||||
|
if var.get('show_var', 'false').lower() == 'true':
|
||||||
|
nodes.append(var)
|
||||||
|
for child in var.get('children', []):
|
||||||
|
nodes.extend(collect_selected_nodes(child))
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
def exists_by_path(tree, full_name):
|
||||||
|
"""
|
||||||
|
Проверяет, существует ли переменная в дереве, следуя по частям пути (например: project → adc → status).
|
||||||
|
Каждая часть ('project', 'project.adc', ...) должна иметь точное совпадение с 'name' в узле.
|
||||||
|
"""
|
||||||
|
path_parts = split_path(full_name)
|
||||||
|
full_names = build_full_names(path_parts, full_name)
|
||||||
|
|
||||||
|
current_level = tree
|
||||||
|
for name in full_names:
|
||||||
|
found = False
|
||||||
|
for var in current_level:
|
||||||
|
if var.get('name') == name:
|
||||||
|
current_level = var.get('children', [])
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
selected_nodes = []
|
||||||
|
for var in expanded_vars:
|
||||||
|
full_name = var['name']
|
||||||
|
# Проверка: если имя содержит вложенность, но целиком есть в корне — пропускаем
|
||||||
|
if ('.' in full_name or '[' in full_name or '->' in full_name):
|
||||||
|
path_parts = split_path(full_name)
|
||||||
|
if exists_by_path(expanded_vars, full_name):
|
||||||
|
# Удалим лишнюю копию из корня unselected_vars
|
||||||
|
find_and_remove(unselected_vars, full_name)
|
||||||
|
else:
|
||||||
|
add_to_nested_tree(unselected_vars, var, path_parts, source_tree=expanded_vars)
|
||||||
|
find_and_remove(unselected_vars, full_name)
|
||||||
|
selected_nodes.extend(collect_selected_nodes(var))
|
||||||
|
|
||||||
|
for node in selected_nodes:
|
||||||
|
full_name = node['name']
|
||||||
|
|
||||||
|
|
||||||
|
path_parts = split_path(full_name)
|
||||||
|
|
||||||
|
# Вырезать из unselected_vars
|
||||||
|
removed = find_and_remove(unselected_vars, full_name)
|
||||||
|
if removed:
|
||||||
|
add_to_nested_tree(selected_vars, removed, path_parts, source_tree=expanded_vars)
|
||||||
|
else:
|
||||||
|
# вдруг удалённый родитель — создаём вручную
|
||||||
|
add_to_nested_tree(selected_vars, node, path_parts, source_tree=expanded_vars)
|
||||||
|
|
||||||
|
return selected_vars, unselected_vars
|
||||||
461
Src/var_table.py
Normal file
461
Src/var_table.py
Normal file
@@ -0,0 +1,461 @@
|
|||||||
|
from PySide2.QtWidgets import (
|
||||||
|
QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
|
||||||
|
QAbstractItemView, QHeaderView, QLabel, QSpacerItem, QSizePolicy, QSpinBox,
|
||||||
|
QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QScrollArea, QWidget
|
||||||
|
)
|
||||||
|
from PySide2.QtGui import QColor, QBrush, QPalette
|
||||||
|
from PySide2.QtCore import Qt, QSettings
|
||||||
|
from enum import IntEnum
|
||||||
|
from generate_debug_vars import type_map
|
||||||
|
import time
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
class rows(IntEnum):
|
||||||
|
No = 0
|
||||||
|
include = 1
|
||||||
|
name = 2
|
||||||
|
type = 3
|
||||||
|
pt_type = 4
|
||||||
|
iq_type = 5
|
||||||
|
ret_type = 6
|
||||||
|
short_name = 7
|
||||||
|
|
||||||
|
class FilterDialog(QDialog):
|
||||||
|
def __init__(self, parent, options, selected, title="Выберите значения"):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.resize(250, 300)
|
||||||
|
self.selected = set(selected)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
|
||||||
|
scroll = QScrollArea(self)
|
||||||
|
scroll.setWidgetResizable(True)
|
||||||
|
container = QWidget()
|
||||||
|
scroll.setWidget(container)
|
||||||
|
|
||||||
|
self.checkboxes = []
|
||||||
|
vbox = QVBoxLayout(container)
|
||||||
|
|
||||||
|
for opt in options:
|
||||||
|
cb = QCheckBox(opt)
|
||||||
|
cb.setChecked(opt in self.selected)
|
||||||
|
vbox.addWidget(cb)
|
||||||
|
self.checkboxes.append(cb)
|
||||||
|
|
||||||
|
layout.addWidget(scroll)
|
||||||
|
|
||||||
|
btn_layout = QHBoxLayout()
|
||||||
|
btn_ok = QPushButton("OK")
|
||||||
|
btn_cancel = QPushButton("Отмена")
|
||||||
|
btn_layout.addWidget(btn_ok)
|
||||||
|
btn_layout.addWidget(btn_cancel)
|
||||||
|
|
||||||
|
layout.addLayout(btn_layout)
|
||||||
|
|
||||||
|
btn_ok.clicked.connect(self.accept)
|
||||||
|
btn_cancel.clicked.connect(self.reject)
|
||||||
|
|
||||||
|
def get_selected(self):
|
||||||
|
return [cb.text() for cb in self.checkboxes if cb.isChecked()]
|
||||||
|
|
||||||
|
|
||||||
|
class SetSizeDialog(QDialog):
|
||||||
|
"""
|
||||||
|
Диалоговое окно для выбора числового значения (размера).
|
||||||
|
"""
|
||||||
|
def __init__(self, parent=None, initial_value=10, min_value=1, max_value=50, title="Укажите размер короткого имени"):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.setFixedSize(320, 120) # Задаем фиксированный размер для аккуратного вида
|
||||||
|
|
||||||
|
# Основной вертикальный макет
|
||||||
|
main_layout = QVBoxLayout(self)
|
||||||
|
|
||||||
|
# Макет для ввода значения
|
||||||
|
input_layout = QHBoxLayout()
|
||||||
|
label = QLabel("Количество символов:", self)
|
||||||
|
|
||||||
|
self.spin_box = QSpinBox(self)
|
||||||
|
self.spin_box.setRange(min_value, max_value) # Устанавливаем диапазон допустимых значений
|
||||||
|
initial_value = parent._shortname_size
|
||||||
|
self.spin_box.setValue(initial_value) # Устанавливаем начальное значение
|
||||||
|
self.spin_box.setFocus() # Устанавливаем фокус на поле ввода
|
||||||
|
|
||||||
|
input_layout.addWidget(label)
|
||||||
|
input_layout.addWidget(self.spin_box)
|
||||||
|
main_layout.addLayout(input_layout)
|
||||||
|
|
||||||
|
# Добавляем пустое пространство для лучшего разделения
|
||||||
|
main_layout.addSpacerItem(QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding))
|
||||||
|
|
||||||
|
# Макет для кнопок
|
||||||
|
btn_layout = QHBoxLayout()
|
||||||
|
btn_layout.addStretch() # Добавляем растягивающийся элемент, чтобы кнопки были справа
|
||||||
|
|
||||||
|
btn_ok = QPushButton("OK")
|
||||||
|
btn_cancel = QPushButton("Отмена")
|
||||||
|
|
||||||
|
btn_layout.addWidget(btn_ok)
|
||||||
|
btn_layout.addWidget(btn_cancel)
|
||||||
|
|
||||||
|
main_layout.addLayout(btn_layout)
|
||||||
|
|
||||||
|
# Подключение сигналов к слотам
|
||||||
|
btn_ok.clicked.connect(self.accept) # При нажатии "OK" диалог закроется со статусом "Accepted"
|
||||||
|
btn_cancel.clicked.connect(self.reject) # При нажатии "Отмена" - со статусом "Rejected"
|
||||||
|
|
||||||
|
def get_selected_size(self):
|
||||||
|
"""
|
||||||
|
Возвращает значение, выбранное в QSpinBox.
|
||||||
|
"""
|
||||||
|
return self.spin_box.value()
|
||||||
|
|
||||||
|
class CtrlScrollComboBox(QComboBox):
|
||||||
|
def wheelEvent(self, event):
|
||||||
|
if event.modifiers() & Qt.ControlModifier:
|
||||||
|
super().wheelEvent(event)
|
||||||
|
else:
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
|
class VariableTableWidget(QTableWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(0, 8, parent)
|
||||||
|
# Таблица переменных
|
||||||
|
self.setHorizontalHeaderLabels([
|
||||||
|
'№', # новый столбец
|
||||||
|
'En',
|
||||||
|
'Name',
|
||||||
|
'Origin Type',
|
||||||
|
'Base Type',
|
||||||
|
'IQ Type',
|
||||||
|
'Return Type',
|
||||||
|
'Short Name'
|
||||||
|
])
|
||||||
|
self.setEditTriggers(QAbstractItemView.AllEditTriggers)
|
||||||
|
self.var_list = []
|
||||||
|
# Инициализируем QSettings с именем организации и приложения
|
||||||
|
self.settings = QSettings("SET", "DebugVarEdit_VarTable")
|
||||||
|
# Восстанавливаем сохранённое состояние, если есть
|
||||||
|
shortsize = self.settings.value("shortname_size", True, type=int)
|
||||||
|
self._shortname_size = shortsize
|
||||||
|
|
||||||
|
self.type_options = list(dict.fromkeys(type_map.values()))
|
||||||
|
self.pt_types_all = [t.replace('pt_', '') for t in self.type_options]
|
||||||
|
self.iq_types_all = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
|
||||||
|
# Задаём базовые iq-типы (без префикса 'iq_')
|
||||||
|
self.iq_types = ['iq_none', 'iq', 'iq10', 'iq15', 'iq19', 'iq24']
|
||||||
|
# Фильтруем типы из type_map.values() исключая те, что содержат 'arr' или 'ptr'
|
||||||
|
type_options = [t for t in dict.fromkeys(type_map.values()) if 'arr' not in t and 'ptr' not in t and
|
||||||
|
'struct' not in t and 'union' not in t and '64' not in t]
|
||||||
|
# Формируем display_type_options без префикса 'pt_'
|
||||||
|
self.pt_types = [t.replace('pt_', '') for t in type_options]
|
||||||
|
|
||||||
|
self._iq_type_filter = list(self.iq_types) # Текущий фильтр iq типов (по умолчанию все)
|
||||||
|
self._pt_type_filter = list(self.pt_types)
|
||||||
|
self._ret_type_filter = list(self.iq_types)
|
||||||
|
header = self.horizontalHeader()
|
||||||
|
# Для остальных колонок — растяжение (Stretch), чтобы они заняли всю оставшуюся ширину
|
||||||
|
|
||||||
|
for col in range(self.columnCount()):
|
||||||
|
if col == self.columnCount() - 1:
|
||||||
|
header.setSectionResizeMode(col, QHeaderView.Stretch)
|
||||||
|
else:
|
||||||
|
header.setSectionResizeMode(col, QHeaderView.Interactive)
|
||||||
|
|
||||||
|
parent_widget = self.parentWidget()
|
||||||
|
# Сделаем колонки с номерами фиксированной ширины
|
||||||
|
self.setColumnWidth(rows.No, 30)
|
||||||
|
self.setColumnWidth(rows.include, 30)
|
||||||
|
self.setColumnWidth(rows.pt_type, 85)
|
||||||
|
self.setColumnWidth(rows.iq_type, 85)
|
||||||
|
self.setColumnWidth(rows.ret_type, 85)
|
||||||
|
|
||||||
|
self.setColumnWidth(rows.name, 300)
|
||||||
|
self.setColumnWidth(rows.type, 100)
|
||||||
|
self._resizing = False
|
||||||
|
self.horizontalHeader().sectionResized.connect(self.on_section_resized)
|
||||||
|
self.horizontalHeader().sectionClicked.connect(self.on_header_clicked)
|
||||||
|
|
||||||
|
|
||||||
|
def populate(self, vars_list, structs, on_change_callback):
|
||||||
|
self.var_list = vars_list
|
||||||
|
|
||||||
|
# --- ДО: удаляем отображение структур и union-переменных
|
||||||
|
for var in vars_list:
|
||||||
|
pt_type = var.get('pt_type', '')
|
||||||
|
if 'struct' in pt_type or 'union' in pt_type:
|
||||||
|
var['show_var'] = 'false'
|
||||||
|
var['enable'] = 'false'
|
||||||
|
|
||||||
|
|
||||||
|
filtered_vars = [v for v in vars_list if v.get('show_var', 'false') == 'true']
|
||||||
|
self.setRowCount(len(filtered_vars))
|
||||||
|
self.verticalHeader().setVisible(False)
|
||||||
|
style_with_padding = "padding-left: 5px; padding-right: 5px; font-size: 14pt; font-family: 'Segoe UI';"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for row, var in enumerate(filtered_vars):
|
||||||
|
# №
|
||||||
|
no_item = QTableWidgetItem(str(row))
|
||||||
|
no_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||||
|
self.setItem(row, rows.No, no_item)
|
||||||
|
|
||||||
|
# Enable
|
||||||
|
cb = QCheckBox()
|
||||||
|
cb.setChecked(var.get('enable', 'false') == 'true')
|
||||||
|
cb.stateChanged.connect(on_change_callback)
|
||||||
|
cb.setStyleSheet(style_with_padding)
|
||||||
|
self.setCellWidget(row, rows.include, cb)
|
||||||
|
|
||||||
|
# Name
|
||||||
|
name_edit = QLineEdit(var['name'])
|
||||||
|
if var['type'] in structs:
|
||||||
|
completer = QCompleter(structs[var['type']].keys())
|
||||||
|
completer.setCaseSensitivity(Qt.CaseInsensitive)
|
||||||
|
name_edit.setCompleter(completer)
|
||||||
|
name_edit.textChanged.connect(on_change_callback)
|
||||||
|
name_edit.setStyleSheet(style_with_padding)
|
||||||
|
self.setCellWidget(row, rows.name, name_edit)
|
||||||
|
|
||||||
|
# Origin Type (readonly)
|
||||||
|
origin_item = QTableWidgetItem(var.get('type', ''))
|
||||||
|
origin_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||||
|
origin_item.setToolTip(var.get('type', '')) # Всплывающая подсказка
|
||||||
|
origin_item.setForeground(QBrush(Qt.black))
|
||||||
|
self.setItem(row, rows.type, origin_item)
|
||||||
|
|
||||||
|
# pt_type
|
||||||
|
pt_combo = CtrlScrollComboBox()
|
||||||
|
pt_combo.addItems(self.pt_types)
|
||||||
|
value = var['pt_type'].replace('pt_', '')
|
||||||
|
if value not in self.pt_types:
|
||||||
|
pt_combo.addItem(value)
|
||||||
|
pt_combo.setCurrentText(value)
|
||||||
|
pt_combo.currentTextChanged.connect(on_change_callback)
|
||||||
|
pt_combo.setStyleSheet(style_with_padding)
|
||||||
|
self.setCellWidget(row, rows.pt_type, pt_combo)
|
||||||
|
|
||||||
|
# iq_type
|
||||||
|
iq_combo = CtrlScrollComboBox()
|
||||||
|
iq_combo.addItems(self.iq_types)
|
||||||
|
value = var['iq_type'].replace('t_', '')
|
||||||
|
if value not in self.iq_types:
|
||||||
|
iq_combo.addItem(value)
|
||||||
|
iq_combo.setCurrentText(value)
|
||||||
|
iq_combo.currentTextChanged.connect(on_change_callback)
|
||||||
|
iq_combo.setStyleSheet(style_with_padding)
|
||||||
|
self.setCellWidget(row, rows.iq_type, iq_combo)
|
||||||
|
|
||||||
|
# return_type
|
||||||
|
ret_combo = CtrlScrollComboBox()
|
||||||
|
ret_combo.addItems(self.iq_types)
|
||||||
|
value = var['return_type'].replace('t_', '')
|
||||||
|
ret_combo.setCurrentText(value)
|
||||||
|
ret_combo.currentTextChanged.connect(on_change_callback)
|
||||||
|
ret_combo.setStyleSheet(style_with_padding)
|
||||||
|
self.setCellWidget(row, rows.ret_type, ret_combo)
|
||||||
|
|
||||||
|
# short_name
|
||||||
|
short_name_val = var.get('shortname', var['name'])
|
||||||
|
short_name_edit = QLineEdit(short_name_val)
|
||||||
|
short_name_edit.textChanged.connect(on_change_callback)
|
||||||
|
short_name_edit.setStyleSheet(style_with_padding)
|
||||||
|
self.setCellWidget(row, rows.short_name, short_name_edit)
|
||||||
|
|
||||||
|
self.check()
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
warning_color = QColor("#FFFACD")
|
||||||
|
error_color = QColor("#FFB6C1")
|
||||||
|
tooltip_shortname = "Short Name длиннее 10 символов — будет обрезано при генерации"
|
||||||
|
tooltip_missing = 'Имя переменной не найдено среди переменных. Добавьте её через кнопку "Добавить переменные"'
|
||||||
|
|
||||||
|
var_names_set = {v.get('name') for v in self.var_list if v.get('name')}
|
||||||
|
|
||||||
|
t0 = time.time()
|
||||||
|
self.setUpdatesEnabled(False)
|
||||||
|
for row in range(self.rowCount()):
|
||||||
|
t1 = time.time()
|
||||||
|
name_widget = self.cellWidget(row, rows.name)
|
||||||
|
t2 = time.time()
|
||||||
|
name = name_widget.text() if name_widget else ""
|
||||||
|
|
||||||
|
short_name_edit = self.cellWidget(row, rows.short_name)
|
||||||
|
t3 = time.time()
|
||||||
|
shortname = short_name_edit.text() if short_name_edit else ""
|
||||||
|
|
||||||
|
long_shortname = len(shortname) > self._shortname_size
|
||||||
|
found = name in var_names_set
|
||||||
|
|
||||||
|
color = None
|
||||||
|
tooltip = ""
|
||||||
|
if not found:
|
||||||
|
color = error_color
|
||||||
|
tooltip = tooltip_missing
|
||||||
|
elif long_shortname:
|
||||||
|
color = warning_color
|
||||||
|
tooltip = tooltip_shortname
|
||||||
|
|
||||||
|
self.highlight_row(row, color, tooltip)
|
||||||
|
t4 = time.time()
|
||||||
|
|
||||||
|
self.setUpdatesEnabled(True)
|
||||||
|
#print(f"Row {row}: cellWidget(name) {t2-t1:.4f}s, cellWidget(shortname) {t3-t2:.4f}s, highlight_row {t4-t3:.4f}s")
|
||||||
|
|
||||||
|
|
||||||
|
def read_data(self):
|
||||||
|
result = []
|
||||||
|
for row in range(self.rowCount()):
|
||||||
|
cb = self.cellWidget(row, rows.include)
|
||||||
|
name = self.cellWidget(row, rows.name).text()
|
||||||
|
pt = self.cellWidget(row, rows.pt_type).currentText()
|
||||||
|
iq = self.cellWidget(row, rows.iq_type).currentText()
|
||||||
|
ret = self.cellWidget(row, rows.ret_type).currentText()
|
||||||
|
shortname = self.cellWidget(row, rows.short_name).text()
|
||||||
|
origin_type = self.item(row, rows.type).text()
|
||||||
|
|
||||||
|
result.append({
|
||||||
|
'show_var': True,
|
||||||
|
'enable': cb.isChecked(),
|
||||||
|
'name': name,
|
||||||
|
'pt_type': f'pt_{pt}',
|
||||||
|
'iq_type': f't_{iq}',
|
||||||
|
'return_type': f't_{ret}',
|
||||||
|
'shortname': shortname,
|
||||||
|
'type': origin_type,
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def on_header_clicked(self, logicalIndex):
|
||||||
|
if logicalIndex == rows.pt_type:
|
||||||
|
dlg = FilterDialog(self, self.pt_types_all, self._pt_type_filter, "Выберите базовые типы")
|
||||||
|
if dlg.exec_():
|
||||||
|
self._pt_type_filter = dlg.get_selected()
|
||||||
|
self.update_comboboxes({rows.pt_type: self._pt_type_filter})
|
||||||
|
|
||||||
|
elif logicalIndex == rows.iq_type:
|
||||||
|
dlg = FilterDialog(self, self.iq_types_all, self._iq_type_filter, "Выберите IQ типы")
|
||||||
|
if dlg.exec_():
|
||||||
|
self._iq_type_filter = dlg.get_selected()
|
||||||
|
self.update_comboboxes({rows.iq_type: self._iq_type_filter})
|
||||||
|
|
||||||
|
elif logicalIndex == rows.ret_type:
|
||||||
|
dlg = FilterDialog(self, self.iq_types_all, self._ret_type_filter, "Выберите IQ типы")
|
||||||
|
if dlg.exec_():
|
||||||
|
self._ret_type_filter = dlg.get_selected()
|
||||||
|
self.update_comboboxes({rows.ret_type: self._ret_type_filter})
|
||||||
|
|
||||||
|
elif logicalIndex == rows.short_name:
|
||||||
|
dlg = SetSizeDialog(self)
|
||||||
|
if dlg.exec_():
|
||||||
|
self._shortname_size = dlg.get_selected_size()
|
||||||
|
self.settings.setValue("shortname_size", self._shortname_size)
|
||||||
|
self.check()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def update_comboboxes(self, columns_filters: Dict[int, List[str]]):
|
||||||
|
"""
|
||||||
|
Обновляет combobox-ячейки в указанных столбцах таблицы.
|
||||||
|
|
||||||
|
:param columns_filters: dict, где ключ — индекс столбца,
|
||||||
|
значение — список допустимых вариантов для combobox.
|
||||||
|
"""
|
||||||
|
for row in range(self.rowCount()):
|
||||||
|
for col, allowed_items in columns_filters.items():
|
||||||
|
combo = self.cellWidget(row, col)
|
||||||
|
if combo:
|
||||||
|
current = combo.currentText()
|
||||||
|
combo.blockSignals(True)
|
||||||
|
combo.clear()
|
||||||
|
|
||||||
|
combo.addItems(allowed_items)
|
||||||
|
if current in allowed_items:
|
||||||
|
combo.setCurrentText(current)
|
||||||
|
else:
|
||||||
|
combo.setCurrentIndex(0)
|
||||||
|
combo.blockSignals(False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def on_section_resized(self, logicalIndex, oldSize, newSize):
|
||||||
|
if self._resizing:
|
||||||
|
return # предотвращаем рекурсию
|
||||||
|
|
||||||
|
min_width = 50
|
||||||
|
delta = newSize - oldSize
|
||||||
|
right_index = logicalIndex + 1
|
||||||
|
|
||||||
|
if right_index >= self.columnCount():
|
||||||
|
# Если правая колока - нет соседа, ограничиваем минимальную ширину
|
||||||
|
if newSize < min_width:
|
||||||
|
self._resizing = True
|
||||||
|
self.setColumnWidth(logicalIndex, min_width)
|
||||||
|
self._resizing = False
|
||||||
|
return
|
||||||
|
|
||||||
|
self._resizing = True
|
||||||
|
try:
|
||||||
|
right_width = self.columnWidth(right_index)
|
||||||
|
new_right_width = right_width - delta
|
||||||
|
|
||||||
|
# Если соседняя колонка станет уже минимальной - подкорректируем левую
|
||||||
|
if new_right_width < min_width:
|
||||||
|
new_right_width = min_width
|
||||||
|
newSize = oldSize + (right_width - min_width)
|
||||||
|
self.setColumnWidth(logicalIndex, newSize)
|
||||||
|
|
||||||
|
self.setColumnWidth(right_index, new_right_width)
|
||||||
|
finally:
|
||||||
|
self._resizing = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_row(self, row: int, color: QColor = None, tooltip: str = ""):
|
||||||
|
"""
|
||||||
|
Подсвечивает строку таблицы цветом `color`, не меняя шрифт.
|
||||||
|
Работает с QLineEdit, QComboBox, QCheckBox (включая обёртки).
|
||||||
|
Если `color=None`, сбрасывает подсветку.
|
||||||
|
"""
|
||||||
|
css_reset = "background-color: none; font: inherit;"
|
||||||
|
css_color = f"background-color: {color.name()};" if color else css_reset
|
||||||
|
|
||||||
|
for col in range(self.columnCount()):
|
||||||
|
item = self.item(row, col)
|
||||||
|
widget = self.cellWidget(row, col)
|
||||||
|
|
||||||
|
if item is not None:
|
||||||
|
current_bg = item.background().color() if item.background() else None
|
||||||
|
if color and current_bg != color:
|
||||||
|
item.setBackground(QBrush(color))
|
||||||
|
item.setToolTip(tooltip)
|
||||||
|
elif not color and current_bg is not None:
|
||||||
|
item.setBackground(QBrush(Qt.NoBrush))
|
||||||
|
item.setToolTip("")
|
||||||
|
elif widget is not None:
|
||||||
|
if widget.styleSheet() != css_color:
|
||||||
|
widget.setStyleSheet(css_color)
|
||||||
|
current_tip = widget.toolTip()
|
||||||
|
if color and current_tip != tooltip:
|
||||||
|
widget.setToolTip(tooltip)
|
||||||
|
elif not color and current_tip:
|
||||||
|
widget.setToolTip("")
|
||||||
|
|
||||||
|
def get_selected_var_names(self):
|
||||||
|
selected_indexes = self.selectedIndexes()
|
||||||
|
selected_rows = set(index.row() for index in selected_indexes)
|
||||||
|
names = []
|
||||||
|
|
||||||
|
for row in selected_rows:
|
||||||
|
name_widget = self.cellWidget(row, rows.name)
|
||||||
|
if name_widget:
|
||||||
|
name = name_widget.text()
|
||||||
|
if name:
|
||||||
|
names.append(name)
|
||||||
|
return names
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
import os
|
|
||||||
|
|
||||||
# Пути
|
|
||||||
dist_path = os.path.abspath("./") # текущая папка — exe будет тут
|
|
||||||
work_path = os.path.abspath("./build_temp")
|
|
||||||
spec_path = os.path.abspath("./build_temp")
|
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
libclang_path = os.path.join(script_dir, "libclang.dll")
|
|
||||||
|
|
||||||
# Запуск PyInstaller с нужными параметрами
|
|
||||||
cmd = [
|
|
||||||
"pyinstaller",
|
|
||||||
"--onefile",
|
|
||||||
"--windowed",
|
|
||||||
"--name", "DebugVarEdit",
|
|
||||||
"--add-binary", f"{libclang_path};.",
|
|
||||||
"--distpath", dist_path,
|
|
||||||
"--workpath", work_path,
|
|
||||||
"--specpath", spec_path,
|
|
||||||
"./Src/setupVars_GUI.py"
|
|
||||||
]
|
|
||||||
|
|
||||||
result = subprocess.run(cmd)
|
|
||||||
if result.returncode == 0:
|
|
||||||
# Удаляем временные папки
|
|
||||||
for folder in ["build_temp", "__pycache__"]:
|
|
||||||
if os.path.exists(folder):
|
|
||||||
shutil.rmtree(folder)
|
|
||||||
|
|
||||||
print("Сборка успешно завершена!")
|
|
||||||
else:
|
|
||||||
print("Сборка завершилась с ошибкой.")
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# -*- mode: python ; coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
a = Analysis(
|
|
||||||
['..\\generateVars.py'],
|
|
||||||
pathex=[],
|
|
||||||
binaries=[],
|
|
||||||
datas=[],
|
|
||||||
hiddenimports=[],
|
|
||||||
hookspath=[],
|
|
||||||
hooksconfig={},
|
|
||||||
runtime_hooks=[],
|
|
||||||
excludes=[],
|
|
||||||
noarchive=False,
|
|
||||||
optimize=0,
|
|
||||||
)
|
|
||||||
pyz = PYZ(a.pure)
|
|
||||||
|
|
||||||
exe = EXE(
|
|
||||||
pyz,
|
|
||||||
a.scripts,
|
|
||||||
a.binaries,
|
|
||||||
a.datas,
|
|
||||||
[],
|
|
||||||
name='generateVars',
|
|
||||||
debug=False,
|
|
||||||
bootloader_ignore_signals=False,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
upx_exclude=[],
|
|
||||||
runtime_tmpdir=None,
|
|
||||||
console=True,
|
|
||||||
disable_windowed_traceback=False,
|
|
||||||
argv_emulation=False,
|
|
||||||
target_arch=None,
|
|
||||||
codesign_identity=None,
|
|
||||||
entitlements_file=None,
|
|
||||||
)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,230 +0,0 @@
|
|||||||
('F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\generateVars.exe',
|
|
||||||
True,
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-console.ico',
|
|
||||||
None,
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
|
||||||
b'"urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n <trustInfo x'
|
|
||||||
b'mlns="urn:schemas-microsoft-com:asm.v3">\n <security>\n <requested'
|
|
||||||
b'Privileges>\n <requestedExecutionLevel level="asInvoker" uiAccess='
|
|
||||||
b'"false"/>\n </requestedPrivileges>\n </security>\n </trustInfo>\n '
|
|
||||||
b'<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\n <'
|
|
||||||
b'application>\n <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f'
|
|
||||||
b'0}"/>\n <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\n '
|
|
||||||
b' <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\n <s'
|
|
||||||
b'upportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\n <supporte'
|
|
||||||
b'dOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\n </application>\n <'
|
|
||||||
b'/compatibility>\n <application xmlns="urn:schemas-microsoft-com:asm.v3">'
|
|
||||||
b'\n <windowsSettings>\n <longPathAware xmlns="http://schemas.micros'
|
|
||||||
b'oft.com/SMI/2016/WindowsSettings">true</longPathAware>\n </windowsSett'
|
|
||||||
b'ings>\n </application>\n <dependency>\n <dependentAssembly>\n <ass'
|
|
||||||
b'emblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version='
|
|
||||||
b'"6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" langua'
|
|
||||||
b'ge="*"/>\n </dependentAssembly>\n </dependency>\n</assembly>',
|
|
||||||
True,
|
|
||||||
False,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\generateVars.pkg',
|
|
||||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
|
||||||
('PYZ-00.pyz',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\PYZ-00.pyz',
|
|
||||||
'PYZ'),
|
|
||||||
('struct',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\struct.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod01_archive',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod01_archive.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod02_importers',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod02_importers.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod03_ctypes',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod03_ctypes.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod04_pywin32',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod04_pywin32.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyiboot01_bootstrap',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_inspect',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('generateVars',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\generateVars.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('python313.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('_decimal.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_hashlib.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('select.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_socket.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('unicodedata.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_lzma.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_bz2.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_elementtree.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_elementtree.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('pyexpat.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\pyexpat.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_ssl.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ssl.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('VCRUNTIME140.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libcrypto-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libssl-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('ucrtbase.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\ucrtbase.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('base_library.zip',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\base_library.zip',
|
|
||||||
'DATA')],
|
|
||||||
[],
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
1751903262,
|
|
||||||
[('run.exe',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
|
||||||
'EXECUTABLE')],
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll')
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
('F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\generateVars.pkg',
|
|
||||||
{'BINARY': True,
|
|
||||||
'DATA': True,
|
|
||||||
'EXECUTABLE': True,
|
|
||||||
'EXTENSION': True,
|
|
||||||
'PYMODULE': True,
|
|
||||||
'PYSOURCE': True,
|
|
||||||
'PYZ': False,
|
|
||||||
'SPLASH': True,
|
|
||||||
'SYMLINK': False},
|
|
||||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
|
||||||
('PYZ-00.pyz',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\PYZ-00.pyz',
|
|
||||||
'PYZ'),
|
|
||||||
('struct',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\struct.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod01_archive',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod01_archive.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod02_importers',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod02_importers.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod03_ctypes',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod03_ctypes.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod04_pywin32',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\localpycs\\pyimod04_pywin32.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyiboot01_bootstrap',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_inspect',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('generateVars',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\generateVars.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('python313.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('_decimal.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_hashlib.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('select.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_socket.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('unicodedata.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_lzma.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_bz2.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_elementtree.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_elementtree.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('pyexpat.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\pyexpat.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_ssl.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ssl.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('VCRUNTIME140.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libcrypto-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libssl-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('ucrtbase.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\ucrtbase.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('base_library.zip',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\base_library.zip',
|
|
||||||
'DATA')],
|
|
||||||
'python313.dll',
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
[],
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None)
|
|
||||||
Binary file not shown.
@@ -1,415 +0,0 @@
|
|||||||
('F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\generateVars\\PYZ-00.pyz',
|
|
||||||
[('__future__',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\__future__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_colorize',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_compat_pickle',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_compat_pickle.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_compression',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_compression.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_opcode_metadata',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_opcode_metadata.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_py_abc',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_pydatetime',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_pydatetime.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_pydecimal',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_pydecimal.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_strptime',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_strptime.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('_threading_local',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_threading_local.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('argparse',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\argparse.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('ast',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ast.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('base64',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\base64.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('bisect',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\bisect.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('bz2',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\bz2.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('calendar',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\calendar.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('contextlib',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\contextlib.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('contextvars',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\contextvars.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('copy',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\copy.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('csv',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\csv.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('dataclasses',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\dataclasses.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('datetime',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\datetime.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('decimal',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\decimal.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('dis',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\dis.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email._encoded_words',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_encoded_words.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email._header_value_parser',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_header_value_parser.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email._parseaddr',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_parseaddr.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email._policybase',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_policybase.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.base64mime',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\base64mime.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.charset',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\charset.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.contentmanager',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\contentmanager.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.encoders',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\encoders.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.errors',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\errors.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.feedparser',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\feedparser.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.generator',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\generator.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.header',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\header.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.headerregistry',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\headerregistry.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.iterators',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\iterators.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.message',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\message.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.parser',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\parser.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.policy',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\policy.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.quoprimime',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\quoprimime.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('email.utils',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\utils.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('fnmatch',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\fnmatch.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('fractions',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\fractions.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('ftplib',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ftplib.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('getopt',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\getopt.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('getpass',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\getpass.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('gettext',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\gettext.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('glob',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\glob.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('gzip',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\gzip.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('hashlib',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\hashlib.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('http',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\http\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('http.client',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\http\\client.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('http.cookiejar',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\http\\cookiejar.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib._abc',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib._bootstrap',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_bootstrap.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib._bootstrap_external',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_bootstrap_external.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.abc',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.machinery',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\machinery.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.metadata',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.metadata._adapters',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_adapters.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.metadata._collections',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_collections.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.metadata._functools',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_functools.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.metadata._itertools',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_itertools.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.metadata._meta',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_meta.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.metadata._text',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_text.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.readers',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\readers.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.resources',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.resources._adapters',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_adapters.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.resources._common',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_common.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.resources._functional',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_functional.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.resources._itertools',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_itertools.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.resources.abc',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.resources.readers',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\readers.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('importlib.util',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\util.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('inspect',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\inspect.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('ipaddress',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ipaddress.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('json',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('json.decoder',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\decoder.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('json.encoder',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\encoder.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('json.scanner',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\scanner.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('logging',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\logging\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('lzma',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\lzma.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('mimetypes',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\mimetypes.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('netrc',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\netrc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('nturl2path',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\nturl2path.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('numbers',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\numbers.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('opcode',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\opcode.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pathlib',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pathlib._abc',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pathlib._local',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_local.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pickle',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pickle.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pprint',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pprint.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('py_compile',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\py_compile.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('quopri',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\quopri.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('random',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\random.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('selectors',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\selectors.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('shutil',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\shutil.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('signal',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\signal.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('socket',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\socket.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('ssl',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ssl.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('statistics',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\statistics.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('string',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\string.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('stringprep',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('subprocess',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\subprocess.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('tarfile',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tarfile.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('tempfile',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tempfile.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('textwrap',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\textwrap.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('threading',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\threading.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('token',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\token.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('tokenize',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tokenize.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('tracemalloc',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tracemalloc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('typing',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\typing.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('urllib',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('urllib.error',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\error.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('urllib.parse',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\parse.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('urllib.request',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\request.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('urllib.response',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\response.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.etree',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\etree\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.etree.ElementInclude',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\etree\\ElementInclude.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.etree.ElementPath',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\etree\\ElementPath.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.etree.ElementTree',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\etree\\ElementTree.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.etree.cElementTree',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\etree\\cElementTree.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.parsers',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\parsers\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.parsers.expat',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\parsers\\expat.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.sax',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\sax\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.sax._exceptions',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\sax\\_exceptions.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.sax.expatreader',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\sax\\expatreader.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.sax.handler',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\sax\\handler.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.sax.saxutils',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\sax\\saxutils.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('xml.sax.xmlreader',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\xml\\sax\\xmlreader.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('zipfile',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('zipfile._path',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\_path\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('zipfile._path.glob',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\_path\\glob.py',
|
|
||||||
'PYMODULE')])
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
This file lists modules PyInstaller was not able to find. This does not
|
|
||||||
necessarily mean this module is required for running your program. Python and
|
|
||||||
Python 3rd-party packages include a lot of conditional or optional modules. For
|
|
||||||
example the module 'ntpath' only exists on Windows, whereas the module
|
|
||||||
'posixpath' only exists on Posix systems.
|
|
||||||
|
|
||||||
Types if import:
|
|
||||||
* top-level: imported at the top-level - look at these first
|
|
||||||
* conditional: imported within an if-statement
|
|
||||||
* delayed: imported within a function
|
|
||||||
* optional: imported within a try-except-statement
|
|
||||||
|
|
||||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
|
||||||
tracking down the missing module yourself. Thanks!
|
|
||||||
|
|
||||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional)
|
|
||||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional)
|
|
||||||
missing module named 'collections.abc' - imported by traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level), tracemalloc (top-level), xml.etree.ElementTree (top-level), http.client (top-level)
|
|
||||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
|
|
||||||
missing module named resource - imported by posix (top-level)
|
|
||||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), netrc (delayed, conditional), getpass (delayed, optional)
|
|
||||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
|
||||||
missing module named _scproxy - imported by urllib.request (conditional)
|
|
||||||
missing module named termios - imported by getpass (optional)
|
|
||||||
missing module named _posixsubprocess - imported by subprocess (conditional)
|
|
||||||
missing module named fcntl - imported by subprocess (optional)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
|||||||
# -*- mode: python ; coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
a = Analysis(
|
|
||||||
['..\\scanVars.py'],
|
|
||||||
pathex=[],
|
|
||||||
binaries=[('F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools/build/libclang.dll', '.')],
|
|
||||||
datas=[],
|
|
||||||
hiddenimports=[],
|
|
||||||
hookspath=[],
|
|
||||||
hooksconfig={},
|
|
||||||
runtime_hooks=[],
|
|
||||||
excludes=[],
|
|
||||||
noarchive=False,
|
|
||||||
optimize=0,
|
|
||||||
)
|
|
||||||
pyz = PYZ(a.pure)
|
|
||||||
|
|
||||||
exe = EXE(
|
|
||||||
pyz,
|
|
||||||
a.scripts,
|
|
||||||
a.binaries,
|
|
||||||
a.datas,
|
|
||||||
[],
|
|
||||||
name='scanVars',
|
|
||||||
debug=False,
|
|
||||||
bootloader_ignore_signals=False,
|
|
||||||
strip=False,
|
|
||||||
upx=True,
|
|
||||||
upx_exclude=[],
|
|
||||||
runtime_tmpdir=None,
|
|
||||||
console=True,
|
|
||||||
disable_windowed_traceback=False,
|
|
||||||
argv_emulation=False,
|
|
||||||
target_arch=None,
|
|
||||||
codesign_identity=None,
|
|
||||||
entitlements_file=None,
|
|
||||||
)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,291 +0,0 @@
|
|||||||
('F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\scanVars.exe',
|
|
||||||
True,
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-console.ico',
|
|
||||||
None,
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
|
||||||
b'"urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n <trustInfo x'
|
|
||||||
b'mlns="urn:schemas-microsoft-com:asm.v3">\n <security>\n <requested'
|
|
||||||
b'Privileges>\n <requestedExecutionLevel level="asInvoker" uiAccess='
|
|
||||||
b'"false"/>\n </requestedPrivileges>\n </security>\n </trustInfo>\n '
|
|
||||||
b'<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\n <'
|
|
||||||
b'application>\n <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f'
|
|
||||||
b'0}"/>\n <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\n '
|
|
||||||
b' <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\n <s'
|
|
||||||
b'upportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\n <supporte'
|
|
||||||
b'dOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\n </application>\n <'
|
|
||||||
b'/compatibility>\n <application xmlns="urn:schemas-microsoft-com:asm.v3">'
|
|
||||||
b'\n <windowsSettings>\n <longPathAware xmlns="http://schemas.micros'
|
|
||||||
b'oft.com/SMI/2016/WindowsSettings">true</longPathAware>\n </windowsSett'
|
|
||||||
b'ings>\n </application>\n <dependency>\n <dependentAssembly>\n <ass'
|
|
||||||
b'emblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version='
|
|
||||||
b'"6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" langua'
|
|
||||||
b'ge="*"/>\n </dependentAssembly>\n </dependency>\n</assembly>',
|
|
||||||
True,
|
|
||||||
False,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\scanVars.pkg',
|
|
||||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
|
||||||
('PYZ-00.pyz',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\PYZ-00.pyz',
|
|
||||||
'PYZ'),
|
|
||||||
('struct',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\struct.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod01_archive',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod01_archive.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod02_importers',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod02_importers.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod03_ctypes',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod03_ctypes.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod04_pywin32',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod04_pywin32.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyiboot01_bootstrap',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_inspect',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_setuptools',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_setuptools.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_pkgutil',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_multiprocessing',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('scanVars',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\scanVars.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('libclang.dll',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\libclang.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('python313.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('select.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_multiprocessing.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_multiprocessing.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('pyexpat.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\pyexpat.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_ssl.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ssl.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_hashlib.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('unicodedata.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_decimal.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_socket.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_lzma.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_bz2.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_ctypes.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ctypes.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_queue.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_overlapped.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_asyncio.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_asyncio.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_wmi.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_wmi.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_elementtree.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_elementtree.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('VCRUNTIME140.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libssl-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libcrypto-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libffi-8.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('VCRUNTIME140_1.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('ucrtbase.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\ucrtbase.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\WHEEL',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\WHEEL',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\INSTALLER',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\INSTALLER',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\RECORD',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\RECORD',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\top_level.txt',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\top_level.txt',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\LICENSE',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\LICENSE',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\REQUESTED',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\REQUESTED',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\METADATA',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\METADATA',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\jaraco\\text\\Lorem ipsum.txt',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\jaraco\\text\\Lorem '
|
|
||||||
'ipsum.txt',
|
|
||||||
'DATA'),
|
|
||||||
('base_library.zip',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\base_library.zip',
|
|
||||||
'DATA')],
|
|
||||||
[],
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
1751897901,
|
|
||||||
[('run.exe',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
|
||||||
'EXECUTABLE')],
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll')
|
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
('F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\scanVars.pkg',
|
|
||||||
{'BINARY': True,
|
|
||||||
'DATA': True,
|
|
||||||
'EXECUTABLE': True,
|
|
||||||
'EXTENSION': True,
|
|
||||||
'PYMODULE': True,
|
|
||||||
'PYSOURCE': True,
|
|
||||||
'PYZ': False,
|
|
||||||
'SPLASH': True,
|
|
||||||
'SYMLINK': False},
|
|
||||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
|
||||||
('PYZ-00.pyz',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\PYZ-00.pyz',
|
|
||||||
'PYZ'),
|
|
||||||
('struct',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\struct.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod01_archive',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod01_archive.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod02_importers',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod02_importers.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod03_ctypes',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod03_ctypes.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyimod04_pywin32',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\localpycs\\pyimod04_pywin32.pyc',
|
|
||||||
'PYMODULE'),
|
|
||||||
('pyiboot01_bootstrap',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_inspect',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_setuptools',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_setuptools.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_pkgutil',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('pyi_rth_multiprocessing',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('scanVars',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\scanVars.py',
|
|
||||||
'PYSOURCE'),
|
|
||||||
('libclang.dll',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\libclang.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('python313.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('select.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_multiprocessing.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_multiprocessing.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('pyexpat.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\pyexpat.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_ssl.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ssl.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_hashlib.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('unicodedata.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_decimal.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_socket.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_lzma.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_bz2.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_ctypes.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ctypes.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_queue.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_overlapped.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_asyncio.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_asyncio.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_wmi.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_wmi.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('_elementtree.pyd',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_elementtree.pyd',
|
|
||||||
'EXTENSION'),
|
|
||||||
('api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-math-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-conio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-environment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-stdio-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-time-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-process-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-runtime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-convert-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('VCRUNTIME140.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-locale-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-crt-utility-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libssl-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libcrypto-3.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libffi-8.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('VCRUNTIME140_1.dll',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('ucrtbase.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\ucrtbase.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l2-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-1.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-profile-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-handle-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-heap-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-memory-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-interlocked-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-string-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-debug-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-timezone-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-datetime-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processthreads-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-console-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-synch-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-file-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-localization-l1-2-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'F:\\Work\\Programs\\Active-HDL-13-x64\\bin\\api-ms-win-core-util-l1-1-0.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\WHEEL',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\WHEEL',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\INSTALLER',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\INSTALLER',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\RECORD',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\RECORD',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\top_level.txt',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\top_level.txt',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\LICENSE',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\LICENSE',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\REQUESTED',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\REQUESTED',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\METADATA',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\importlib_metadata-8.0.0.dist-info\\METADATA',
|
|
||||||
'DATA'),
|
|
||||||
('setuptools\\_vendor\\jaraco\\text\\Lorem ipsum.txt',
|
|
||||||
'C:\\Users\\I\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\setuptools\\_vendor\\jaraco\\text\\Lorem '
|
|
||||||
'ipsum.txt',
|
|
||||||
'DATA'),
|
|
||||||
('base_library.zip',
|
|
||||||
'F:\\Work\\Projects\\TMS\\TMS_new_bus\\Src\\DebugTools\\build\\scanVars\\base_library.zip',
|
|
||||||
'DATA')],
|
|
||||||
'python313.dll',
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
False,
|
|
||||||
[],
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None)
|
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,54 +0,0 @@
|
|||||||
|
|
||||||
This file lists modules PyInstaller was not able to find. This does not
|
|
||||||
necessarily mean this module is required for running your program. Python and
|
|
||||||
Python 3rd-party packages include a lot of conditional or optional modules. For
|
|
||||||
example the module 'ntpath' only exists on Windows, whereas the module
|
|
||||||
'posixpath' only exists on Posix systems.
|
|
||||||
|
|
||||||
Types if import:
|
|
||||||
* top-level: imported at the top-level - look at these first
|
|
||||||
* conditional: imported within an if-statement
|
|
||||||
* delayed: imported within a function
|
|
||||||
* optional: imported within a try-except-statement
|
|
||||||
|
|
||||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
|
||||||
tracking down the missing module yourself. Thanks!
|
|
||||||
|
|
||||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), setuptools._distutils.util (delayed, conditional, optional), netrc (delayed, conditional), getpass (delayed, optional), setuptools._vendor.backports.tarfile (optional), setuptools._distutils.archive_util (optional), http.server (delayed, optional)
|
|
||||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), setuptools._vendor.backports.tarfile (optional), setuptools._distutils.archive_util (optional)
|
|
||||||
missing module named 'collections.abc' - imported by traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level), tracemalloc (top-level), setuptools (top-level), setuptools._distutils.filelist (top-level), setuptools._distutils.util (top-level), setuptools._vendor.jaraco.functools (top-level), setuptools._vendor.more_itertools.more (top-level), setuptools._vendor.more_itertools.recipes (top-level), setuptools._distutils._modified (top-level), setuptools._distutils.compat (top-level), setuptools._distutils.spawn (top-level), setuptools._distutils.compilers.C.base (top-level), setuptools._distutils.fancy_getopt (top-level), setuptools._reqs (top-level), http.client (top-level), setuptools.discovery (top-level), setuptools.dist (top-level), setuptools._distutils.command.bdist (top-level), setuptools._distutils.core (top-level), setuptools._distutils.cmd (top-level), setuptools._distutils.dist (top-level), configparser (top-level), setuptools._distutils.extension (top-level), setuptools.config.setupcfg (top-level), setuptools.config.expand (top-level), setuptools.config.pyprojecttoml (top-level), setuptools.config._apply_pyprojecttoml (top-level), tomllib._parser (top-level), setuptools._vendor.tomli._parser (top-level), setuptools.command.egg_info (top-level), setuptools._distutils.command.build (top-level), setuptools._distutils.command.sdist (top-level), setuptools.glob (top-level), setuptools.command._requirestxt (top-level), setuptools.command.bdist_wheel (top-level), setuptools._vendor.wheel.cli.convert (top-level), setuptools._vendor.wheel.cli.tags (top-level), setuptools._vendor.typing_extensions (top-level), xml.etree.ElementTree (top-level), setuptools._distutils.command.build_ext (top-level), _pyrepl.types (top-level), _pyrepl.readline (top-level), asyncio.base_events (top-level), asyncio.coroutines (top-level), setuptools._distutils.compilers.C.msvc (top-level)
|
|
||||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
|
||||||
missing module named fcntl - imported by subprocess (optional), _pyrepl.unix_console (top-level)
|
|
||||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
|
||||||
missing module named _scproxy - imported by urllib.request (conditional)
|
|
||||||
missing module named termios - imported by getpass (optional), tty (top-level), _pyrepl.pager (delayed, optional), _pyrepl.unix_console (top-level), _pyrepl.fancy_termios (top-level), _pyrepl.unix_eventqueue (top-level)
|
|
||||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
|
||||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
|
||||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
|
||||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
|
||||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), _pyrepl.unix_console (delayed, optional)
|
|
||||||
missing module named resource - imported by posix (top-level)
|
|
||||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
|
||||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
|
||||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
|
||||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
|
||||||
missing module named pyimod02_importers - imported by C:\Users\I\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
|
||||||
missing module named typing_extensions.Buffer - imported by setuptools._vendor.typing_extensions (top-level), setuptools._vendor.wheel.wheelfile (conditional)
|
|
||||||
missing module named typing_extensions.Literal - imported by setuptools._vendor.typing_extensions (top-level), setuptools.config._validate_pyproject.formats (conditional)
|
|
||||||
missing module named typing_extensions.Self - imported by setuptools._vendor.typing_extensions (top-level), setuptools.config.expand (conditional), setuptools.config.pyprojecttoml (conditional), setuptools.config._validate_pyproject.error_reporting (conditional)
|
|
||||||
missing module named typing_extensions.deprecated - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.sysconfig (conditional), setuptools._distutils.command.bdist (conditional)
|
|
||||||
missing module named typing_extensions.TypeAlias - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.compilers.C.base (conditional), setuptools._reqs (conditional), setuptools.warnings (conditional), setuptools._path (conditional), setuptools._distutils.dist (conditional), setuptools.config.setupcfg (conditional), setuptools.config._apply_pyprojecttoml (conditional), setuptools.dist (conditional), setuptools.command.bdist_egg (conditional), setuptools.compat.py311 (conditional)
|
|
||||||
missing module named typing_extensions.Unpack - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.util (conditional), setuptools._distutils.compilers.C.base (conditional), setuptools._distutils.cmd (conditional)
|
|
||||||
missing module named typing_extensions.TypeVarTuple - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.util (conditional), setuptools._distutils.compilers.C.base (conditional), setuptools._distutils.cmd (conditional)
|
|
||||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
|
||||||
missing module named vms_lib - imported by platform (delayed, optional)
|
|
||||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
|
||||||
missing module named java - imported by platform (delayed)
|
|
||||||
missing module named usercustomize - imported by site (delayed, optional)
|
|
||||||
missing module named sitecustomize - imported by site (delayed, optional)
|
|
||||||
missing module named _curses - imported by curses (top-level), curses.has_key (top-level), _pyrepl.curses (optional)
|
|
||||||
missing module named readline - imported by site (delayed, optional), rlcompleter (optional), code (delayed, conditional, optional)
|
|
||||||
missing module named _typeshed - imported by setuptools._distutils.dist (conditional), setuptools.glob (conditional), setuptools.compat.py311 (conditional)
|
|
||||||
missing module named _manylinux - imported by packaging._manylinux (delayed, optional), setuptools._vendor.packaging._manylinux (delayed, optional), setuptools._vendor.wheel.vendored.packaging._manylinux (delayed, optional)
|
|
||||||
missing module named importlib_resources - imported by setuptools._vendor.jaraco.text (optional)
|
|
||||||
missing module named trove_classifiers - imported by setuptools.config._validate_pyproject.formats (optional)
|
|
||||||
File diff suppressed because it is too large
Load Diff
498
debug_tools.c
498
debug_tools.c
@@ -1,274 +1,293 @@
|
|||||||
#include "debug_tools.h"
|
#include "debug_tools.h"
|
||||||
#include "IQmathLib.h"
|
|
||||||
|
|
||||||
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var);
|
#if !defined(GLOBAL_Q)
|
||||||
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var, DebugVarIQType_t iq_type_final);
|
#define GLOBAL_Q 16
|
||||||
|
#endif
|
||||||
|
|
||||||
DebugVarIQType_t dbg_type = t_iq24;
|
|
||||||
|
|
||||||
long Debug_ReadVar(DebugVar_t *var, DebugVarIQType_t iq_type_final)
|
DebugLowLevel_t debug_ll = DEBUG_LOWLEVEL_INIT; ///< Ñòðóêòóðà îòëàäêè íèæíåãî óðîâíÿ (èíèöèàëèçàöèÿ)
|
||||||
|
|
||||||
|
static int getDebugVar(DebugVar_t *var, int32_t *int_var, float *float_var);
|
||||||
|
static int convertDebugVarToIQx(DebugVar_t *var, int32_t *ret_var);
|
||||||
|
|
||||||
|
///////////////////////////----EXAPLE-----//////////////////////////////
|
||||||
|
int var_numb = 1; ///< Ïðèìåð ïåðåìåííîé äëÿ îòëàäêè
|
||||||
|
DebugVarName_t var_name; ///< Èìÿ ïåðåìåííîé
|
||||||
|
int32_t return_var; ///< Ïåðåìåííàÿ äëÿ âîçâðàòà ðåçóëüòàòà
|
||||||
|
int32_t return_ll_var; ///< Âîçâðàùàåìîå çíà÷åíèå ñ íèæíåãî óðîâíÿ
|
||||||
|
int result; ///< Ïåðåìåííàÿ ðåçóëüòàòà
|
||||||
|
DateTime_t ext_date = {2025, 11, 07, 16, 50}; ///< Ïðèìåð âíåøíåé äàòû ñáîðêè
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ïðèìåð èñïîëüçîâàíèÿ ôóíêöèé îòëàäêè.
|
||||||
|
* @details Äåìîíñòðàöèîííàÿ ôóíêöèÿ äëÿ ðàáîòû ñ ïåðåìåííûìè îòëàäêè.
|
||||||
|
*/
|
||||||
|
void Debug_Test_Example(void)
|
||||||
{
|
{
|
||||||
long tmp_var;
|
result = Debug_ReadVar(var_numb, &return_var);
|
||||||
if((var->ptr_type == pt_struct) || (var->ptr_type == pt_union) || (var->ptr_type == pt_unknown))
|
result = Debug_ReadVarName(var_numb, var_name);
|
||||||
return;
|
|
||||||
|
|
||||||
convertDebugVarToIQx(var, &tmp_var, dbg_type);
|
|
||||||
|
|
||||||
return tmp_var;
|
if(Debug_LowLevel_Initialize(&ext_date) == 0)
|
||||||
|
result = Debug_LowLevel_ReadVar(&return_ll_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int convertDebugVarToIQx(DebugVar_t *var, long *ret_var, DebugVarIQType_t iq_type_final)
|
///////////////////////////----PUBLIC-----//////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ×èòàåò ïåðåìåííóþ ïî èíäåêñó.
|
||||||
|
* @param var_ind – èíäåêñ ïåðåìåííîé.
|
||||||
|
* @param return_32b – óêàçàòåëü äëÿ âîçâðàòà ðåçóëüòàòà.
|
||||||
|
* @return int – 0: óñïåõ, 1: îøèáêà.
|
||||||
|
* @details Èñïîëüçóåòñÿ äëÿ ÷òåíèÿ çíà÷åíèé ïåðåìåííûõ ïî èõ èíäåêñó.
|
||||||
|
*/
|
||||||
|
int Debug_ReadVar(int var_ind, int32_t *return_32b)
|
||||||
{
|
{
|
||||||
long iq_numb, iq_united, iq_final;
|
if(return_32b == NULL)
|
||||||
float float_numb;
|
return 1;
|
||||||
|
int32_t tmp_var;
|
||||||
|
|
||||||
if(getDebugVar(var, &iq_numb, &float_numb) == 1)
|
if (var_ind >= DebugVar_Qnt)
|
||||||
return 1;
|
return 1;
|
||||||
|
if((dbg_vars[var_ind].ptr_type == pt_struct) || (dbg_vars[var_ind].ptr_type == pt_union) ||
|
||||||
|
(dbg_vars[var_ind].ptr_type == pt_unknown))
|
||||||
|
return 1;
|
||||||
|
|
||||||
// ïðèâåäåíèå ê îäíîìó IQ
|
return convertDebugVarToIQx(&dbg_vars[var_ind], return_32b);
|
||||||
switch(var->iq_type)
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ×èòàåò èìÿ ïåðåìåííîé ïî èíäåêñó.
|
||||||
|
* @param var_ind – èíäåêñ ïåðåìåííîé.
|
||||||
|
* @param name_ptr – óêàçàòåëü íà áóôåð èìåíè (DebugVarName_t).
|
||||||
|
* @return int – 0: óñïåõ, 1: îøèáêà.
|
||||||
|
* @details Êîïèðóåò èìÿ ïåðåìåííîé â ïðåäîñòàâëåííûé áóôåð.
|
||||||
|
*/
|
||||||
|
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr)
|
||||||
|
{
|
||||||
|
if(name_ptr == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (var_ind >= DebugVar_Qnt)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
// Êîïèðîâàíèå ñ çàùèòîé îò ïåðåïîëíåíèÿ è ÿâíîé îñòàíîâêîé ïî '\0'
|
||||||
|
for (i = 0; i < sizeof(dbg_vars[var_ind].name); i++)
|
||||||
{
|
{
|
||||||
case t_iq_none:
|
name_ptr[i] = dbg_vars[var_ind].name[i];
|
||||||
if(var->ptr_type == pt_float)
|
if (dbg_vars[var_ind].name[i] == '\0')
|
||||||
{
|
|
||||||
iq_united = _IQ(float_numb);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iq_united = _IQ(iq_numb);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case t_iq1:
|
|
||||||
iq_united = _IQ1toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq2:
|
|
||||||
iq_united = _IQ2toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq3:
|
|
||||||
iq_united = _IQ3toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq4:
|
|
||||||
iq_united = _IQ4toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq5:
|
|
||||||
iq_united = _IQ5toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq6:
|
|
||||||
iq_united = _IQ6toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq7:
|
|
||||||
iq_united = _IQ7toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq8:
|
|
||||||
iq_united = _IQ8toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq9:
|
|
||||||
iq_united = _IQ9toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq10:
|
|
||||||
iq_united = _IQ10toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq11:
|
|
||||||
iq_united = _IQ11toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq12:
|
|
||||||
iq_united = _IQ12toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq13:
|
|
||||||
iq_united = _IQ13toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq14:
|
|
||||||
iq_united = _IQ14toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq15:
|
|
||||||
iq_united = _IQ15toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq16:
|
|
||||||
iq_united = _IQ16toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq17:
|
|
||||||
iq_united = _IQ17toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq18:
|
|
||||||
iq_united = _IQ18toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq19:
|
|
||||||
iq_united = _IQ19toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq20:
|
|
||||||
iq_united = _IQ20toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq21:
|
|
||||||
iq_united = _IQ21toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq22:
|
|
||||||
iq_united = _IQ22toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq23:
|
|
||||||
iq_united = _IQ23toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq24:
|
|
||||||
iq_united = _IQ24toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq25:
|
|
||||||
iq_united = _IQ25toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq26:
|
|
||||||
iq_united = _IQ26toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq27:
|
|
||||||
iq_united = _IQ27toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq28:
|
|
||||||
iq_united = _IQ28toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq29:
|
|
||||||
iq_united = _IQ29toIQ(iq_numb);
|
|
||||||
break;
|
|
||||||
case t_iq30:
|
|
||||||
iq_united = _IQ30toIQ(iq_numb);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Ãàðàíòèðîâàííîå çàâåðøåíèå ñòðîêè (íà ñëó÷àé, åñëè â var->name íå áûëî '\0')
|
||||||
|
name_ptr[sizeof(dbg_vars[var_ind].name) - 1] = '\0';
|
||||||
|
|
||||||
// ïðèâåäåíèå îáùåãî IQ ê çàïðàøèâàåìîìó
|
|
||||||
switch(iq_type_final)
|
|
||||||
{
|
|
||||||
case t_iq_none:
|
|
||||||
iq_final = (int)_IQtoF(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq1:
|
|
||||||
iq_final = _IQtoIQ1(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq2:
|
|
||||||
iq_final = _IQtoIQ2(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq3:
|
|
||||||
iq_final = _IQtoIQ3(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq4:
|
|
||||||
iq_final = _IQtoIQ4(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq5:
|
|
||||||
iq_final = _IQtoIQ5(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq6:
|
|
||||||
iq_final = _IQtoIQ6(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq7:
|
|
||||||
iq_final = _IQtoIQ7(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq8:
|
|
||||||
iq_final = _IQtoIQ8(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq9:
|
|
||||||
iq_final = _IQtoIQ9(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq10:
|
|
||||||
iq_final = _IQtoIQ10(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq11:
|
|
||||||
iq_final = _IQtoIQ11(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq12:
|
|
||||||
iq_final = _IQtoIQ12(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq13:
|
|
||||||
iq_final = _IQtoIQ13(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq14:
|
|
||||||
iq_final = _IQtoIQ14(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq15:
|
|
||||||
iq_final = _IQtoIQ15(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq16:
|
|
||||||
iq_final = _IQtoIQ16(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq17:
|
|
||||||
iq_final = _IQtoIQ17(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq18:
|
|
||||||
iq_final = _IQtoIQ18(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq19:
|
|
||||||
iq_final = _IQtoIQ19(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq20:
|
|
||||||
iq_final = _IQtoIQ20(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq21:
|
|
||||||
iq_final = _IQtoIQ21(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq22:
|
|
||||||
iq_final = _IQtoIQ22(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq23:
|
|
||||||
iq_final = _IQtoIQ23(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq24:
|
|
||||||
iq_final = _IQtoIQ24(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq25:
|
|
||||||
iq_final = _IQtoIQ25(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq26:
|
|
||||||
iq_final = _IQtoIQ26(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq27:
|
|
||||||
iq_final = _IQtoIQ27(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq28:
|
|
||||||
iq_final = _IQtoIQ28(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq29:
|
|
||||||
iq_final = _IQtoIQ29(iq_united);
|
|
||||||
break;
|
|
||||||
case t_iq30:
|
|
||||||
iq_final = _IQtoIQ30(iq_united);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ret_var = iq_final;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
|
* @brief ×èòàåò çíà÷åíèå ïåðåìåííîé îòëàäêè ñ íèæíåãî óðîâíÿ.
|
||||||
|
* @param return_32b – óêàçàòåëü íà ïåðåìåííóþ, êóäà çàïèñûâàåòñÿ ðåçóëüòàò.
|
||||||
|
* @return int – 0: óñïåõ, 1: îøèáêà, 2: íåäîïóñòèìûé àäðåñ.
|
||||||
|
* @details Èñïîëüçóåò àäðåññ, ïåðåäàâàåìûé ñ òåðìèíàëêè äëÿ ïîëó÷åíèÿ çíà÷åíèÿ.
|
||||||
|
*/
|
||||||
|
int Debug_LowLevel_ReadVar(int32_t *return_32b)
|
||||||
{
|
{
|
||||||
if (!var || !int_var || !float_var)
|
if (return_32b == NULL)
|
||||||
|
return 1;
|
||||||
|
if (debug_ll.isVerified == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
uint8_t *addr = debug_ll.dbg_var.Ptr;
|
||||||
|
uint32_t addr_val = (uint32_t)addr;
|
||||||
|
|
||||||
|
// Ðàçðåø¸ííûå äèàïàçîíû ïàìÿòè (èç .cmd ôàéëà)
|
||||||
|
if (!(
|
||||||
|
(addr_val <= 0x0007FF) || // RAMM0 + RAMM1
|
||||||
|
(addr_val >= 0x008120 && addr_val <= 0x009FFC) || // L0 + L1 SARAM
|
||||||
|
(addr_val >= 0x3F8000 && addr_val <= 0x3F9FFF) || // PRAMH0 + DRAMH0
|
||||||
|
(addr_val >= 0x3FF000 && addr_val <= 0x3FFFFF) || // BOOTROM + RESET
|
||||||
|
(addr_val >= 0x080002 && addr_val <= 0x09FFFF) || // RAMEX1
|
||||||
|
(addr_val >= 0x0F0000 && addr_val <= 0x0FFEFF) || // RAMEX4
|
||||||
|
(addr_val >= 0x100002 && addr_val <= 0x103FFF) || // RAMEX0 + RAMEX2 + RAMEX01
|
||||||
|
(addr_val >= 0x102000 && addr_val <= 0x103FFF) // RAMEX2
|
||||||
|
)) {
|
||||||
|
return 2; // Çàïðåù¸ííûé àäðåñ — íåëüçÿ ÷èòàòü
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertDebugVarToIQx(&debug_ll.dbg_var, return_32b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Èíèöèàëèçàöèÿ îòëàäêè íà íèæíåì óðîâíå ïî äàòå ñáîðêè.
|
||||||
|
* @param external_date – ñòðóêòóðà ñ äàòîé DateTime_t
|
||||||
|
* @return int – 0: ñîâïàäàåò, 1: íå ñîâïàäàåò, -1: îøèáêà.
|
||||||
|
* @details Ñðàâíèâàåò äàòó êîìïèëÿöèè ñ çàïðàøèâàåìîé è èíèöèàëèçèðóåò îòëàäî÷íóþ ïåðåìåííóþ.
|
||||||
|
*/
|
||||||
|
int Debug_LowLevel_Initialize(DateTime_t* external_date)
|
||||||
|
{
|
||||||
|
if (external_date == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ñðàâíåíèå âñåõ ïîëåé
|
||||||
|
if (external_date->year == debug_ll.build_date.year &&
|
||||||
|
external_date->month == debug_ll.build_date.month &&
|
||||||
|
external_date->day == debug_ll.build_date.day &&
|
||||||
|
external_date->hour == debug_ll.build_date.hour &&
|
||||||
|
external_date->minute == debug_ll.build_date.minute)
|
||||||
|
{
|
||||||
|
debug_ll.isVerified = 1;
|
||||||
|
return 0; // Ñîâïàëî
|
||||||
|
}
|
||||||
|
debug_ll.isVerified = 0;
|
||||||
|
|
||||||
|
return 1; // Íå ñîâïàëî
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////----INTERNAL FUNCTIONS-----////////////////////////
|
||||||
|
/**
|
||||||
|
* @brief Ïðåîáðàçóåò òèï IQ ïåðåìåííîé â ÷èñëî áèòîâ äëÿ ñäâèãà(Q-ôàêòîð).
|
||||||
|
* @param t – òèï IQ (ïåðå÷èñëåíèå DebugVarIQType_t).
|
||||||
|
* @return int – Q-ôàêòîð (íàïðèìåð, 24), 0: åñëè t_iq_none, -1: îøèáêà.
|
||||||
|
* @details Ñîïîñòàâëÿåò òèï IQ ïåðåìåííîé ñ ñîîòâåòñòâóþùèì Q-çíà÷åíèåì.
|
||||||
|
*/
|
||||||
|
static int iqTypeToQ(DebugVarIQType_t t)
|
||||||
|
{
|
||||||
|
if (t == t_iq_none)
|
||||||
|
return 0; // áåç IQ, float, int
|
||||||
|
else if (t == t_iq)
|
||||||
|
return GLOBAL_Q; // îáùèé IQ, íàïðèìåð 24
|
||||||
|
else if (t >= t_iq1 && t <= t_iq30)
|
||||||
|
return (int)t - (int)t_iq1 + 1; // íàïðèìåð t_iq1 -> 1, t_iq2 -> 2 è ò.ä.
|
||||||
|
else
|
||||||
|
return -1; // îøèáêà
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ïðåîáðàçóåò ïåðåìåííóþ îòëàäêè â IQ ôîðìàò.
|
||||||
|
* @param var – óêàçàòåëü íà ïåðåìåííóþ îòëàäêè.
|
||||||
|
* @param ret_var – óêàçàòåëü äëÿ âîçâðàòà çíà÷åíèÿ â ôîðìàòå 32 áèòà.
|
||||||
|
* @return int – 0: óñïåõ, 1: îøèáêà ÷òåíèÿ, 2: íåïðàâèëüíûé ôîðìàò, 3: ïåðåïîëíåíèå.
|
||||||
|
* @details Îïðåäåëÿåò ôîðìàò IQ ïåðåìåííîé, êîíâåðòèðóåò å¸ â 32b ñ ó÷¸òîì ìàñøòàáà.
|
||||||
|
*/
|
||||||
|
static int convertDebugVarToIQx(DebugVar_t *var, int32_t *ret_var)
|
||||||
|
{
|
||||||
|
int32_t iq_numb, iq_united, iq_final;
|
||||||
|
float float_numb;
|
||||||
|
|
||||||
|
if(getDebugVar(var, &iq_numb, &float_numb) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int src_q = iqTypeToQ(var->iq_type);
|
||||||
|
int dst_q = iqTypeToQ(var->return_type);
|
||||||
|
|
||||||
|
if (src_q < 0 || dst_q < 0)
|
||||||
|
return 2; // íåïðàâèëüíûé ôîðìàò
|
||||||
|
|
||||||
|
int64_t iq_united64 = 0;
|
||||||
|
int64_t iq_final64 = 0;
|
||||||
|
|
||||||
|
// Êîíâåðòàöèÿ ê GLOBAL_Q (64-áèò)
|
||||||
|
if (var->iq_type == t_iq_none) {
|
||||||
|
if (var->ptr_type == pt_float) {
|
||||||
|
// float_numb óìíîæàåì íà 2^GLOBAL_Q
|
||||||
|
// Ðåçóëüòàò ïðèâîäèì ê 64 áèòà
|
||||||
|
iq_united64 = (int64_t)(float_numb * (1 << GLOBAL_Q));
|
||||||
|
} else {
|
||||||
|
iq_united64 = ((int64_t)iq_numb) << GLOBAL_Q;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int shift = GLOBAL_Q - src_q;
|
||||||
|
if (shift >= 0)
|
||||||
|
iq_united64 = ((int64_t)iq_numb) << shift;
|
||||||
|
else
|
||||||
|
iq_united64 = ((int64_t)iq_numb) >> (-shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Êîíâåðòàöèÿ èç GLOBAL_Q â öåëåâîé IQ (64-áèò)
|
||||||
|
if (var->return_type == t_iq_none) {
|
||||||
|
// Âîçâðàùàåì öåëîå, îòáðîñèâ äðîáíóþ ÷àñòü
|
||||||
|
*ret_var = (uint32_t)(iq_united64 >> GLOBAL_Q);
|
||||||
|
} else {
|
||||||
|
int shift = dst_q - GLOBAL_Q;
|
||||||
|
if (shift >= 0)
|
||||||
|
iq_final64 = iq_united64 << shift;
|
||||||
|
else
|
||||||
|
iq_final64 = iq_united64 >> (-shift);
|
||||||
|
|
||||||
|
// Ïðîâåðÿåì ïåðåïîëíåíèå int32_t
|
||||||
|
if (iq_final64 > 2147483647 || iq_final64 < -2147483648)
|
||||||
|
return 3; // ïåðåïîëíåíèå
|
||||||
|
|
||||||
|
*ret_var = (uint32_t)iq_final64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ïðî÷èòàòü çíà÷åíèå ïåðåìåííîé îòëàäêè.
|
||||||
|
* @param var – óêàçàòåëü íà ñòðóêòóðó DebugVar.
|
||||||
|
* @param int_var – óêàçàòåëü íà ïåðåìåííóþ òèïà 32 áèòà äëÿ âîçâðàòà öåëî÷èñëåííîãî çíà÷åíèÿ.
|
||||||
|
* @param float_var – óêàçàòåëü íà ïåðåìåííóþ òèïà float äëÿ âîçâðàòà çíà÷åíèÿ ñ ïëàâàþùåé òî÷êîé.
|
||||||
|
* @return int – 0: óñïåõ, 1: îøèáêà óêàçàòåëåé èëè íåïîääåðæèâàåìûé òèï, 3/4: îøèáêà âûðàâíèâàíèÿ.
|
||||||
|
* @details  çàâèñèìîñòè îò òèïà ïåðåìåííîé ñ÷èòûâàåò å¸ çíà÷åíèå è ñîõðàíÿåò â ñîîòâåòñòâóþùåì óêàçàòåëå.
|
||||||
|
*/
|
||||||
|
static int getDebugVar(DebugVar_t *var, int32_t *int_var, float *float_var)
|
||||||
|
{
|
||||||
|
if (!var || !int_var || !float_var || !var->Ptr)
|
||||||
return 1; // îøèáêà: null óêàçàòåëü
|
return 1; // îøèáêà: null óêàçàòåëü
|
||||||
|
|
||||||
|
uint8_t *addr = var->Ptr;
|
||||||
|
uint32_t addr_val = (uint32_t)addr;
|
||||||
|
|
||||||
switch (var->ptr_type)
|
switch (var->ptr_type)
|
||||||
{
|
{
|
||||||
case pt_int8: // signed char
|
case pt_int8: // 8 áèò
|
||||||
*int_var = *((signed char *)var->Ptr);
|
if ((addr_val & ALIGN_8BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
|
||||||
|
return 1; // îøèáêà âûðàâíèâàíèÿ
|
||||||
|
*int_var = *((volatile int8_t *)addr);
|
||||||
|
case pt_uint8:
|
||||||
|
if ((addr_val & ALIGN_8BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
|
||||||
|
return 1; // îøèáêà âûðàâíèâàíèÿ
|
||||||
|
*int_var = *((volatile uint8_t *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pt_int16: // int
|
case pt_int16: // 16 áèò (int)
|
||||||
*int_var = *((int *)var->Ptr);
|
if ((addr_val & ALIGN_16BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
|
||||||
|
return 2; // îøèáêà âûðàâíèâàíèÿ
|
||||||
|
*int_var = *((volatile int16_t *)addr);
|
||||||
|
case pt_uint16:
|
||||||
|
if ((addr_val & ALIGN_16BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
|
||||||
|
return 2; // îøèáêà âûðàâíèâàíèÿ
|
||||||
|
*int_var = *((volatile uint16_t *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pt_int32: // long
|
case pt_int32: // 32 áèò
|
||||||
*int_var = *((long *)var->Ptr);
|
if ((addr_val & ALIGN_32BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
|
||||||
|
return 3; // îøèáêà âûðàâíèâàíèÿ
|
||||||
|
*int_var = *((volatile int32_t *)addr);
|
||||||
|
case pt_uint32:
|
||||||
|
if ((addr_val & ALIGN_32BIT) != 0) // ïðîâåðÿåì âûðàâíèâàíèå
|
||||||
|
return 3; // îøèáêà âûðàâíèâàíèÿ
|
||||||
|
*int_var = *((volatile uint32_t *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pt_uint8: // unsigned char
|
case pt_float: // float (4 áàéòà)
|
||||||
*int_var = *((unsigned char *)var->Ptr);
|
if ((addr_val & ALIGN_FLOAT) != 0) // ïðîâåðêà âûðàâíèâàíèÿ
|
||||||
break;
|
return 4; // îøèáêà âûðàâíèâàíèÿ
|
||||||
|
*float_var = *((volatile float *)addr);
|
||||||
case pt_uint16: // unsigned int
|
|
||||||
*int_var = *((unsigned int *)var->Ptr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case pt_uint32: // unsigned long
|
|
||||||
*int_var = *((unsigned long *)var->Ptr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case pt_float: // float
|
|
||||||
*float_var = *((float *)var->Ptr);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1; // íåïîääåðæèâàåìûé òèï
|
||||||
// äëÿ óêàçàòåëåé è ìàññèâîâ íå ïîääåðæèâàåòñÿ ÷òåíèå
|
// äëÿ óêàçàòåëåé è ìàññèâîâ íå ïîääåðæèâàåòñÿ ÷òåíèå
|
||||||
// case pt_ptr_int8:
|
// case pt_ptr_int8:
|
||||||
// case pt_ptr_int16:
|
// case pt_ptr_int16:
|
||||||
@@ -282,9 +301,8 @@ static int getDebugVar(DebugVar_t *var, long *int_var, float *float_var)
|
|||||||
// case pt_arr_uint8:
|
// case pt_arr_uint8:
|
||||||
// case pt_arr_uint16:
|
// case pt_arr_uint16:
|
||||||
// case pt_arr_uint32:
|
// case pt_arr_uint32:
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; // óñïåõ
|
return 0; // óñïåõ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
109
debug_tools.h
109
debug_tools.h
@@ -1,18 +1,52 @@
|
|||||||
#ifndef DEBUG_TOOLS
|
#ifndef DEBUG_TOOLS
|
||||||
#define DEBUG_TOOLS
|
#define DEBUG_TOOLS
|
||||||
#include "IQmathLib.h"
|
#include <stdint.h>
|
||||||
#include "DSP281x_Device.h"
|
#include <limits.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if UINT8_MAX // Åñëè åñòü òèï 8 áèò - çí÷à÷èò àäðåñàöèÿ ïî 8 áèò
|
||||||
|
|
||||||
|
#define ALIGN_8BIT 0x0 ///< Âûðàâíèâàíèå áåç îãðàíè÷åíèé (ëþáîé àäðåñ)
|
||||||
|
#define ALIGN_16BIT 0x1 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 2 (addr & 0x1 == 0)
|
||||||
|
#define ALIGN_32BIT 0x3 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 4 (addr & 0x3 == 0)
|
||||||
|
#define ALIGN_64BIT 0x7 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 8 (addr & 0x7 == 0)
|
||||||
|
#define ALIGN_FLOAT ALIGN_32BIT
|
||||||
|
|
||||||
|
#else // Åñëè íåò òèïà 8 áèò - çíà÷èò àäðåñàöèÿ ïî 16 áèò
|
||||||
|
|
||||||
|
#define ALIGN_8BIT 0x0 ///< Âûðàâíèâàíèå áåç îãðàíè÷åíèé (ëþáîé àäðåñ)
|
||||||
|
#define ALIGN_16BIT 0x0 ///< Âûðàâíèâàíèå áåç îãðàíè÷åíèé (ëþáîé àäðåñ)
|
||||||
|
#define ALIGN_32BIT 0x1 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 4 (addr & 0x1 == 0)
|
||||||
|
#define ALIGN_64BIT 0x3 ///< Âûðàâíèâàíèå: àäðåñ äîëæåí áûòü êðàòåí 8 (addr & 0x3 == 0)
|
||||||
|
#define ALIGN_FLOAT ALIGN_32BIT
|
||||||
|
|
||||||
|
#endif //STM32/TMS32
|
||||||
|
|
||||||
|
#if !UINT8_MAX
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef signed char int8_t;
|
||||||
|
#endif
|
||||||
|
#if !defined(NULL)
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Òèï äàííûõ, íà êîòîðûé óêàçûâàåò óêàçàòåëü ïåðåìåííîé îòëàäêè.
|
||||||
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
pt_unknown, // unknown
|
pt_unknown, // unknown
|
||||||
pt_int8, // signed char
|
pt_int8, // signed char
|
||||||
pt_int16, // int
|
pt_int16, // int
|
||||||
pt_int32, // long
|
pt_int32, // long
|
||||||
|
pt_int64, // long
|
||||||
pt_uint8, // unsigned char
|
pt_uint8, // unsigned char
|
||||||
pt_uint16, // unsigned int
|
pt_uint16, // unsigned int
|
||||||
pt_uint32, // unsigned long
|
pt_uint32, // unsigned long
|
||||||
pt_float, // float
|
pt_uint64, // unsigned long
|
||||||
|
pt_float, // floatf
|
||||||
pt_struct, // struct
|
pt_struct, // struct
|
||||||
pt_union, // struct
|
pt_union, // struct
|
||||||
// pt_ptr_int8, // signed char*
|
// pt_ptr_int8, // signed char*
|
||||||
@@ -29,6 +63,9 @@ typedef enum
|
|||||||
// pt_arr_uint32, // unsigned long[]
|
// pt_arr_uint32, // unsigned long[]
|
||||||
}DebugVarPtrType_t;
|
}DebugVarPtrType_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Òèïû IQ-ïðåäñòàâëåíèÿ ïåðåìåííîé îòëàäêè.
|
||||||
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
t_iq_none,
|
t_iq_none,
|
||||||
@@ -65,17 +102,67 @@ typedef enum
|
|||||||
t_iq30
|
t_iq30
|
||||||
}DebugVarIQType_t;
|
}DebugVarIQType_t;
|
||||||
|
|
||||||
|
typedef char DebugVarName_t[11]; ///< Èìÿ ïåðåìåííîé îòëàäêè (äî 10 ñèìâîëîâ + \0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Îïèñàíèå ïåðåìåííîé îòëàäêè.
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char* Ptr;
|
uint8_t* Ptr; ///< Óêàçàòåëü íà çíà÷åíèå ïåðåìåííîé
|
||||||
DebugVarPtrType_t ptr_type;
|
DebugVarPtrType_t ptr_type; ///< Òèï çíà÷åíèÿ
|
||||||
DebugVarIQType_t iq_type;
|
DebugVarIQType_t iq_type; ///< Òèï IQ ïåðåìåííîé (åñëè åñòü)
|
||||||
char name[10];
|
DebugVarIQType_t return_type;///< Òèï IQ âîçâðàùàåìîãî çíà÷åíèÿ
|
||||||
}DebugVar_t;
|
DebugVarName_t name; ///< Èìÿ ïåðåìåííîé
|
||||||
|
} DebugVar_t;
|
||||||
|
|
||||||
|
typedef long DebugValue_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ñòðóêòóðà äàòû è âðåìåíè.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t year; ///< Ãîä (íàïðèìåð, 2025)
|
||||||
|
uint8_t month; ///< Ìåñÿö (1-12)
|
||||||
|
uint8_t day; ///< Äåíü (1-31)
|
||||||
|
uint8_t hour; ///< ×àñû (0-23)
|
||||||
|
uint8_t minute; ///< Ìèíóòû (0-59)
|
||||||
|
} DateTime_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ñòðóêòóðà íèæíåãî óðîâíÿ îòëàäêè.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DateTime_t build_date; ///< Äàòà ñáîðêè
|
||||||
|
unsigned int isVerified; ///< Ôëàã èíèöèàëèçàöèè íèçêîóðîâíåíîé îòëàäêè (0 — íåò, 1 — óñïåøíî)
|
||||||
|
DebugVar_t dbg_var; ///< Ïåðåìåííàÿ äëÿ îòëàäêè
|
||||||
|
}DebugLowLevel_t;
|
||||||
|
extern DebugLowLevel_t debug_ll; ///< Ãëîáàëüíûé ýêçåìïëÿð îòëàäêè íèæíåãî óðîâíÿ
|
||||||
|
|
||||||
|
|
||||||
extern int DebugVar_Qnt;
|
/** @brief Ìàêðîñ èíèöèàëèçàöèè äàòû */
|
||||||
extern DebugVar_t dbg_vars[];
|
#define DATE_INIT {BUILD_YEAR, BUILD_MONTH, BUILD_DATA, BUILD_HOURS, BUILD_MINUTES}
|
||||||
long Debug_ReadVar(DebugVar_t *var, DebugVarIQType_t iq_type_final);
|
/** @brief Ìàêðîñ èíèöèàëèçàöèè ïåðåìåííîé îòëàäêè */
|
||||||
|
#define DEBUG_VAR_INIT {0, pt_uint16, t_iq_none, t_iq_none, "\0"}
|
||||||
|
/** @brief Ìàêðîñ èíèöèàëèçàöèè íèæíåãî óðîâíÿ îòëàäêè */
|
||||||
|
#define DEBUG_LOWLEVEL_INIT {DATE_INIT, 0, DEBUG_VAR_INIT}
|
||||||
|
|
||||||
|
|
||||||
|
extern int DebugVar_Qnt; ///< Êîëè÷åñòâî ïåðåìåííûõ îòëàäêè
|
||||||
|
extern DebugVar_t dbg_vars[]; ///< Ìàññèâ ïåðåìåííûõ îòëàäêè
|
||||||
|
|
||||||
|
|
||||||
|
/* Ïðèìåð èñïîëüçîâàíèÿ îòëàäêè */
|
||||||
|
void Debug_Test_Example(void);
|
||||||
|
|
||||||
|
/* ×èòàåò çíà÷åíèå ïåðåìåííîé ïî èíäåêñó */
|
||||||
|
int Debug_ReadVar(int var_ind, int32_t *return_long);
|
||||||
|
/* ×èòàåò èìÿ ïåðåìåííîé ïî èíäåêñó */
|
||||||
|
int Debug_ReadVarName(int var_ind, DebugVarName_t name_ptr);
|
||||||
|
/* ×èòàåò çíà÷åíèå ïåðåìåííîé ñ íèæíåãî óðîâíÿ */
|
||||||
|
int Debug_LowLevel_ReadVar(int32_t *return_long);
|
||||||
|
/* Èíèöèàëèçèðóåò îòëàäêó íèæíåãî óðîâíÿ */
|
||||||
|
int Debug_LowLevel_Initialize(DateTime_t *external_date);
|
||||||
|
|
||||||
#endif //DEBUG_TOOLS
|
#endif //DEBUG_TOOLS
|
||||||
|
|||||||
321
debug_vars.c
321
debug_vars.c
@@ -1,321 +0,0 @@
|
|||||||
// Ýòîò ôàéë ñãåíåðèðîâàí àâòîìàòè÷åñêè
|
|
||||||
#include "debug_tools.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Èíêëþäû äëÿ äîñòóïà ê ïåðåìåííûì
|
|
||||||
#include "vector.h"
|
|
||||||
#include "RS_Functions_modbus.h"
|
|
||||||
#include "adc_tools.h"
|
|
||||||
#include "errors.h"
|
|
||||||
#include "v_pwm24.h"
|
|
||||||
#include "f281xpwm.h"
|
|
||||||
#include "xp_project.h"
|
|
||||||
#include "rotation_speed.h"
|
|
||||||
#include "teta_calc.h"
|
|
||||||
#include "dq_to_alphabeta_cos.h"
|
|
||||||
#include "xp_write_xpwm_time.h"
|
|
||||||
#include "log_can.h"
|
|
||||||
#include "pwm_vector_regul.h"
|
|
||||||
#include "RS_Functions.h"
|
|
||||||
#include "detect_phase_break2.h"
|
|
||||||
#include "svgen_dq.h"
|
|
||||||
#include "x_parallel_bus.h"
|
|
||||||
#include "Spartan2E_Functions.h"
|
|
||||||
#include "x_serial_bus.h"
|
|
||||||
#include "xp_controller.h"
|
|
||||||
#include "xp_rotation_sensor.h"
|
|
||||||
#include "xPeriphSP6_loader.h"
|
|
||||||
#include "log_to_memory.h"
|
|
||||||
#include "global_time.h"
|
|
||||||
#include "CAN_Setup.h"
|
|
||||||
#include "log_params.h"
|
|
||||||
#include "CRC_Functions.h"
|
|
||||||
#include "pid_reg3.h"
|
|
||||||
#include "IQmathLib.h"
|
|
||||||
#include "doors_control.h"
|
|
||||||
#include "isolation.h"
|
|
||||||
#include "main22220.h"
|
|
||||||
#include "optical_bus.h"
|
|
||||||
#include "alarm_log_can.h"
|
|
||||||
#include "bender.h"
|
|
||||||
#include "can_watercool.h"
|
|
||||||
#include "detect_phase_break.h"
|
|
||||||
#include "modbus_read_table.h"
|
|
||||||
#include "rmp_cntl_my1.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Ýêñòåðíû äëÿ äîñòóïà ê ïåðåìåííûì
|
|
||||||
extern int ADC0finishAddr;
|
|
||||||
extern int ADC0startAddr;
|
|
||||||
extern int ADC1finishAddr;
|
|
||||||
extern int ADC1startAddr;
|
|
||||||
extern int ADC2finishAddr;
|
|
||||||
extern int ADC2startAddr;
|
|
||||||
extern int ADC_f[2][16];
|
|
||||||
extern int ADC_sf[2][16];
|
|
||||||
extern int ADDR_FOR_ALL;
|
|
||||||
extern int BUSY;
|
|
||||||
extern BENDER Bender[2];
|
|
||||||
extern int CAN_answer_wait[32];
|
|
||||||
extern int CAN_count_cycle_input_units[8];
|
|
||||||
extern int CAN_no_answer[32];
|
|
||||||
extern int CAN_refresh_cicle[32];
|
|
||||||
extern int CAN_request_sent[32];
|
|
||||||
extern int CAN_timeout[32];
|
|
||||||
extern int CAN_timeout_cicle[32];
|
|
||||||
extern int CNTRL_ADDR;
|
|
||||||
extern const int CNTRL_ADDR_UNIVERSAL;
|
|
||||||
extern _iq CONST_15;
|
|
||||||
extern _iq CONST_23;
|
|
||||||
extern int CanOpenUnites[30];
|
|
||||||
extern int CanTimeOutErrorTR;
|
|
||||||
extern XControll_reg Controll;
|
|
||||||
extern int Dpwm;
|
|
||||||
extern int Dpwm2;
|
|
||||||
extern int Dpwm4;
|
|
||||||
extern int EvaTimer1InterruptCount;
|
|
||||||
extern int EvaTimer2InterruptCount;
|
|
||||||
extern int EvbTimer3InterruptCount;
|
|
||||||
extern int EvbTimer4InterruptCount;
|
|
||||||
extern int Fpwm;
|
|
||||||
extern int IN0finishAddr;
|
|
||||||
extern int IN0startAddr;
|
|
||||||
extern int IN1finishAddr;
|
|
||||||
extern int IN1startAddr;
|
|
||||||
extern int IN2finishAddr;
|
|
||||||
extern int IN2startAddr;
|
|
||||||
extern float IQ_OUT_NOM;
|
|
||||||
extern long I_OUT_1_6_NOMINAL_IQ;
|
|
||||||
extern long I_OUT_1_8_NOMINAL_IQ;
|
|
||||||
extern float I_OUT_NOMINAL;
|
|
||||||
extern long I_OUT_NOMINAL_IQ;
|
|
||||||
extern long I_ZPT_NOMINAL_IQ;
|
|
||||||
extern _iq Id_out_max_full;
|
|
||||||
extern _iq Id_out_max_low_speed;
|
|
||||||
extern _iq Iq_out_max;
|
|
||||||
extern _iq Iq_out_nom;
|
|
||||||
extern const unsigned long K_LEM_ADC[20];
|
|
||||||
extern float KmodTerm;
|
|
||||||
extern int ROTfinishAddr;
|
|
||||||
extern unsigned int RS_Len[70];
|
|
||||||
extern const unsigned int R_ADC[20];
|
|
||||||
extern int RotPlaneStartAddr;
|
|
||||||
extern _iq SQRT_32;
|
|
||||||
extern int Unites[8][128];
|
|
||||||
extern int VAR_FREQ_PWM_XTICS;
|
|
||||||
extern int VAR_PERIOD_MAX_XTICS;
|
|
||||||
extern int VAR_PERIOD_MIN_BR_XTICS;
|
|
||||||
extern int VAR_PERIOD_MIN_XTICS;
|
|
||||||
extern int Zpwm;
|
|
||||||
extern WINDING a;
|
|
||||||
extern volatile AddrToSent addrToSent;
|
|
||||||
extern unsigned int adr_read_from_modbus3;
|
|
||||||
extern ALARM_LOG_CAN alarm_log_can;
|
|
||||||
extern ALARM_LOG_CAN_SETUP alarm_log_can_setup;
|
|
||||||
extern ANALOG_VALUE analog;
|
|
||||||
extern int ar_sa_all[3][6][4][7];
|
|
||||||
extern _iq ar_tph[7];
|
|
||||||
extern int block_size_counter_fast;
|
|
||||||
extern int block_size_counter_slow;
|
|
||||||
extern _iq break_result_1;
|
|
||||||
extern _iq break_result_2;
|
|
||||||
extern _iq break_result_3;
|
|
||||||
extern _iq break_result_4;
|
|
||||||
extern Byte byte;
|
|
||||||
extern long c_s;
|
|
||||||
extern int calibration1;
|
|
||||||
extern int calibration2;
|
|
||||||
extern test_functions callfunc;
|
|
||||||
extern CANOPEN_CAN_SETUP canopen_can_setup;
|
|
||||||
extern unsigned int capnum0;
|
|
||||||
extern unsigned int capnum1;
|
|
||||||
extern unsigned int capnum2;
|
|
||||||
extern unsigned int capnum3;
|
|
||||||
extern unsigned int chNum;
|
|
||||||
extern BREAK_PHASE_I chanell1;
|
|
||||||
extern BREAK_PHASE_I chanell2;
|
|
||||||
extern int cmd_3_or_16;
|
|
||||||
extern int compress_size;
|
|
||||||
extern ControlReg controlReg;
|
|
||||||
extern COS_FI_STRUCT cos_fi;
|
|
||||||
extern unsigned int count_error_sync;
|
|
||||||
extern int count_modbus_table_changed;
|
|
||||||
extern int count_run_pch;
|
|
||||||
extern WORD crc_16_tab[256];
|
|
||||||
extern char crypt[34];
|
|
||||||
extern int cur_position_buf_modbus16_can;
|
|
||||||
extern CYCLE cycle[32];
|
|
||||||
extern int delta_capnum;
|
|
||||||
extern int delta_error;
|
|
||||||
extern volatile DOORS_STATUS doors;
|
|
||||||
extern int enable_can;
|
|
||||||
extern int enable_can_recive_after_units_box;
|
|
||||||
extern _iq err_level_adc;
|
|
||||||
extern _iq err_level_adc_on_go;
|
|
||||||
extern unsigned int err_main;
|
|
||||||
extern int err_modbus16;
|
|
||||||
extern int err_modbus3;
|
|
||||||
extern ERRORS errors;
|
|
||||||
extern FLAG f;
|
|
||||||
extern volatile int fail;
|
|
||||||
extern FAULTS faults;
|
|
||||||
extern FIFO fifo;
|
|
||||||
extern ANALOG_VALUE filter;
|
|
||||||
extern int flag_buf;
|
|
||||||
extern int flag_enable_can_from_mpu;
|
|
||||||
extern int flag_enable_can_from_terminal;
|
|
||||||
extern int flag_on_off_pch;
|
|
||||||
extern unsigned int flag_received_first_mess_from_MPU;
|
|
||||||
extern unsigned int flag_reverse;
|
|
||||||
extern unsigned int flag_send_answer_rs;
|
|
||||||
extern int flag_test_tabe_filled;
|
|
||||||
extern int flag_we_int_pwm_on;
|
|
||||||
extern _iq freq1;
|
|
||||||
extern float freqTerm;
|
|
||||||
extern GLOBAL_TIME global_time;
|
|
||||||
extern int hb_logs_data;
|
|
||||||
extern int i;
|
|
||||||
extern BREAK2_PHASE i1_out;
|
|
||||||
extern BREAK2_PHASE i2_out;
|
|
||||||
extern int init_log[3];
|
|
||||||
extern _iq19 iq19_k_norm_ADC[20];
|
|
||||||
extern _iq19 iq19_zero_ADC[20];
|
|
||||||
extern _iq iq_alfa_coef;
|
|
||||||
extern _iq iq_k_norm_ADC[20];
|
|
||||||
extern IQ_LOGSPARAMS iq_logpar;
|
|
||||||
extern _iq iq_max;
|
|
||||||
extern _iq iq_norm_ADC[20];
|
|
||||||
extern ISOLATION isolation1;
|
|
||||||
extern ISOLATION isolation2;
|
|
||||||
extern _iq k1;
|
|
||||||
extern float kI_D;
|
|
||||||
extern float kI_D_Inv31;
|
|
||||||
extern float kI_Q;
|
|
||||||
extern float kI_Q_Inv31;
|
|
||||||
extern float kP_D;
|
|
||||||
extern float kP_D_Inv31;
|
|
||||||
extern float kP_Q;
|
|
||||||
extern float kP_Q_Inv31;
|
|
||||||
extern _iq koef_Base_stop_run;
|
|
||||||
extern _iq koef_Iabc_filter;
|
|
||||||
extern _iq koef_Im_filter;
|
|
||||||
extern _iq koef_Im_filter_long;
|
|
||||||
extern _iq koef_K_stop_run;
|
|
||||||
extern _iq koef_Krecup;
|
|
||||||
extern _iq koef_Min_recup;
|
|
||||||
extern _iq koef_TemperBSU_long_filter;
|
|
||||||
extern _iq koef_Ud_fast_filter;
|
|
||||||
extern _iq koef_Ud_long_filter;
|
|
||||||
extern _iq koef_Wlong;
|
|
||||||
extern _iq koef_Wout_filter;
|
|
||||||
extern _iq koef_Wout_filter_long;
|
|
||||||
extern long koeff_Fs_filter;
|
|
||||||
extern long koeff_Idq_filter;
|
|
||||||
extern _iq koeff_Iq_filter;
|
|
||||||
extern long koeff_Iq_filter_slow;
|
|
||||||
extern long koeff_Ud_filter;
|
|
||||||
extern long koeff_Uq_filter;
|
|
||||||
extern volatile unsigned long length;
|
|
||||||
extern _iq level_on_off_break[13][2];
|
|
||||||
extern logcan_TypeDef log_can;
|
|
||||||
extern LOG_CAN_SETUP log_can_setup;
|
|
||||||
extern TYPE_LOG_PARAMS log_params;
|
|
||||||
extern long logbuf_sync1[10];
|
|
||||||
extern LOGSPARAMS logpar;
|
|
||||||
extern int m_PWM;
|
|
||||||
extern MAILBOXS_CAN_SETUP mailboxs_can_setup;
|
|
||||||
extern int manufactorerAndProductID;
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_can_in;
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_can_out;
|
|
||||||
extern MODBUS_REG_STRUCT modbus_table_in[450];
|
|
||||||
extern MODBUS_REG_STRUCT modbus_table_out[450];
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_rs_in;
|
|
||||||
extern MODBUS_REG_STRUCT * modbus_table_rs_out;
|
|
||||||
extern MODBUS_REG_STRUCT modbus_table_test[450];
|
|
||||||
extern MPU_CAN_SETUP mpu_can_setup;
|
|
||||||
extern NEW_CYCLE_FIFO new_cycle_fifo;
|
|
||||||
extern int no_write;
|
|
||||||
extern int no_write_slow;
|
|
||||||
extern int number_modbus_table_changed;
|
|
||||||
extern OPTICAL_BUS_DATA optical_read_data;
|
|
||||||
extern OPTICAL_BUS_DATA optical_write_data;
|
|
||||||
extern MODBUS_REG_STRUCT options_controller[200];
|
|
||||||
extern _iq pidCur_Ki;
|
|
||||||
extern PIDREG3 pidD;
|
|
||||||
extern PIDREG3 pidD2;
|
|
||||||
extern PIDREG3 pidFvect;
|
|
||||||
extern int pidFvectKi_test;
|
|
||||||
extern int pidFvectKp_test;
|
|
||||||
extern PIDREG3 pidPvect;
|
|
||||||
extern PIDREG3 pidQ;
|
|
||||||
extern PIDREG3 pidQ2;
|
|
||||||
extern PIDREG_KOEFFICIENTS pidReg_koeffs;
|
|
||||||
extern PIDREG3 pidTetta;
|
|
||||||
extern POWER_RATIO power_ratio;
|
|
||||||
extern int prev_flag_buf;
|
|
||||||
extern unsigned int prev_status_received;
|
|
||||||
extern T_project project;
|
|
||||||
extern PWMGEND pwmd;
|
|
||||||
extern T_controller_read r_c_sbus;
|
|
||||||
extern T_controller_read r_controller;
|
|
||||||
extern FIFO refo;
|
|
||||||
extern TMS_TO_TERMINAL_STRUCT reply;
|
|
||||||
extern TMS_TO_TERMINAL_TEST_ALL_STRUCT reply_test_all;
|
|
||||||
extern long return_var;
|
|
||||||
extern RMP_MY1 rmp_freq;
|
|
||||||
extern RMP_MY1 rmp_wrot;
|
|
||||||
extern T_rotation_sensor rotation_sensor;
|
|
||||||
extern ROTOR_VALUE rotor;
|
|
||||||
extern RS_DATA_STRUCT rs_a;
|
|
||||||
extern RS_DATA_STRUCT rs_b;
|
|
||||||
extern unsigned int sincronisationFault;
|
|
||||||
extern char size_cmd15;
|
|
||||||
extern char size_cmd16;
|
|
||||||
extern int size_fast_done;
|
|
||||||
extern int size_slow_done;
|
|
||||||
extern int stop_log;
|
|
||||||
extern int stop_log_slow;
|
|
||||||
extern SVGENDQ svgen_dq_1;
|
|
||||||
extern SVGENDQ svgen_dq_2;
|
|
||||||
extern SVGEN_PWM24 svgen_pwm24_1;
|
|
||||||
extern SVGEN_PWM24 svgen_pwm24_2;
|
|
||||||
extern unsigned int temp;
|
|
||||||
extern _iq temperature_limit_koeff;
|
|
||||||
extern INVERTER_TEMPERATURES temperature_warning_BI1;
|
|
||||||
extern INVERTER_TEMPERATURES temperature_warning_BI2;
|
|
||||||
extern RECTIFIER_TEMPERATURES temperature_warning_BV1;
|
|
||||||
extern RECTIFIER_TEMPERATURES temperature_warning_BV2;
|
|
||||||
extern TERMINAL_CAN_SETUP terminal_can_setup;
|
|
||||||
extern TETTA_CALC tetta_calc;
|
|
||||||
extern int timCNT_alg;
|
|
||||||
extern int timCNT_prev;
|
|
||||||
extern unsigned int time;
|
|
||||||
extern float time_alg;
|
|
||||||
extern long time_pause_enable_can_from_mpu;
|
|
||||||
extern long time_pause_enable_can_from_terminal;
|
|
||||||
extern int time_pause_logs;
|
|
||||||
extern int time_pause_titles;
|
|
||||||
extern volatile int tryNumb;
|
|
||||||
extern UNITES_CAN_SETUP unites_can_setup;
|
|
||||||
extern long var_numb;
|
|
||||||
extern VECTOR_CONTROL vect_control;
|
|
||||||
extern WaterCooler water_cooler;
|
|
||||||
extern _iq winding_displacement;
|
|
||||||
extern Word word;
|
|
||||||
extern WordReversed wordReversed;
|
|
||||||
extern WordToReverse wordToReverse;
|
|
||||||
extern X_PARALLEL_BUS x_parallel_bus_project;
|
|
||||||
extern X_SERIAL_BUS x_serial_bus_project;
|
|
||||||
extern unsigned int xeeprom_controll_fast;
|
|
||||||
extern unsigned int xeeprom_controll_store;
|
|
||||||
extern XPWM_TIME xpwm_time;
|
|
||||||
extern _iq zadan_Id_min;
|
|
||||||
extern int zero_ADC[20];
|
|
||||||
|
|
||||||
|
|
||||||
// Îïðåäåëåíèå ìàññèâà ñ óêàçàòåëÿìè íà ïåðåìåííûå äëÿ îòëàäêè
|
|
||||||
int DebugVar_Qnt = 1;
|
|
||||||
#pragma DATA_SECTION(dbg_vars,".dbgvar_info")
|
|
||||||
DebugVar_t dbg_vars[] = {\
|
|
||||||
{(char *)&Bender.KOhms , pt_uint16 , iq_none , "Bender.KOhms" }, \
|
|
||||||
};
|
|
||||||
23
debug_vars_example.c
Normal file
23
debug_vars_example.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "debug_tools.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Инклюды для доступа к переменным
|
||||||
|
#include "bender.h"
|
||||||
|
|
||||||
|
// Экстерны для доступа к переменным
|
||||||
|
extern int ADC0finishAddr;
|
||||||
|
|
||||||
|
|
||||||
|
// Определение массива с указателями на переменные для отладки
|
||||||
|
int DebugVar_Qnt = 5;
|
||||||
|
#pragma DATA_SECTION(dbg_vars,".dbgvar_info")
|
||||||
|
// pointer_type iq_type return_iq_type short_name
|
||||||
|
DebugVar_t dbg_vars[] = {\
|
||||||
|
{(uint8_t *)&freqTerm, pt_float, t_iq_none, t_iq10, "freqT" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][0], pt_int16, t_iq_none, t_iq_none, "ADC_sf00" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][1], pt_int16, t_iq_none, t_iq_none, "ADC_sf01" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][2], pt_int16, t_iq_none, t_iq_none, "ADC_sf02" }, \
|
||||||
|
{(uint8_t *)&ADC_sf[0][3], pt_int16, t_iq_none, t_iq_none, "ADC_sf03" }, \
|
||||||
|
{(uint8_t *)&Bender[0].KOhms, pt_uint16, t_iq, t_iq10, "Bend0.KOhm" }, \
|
||||||
|
{(uint8_t *)&Bender[0].Times, pt_uint16, t_iq_none, t_iq_none, "Bend0.Time" }, \
|
||||||
|
};
|
||||||
20181
structs.xml
20181
structs.xml
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user