- HandlerMinelayerData: BUILD_RTI Guards für RTI-Abhängigkeiten - svcTabCommon: Export-Header-Fix via Fallback-Target - TrainingAreaBase: Stub-Header für BUILD_RTI=OFF - ddsfts: Include-Pfad und Dependency-Fixes - BUILD_RTI=OFF Compilation vollständig unterstützt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Entire-Checkpoint: 01M0JNZA586SACX1PRZ2DJAE5S
235 lines
9.3 KiB
Python
235 lines
9.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Export Header Fixer v3 - Improved version
|
|
|
|
This script fixes incorrect export header includes in migrated Qt6 code.
|
|
It properly maps source files to their CMake targets by analyzing SRCS variables.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
def find_cmake_files(root_dir):
|
|
"""Find all CMakeLists.txt files"""
|
|
cmake_files = []
|
|
for root, dirs, files in os.walk(root_dir):
|
|
if 'CMakeLists.txt' in files:
|
|
cmake_files.append(os.path.join(root, 'CMakeLists.txt'))
|
|
return cmake_files
|
|
|
|
def parse_cmake_file(cmake_file, root_dir=None):
|
|
"""
|
|
Parse CMakeLists.txt and extract target information.
|
|
Returns dict: {source_file: target_name}
|
|
If root_dir is provided, keys are relative paths, otherwise just filenames.
|
|
"""
|
|
target_mapping = {}
|
|
cmake_dir = os.path.dirname(cmake_file)
|
|
|
|
with open(cmake_file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
content = f.read()
|
|
|
|
# Remove comments
|
|
content = re.sub(r'#.*', '', content)
|
|
|
|
# Join lines for multi-line commands
|
|
content = re.sub(r'\\\n', ' ', content)
|
|
|
|
# Find all NGL_ADD_LIBRARY2 calls with their SRCS variables
|
|
# Pattern: SET(<SRCS_VAR> <files...>) followed by NGL_ADD_LIBRARY2(... <TARGET> ...)
|
|
|
|
# First, find all SET commands that define source file lists
|
|
src_vars = {}
|
|
set_pattern = r'SET\s*\(\s*(SRCS\w*)\s+((?:[^)]+))\)'
|
|
for match in re.finditer(set_pattern, content, re.IGNORECASE):
|
|
var_name = match.group(1)
|
|
files_str = match.group(2)
|
|
# Extract file names (remove .cpp, .h extensions for matching)
|
|
files = re.findall(r'([\w_-]+\.(?:cpp|h|cc|cxx))', files_str)
|
|
src_vars[var_name] = files
|
|
|
|
# Find all NGL_ADD_LIBRARY2 and NGL_ADD_LIBRARY calls
|
|
# Pattern 1: NGL_ADD_LIBRARY2([targets...] TARGET_NAME type ${SRCS_VAR})
|
|
lib_pattern = r'NGL_ADD_LIBRARY2?\s*\(([^)]+)\)'
|
|
for match in re.finditer(lib_pattern, content, re.IGNORECASE):
|
|
args = match.group(1).strip()
|
|
|
|
# Split into tokens
|
|
tokens = args.split()
|
|
|
|
# Find SHARED or MODULE to identify library type
|
|
lib_type_idx = -1
|
|
for i, token in enumerate(tokens):
|
|
if token.upper() in ('SHARED', 'MODULE', 'STATIC'):
|
|
lib_type_idx = i
|
|
break
|
|
|
|
if lib_type_idx < 1:
|
|
continue
|
|
|
|
# Target name is right before SHARED/MODULE
|
|
target_name = tokens[lib_type_idx - 1]
|
|
|
|
# Find SRCS variable after SHARED/MODULE
|
|
src_var = None
|
|
for i in range(lib_type_idx + 1, len(tokens)):
|
|
token = tokens[i]
|
|
if token.startswith('${') and token.endswith('}'):
|
|
src_var = token[2:-1] # Remove ${ and }
|
|
break
|
|
elif token.endswith('_SRCS') or token.endswith('_HDRS'):
|
|
src_var = token
|
|
break
|
|
|
|
# Map source files to target
|
|
if src_var and src_var in src_vars:
|
|
for src_file in src_vars[src_var]:
|
|
if root_dir:
|
|
# Store with relative path
|
|
full_path = os.path.join(cmake_dir, src_file)
|
|
rel_path = os.path.relpath(full_path, root_dir)
|
|
target_mapping[rel_path] = target_name
|
|
# Always store filename-only mapping too (will be overwritten by last occurrence)
|
|
target_mapping[src_file] = target_name
|
|
|
|
return target_mapping
|
|
|
|
def find_export_header_includes(file_path):
|
|
"""Find export header includes in a file"""
|
|
includes = []
|
|
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
for line_num, line in enumerate(f, 1):
|
|
# Match both <...> and "..." includes with _export.h
|
|
match = re.search(r'#include\s*[<"]([^>"\s]+_export\.h)[>"]', line)
|
|
if match:
|
|
includes.append((line_num, line.strip(), match.group(1)))
|
|
return includes
|
|
|
|
def get_expected_export_header(target_name):
|
|
"""Get expected export header name for a target"""
|
|
return f"{target_name.lower()}_export.h"
|
|
|
|
def fix_export_header(file_path, old_include, new_include):
|
|
"""Replace old export header include with new one"""
|
|
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
content = f.read()
|
|
|
|
# Replace the include - handle both <...> and "..."
|
|
old_pattern = re.escape(old_include)
|
|
# Match both angle brackets and quotes
|
|
content = re.sub(
|
|
rf'#include\s*[<"]{old_pattern}[>"]',
|
|
f'#include "{new_include}"',
|
|
content
|
|
)
|
|
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage: fix_export_headers_v3.py <directory>")
|
|
sys.exit(1)
|
|
|
|
root_dir = sys.argv[1]
|
|
print(f"Scanning directory: {root_dir}")
|
|
print("=" * 60)
|
|
|
|
# Build target mapping from all CMakeLists.txt files
|
|
cmake_files = find_cmake_files(root_dir)
|
|
print(f"Found {len(cmake_files)} CMakeLists.txt files")
|
|
|
|
target_mapping = {}
|
|
for cmake_file in cmake_files:
|
|
file_mapping = parse_cmake_file(cmake_file, root_dir)
|
|
target_mapping.update(file_mapping)
|
|
|
|
print(f"Mapped {len(target_mapping)} source files to targets")
|
|
print()
|
|
|
|
# Find all header files and check for export header includes
|
|
fixed = 0
|
|
skipped = 0
|
|
errors = 0
|
|
|
|
for root, dirs, files in os.walk(root_dir):
|
|
for file in files:
|
|
if file.endswith(('.h', '.hpp', '.hxx')):
|
|
file_path = os.path.join(root, file)
|
|
rel_path = os.path.relpath(file_path, root_dir)
|
|
|
|
# Get just the filename for mapping
|
|
filename = os.path.basename(file_path)
|
|
|
|
includes = find_export_header_includes(file_path)
|
|
|
|
for line_num, line, old_include in includes:
|
|
# Skip common header files that appear in many targets
|
|
# They should use their own target-specific export header
|
|
if filename in ('logger.h', 'settings.h', 'initialization.h'):
|
|
# These files need special handling - look only in local CMakeLists.txt
|
|
cmake_file = os.path.join(root, 'CMakeLists.txt')
|
|
if os.path.exists(cmake_file):
|
|
dir_mapping = parse_cmake_file(cmake_file, root_dir)
|
|
# Try relative path first
|
|
if rel_path in dir_mapping:
|
|
target_name = dir_mapping[rel_path]
|
|
elif filename in dir_mapping:
|
|
target_name = dir_mapping[filename]
|
|
else:
|
|
# Not found in local CMakeLists.txt - skip
|
|
skipped += 1
|
|
continue
|
|
else:
|
|
# No CMakeLists.txt in directory - skip
|
|
skipped += 1
|
|
continue
|
|
else:
|
|
# For other files, use the standard lookup
|
|
target_name = None
|
|
|
|
# Try exact relative path match first (most precise)
|
|
if rel_path in target_mapping:
|
|
target_name = target_mapping[rel_path]
|
|
# Try filename only (for unique files)
|
|
elif filename in target_mapping:
|
|
target_name = target_mapping[filename]
|
|
# Try to find by parsing local CMakeLists.txt
|
|
else:
|
|
cmake_file = os.path.join(root, 'CMakeLists.txt')
|
|
if os.path.exists(cmake_file):
|
|
dir_mapping = parse_cmake_file(cmake_file, root_dir)
|
|
# Try relative path in local mapping
|
|
if rel_path in dir_mapping:
|
|
target_name = dir_mapping[rel_path]
|
|
# Try filename in local mapping
|
|
elif filename in dir_mapping:
|
|
target_name = dir_mapping[filename]
|
|
|
|
if target_name:
|
|
expected_header = get_expected_export_header(target_name)
|
|
|
|
if old_include != expected_header:
|
|
print(f"FIX: {rel_path}")
|
|
print(f" Old: {old_include}")
|
|
print(f" New: {expected_header}")
|
|
fix_export_header(file_path, old_include, expected_header)
|
|
fixed += 1
|
|
else:
|
|
skipped += 1
|
|
else:
|
|
# File not in mapping - might be in a SRCS list we didn't parse
|
|
# or might be a header-only file
|
|
skipped += 1
|
|
|
|
print()
|
|
print("=" * 60)
|
|
print("Summary:")
|
|
print(f" Fixed: {fixed}")
|
|
print(f" Skipped: {skipped}")
|
|
print(f" Errors: {errors}")
|
|
|
|
if __name__ == '__main__':
|
|
main() |