#!/usr/bin/env python3 """ Fix wrong export header includes that were incorrectly changed by fix_export_includes.py This script: 1. Finds all files with wrong export header includes (s_export.h, n_export.h, a_export.h, etc.) 2. Determines the correct export header name based on the CMakeLists.txt target 3. Checks if the file actually uses export macros 4. If no macros: removes the include 5. If macros exist: fixes the include to the correct name """ import os import re import subprocess from pathlib import Path def find_cmake_target(file_path, base_dir): """Find the CMake target that produces this file by searching CMakeLists.txt""" file_dir = Path(file_path).parent cmake_file = file_dir / "CMakeLists.txt" if not cmake_file.exists(): # Search parent directories for parent in file_dir.parents: if parent == base_dir: break cmake_file = parent / "CMakeLists.txt" if cmake_file.exists(): break if not cmake_file.exists(): return None # Read CMakeLists.txt and find NGL_ADD_LIBRARY2 or add_library calls with open(cmake_file, 'r') as f: content = f.read() # Look for NGL_ADD_LIBRARY2 or add_library with the source file file_name = Path(file_path).name lines = content.split('\n') for i, line in enumerate(lines): # Match NGL_ADD_LIBRARY2(target_name ... file_path ...) if 'NGL_ADD_LIBRARY2' in line or 'add_library' in line: # Check if this target includes our file (might be in subsequent lines) block_end = i + 20 # Look ahead up to 20 lines block = '\n'.join(lines[i:min(block_end, len(lines))]) if file_name in block or '*.cpp' in block or '*.h' in block: # Extract target name match = re.search(r'NGL_ADD_LIBRARY2\s*\(\s*(\w+)', line) if match: return match.group(1) match = re.search(r'add_library\s*\(\s*(\w+)', line) if match: return match.group(1) return None def get_export_header_name(target_name): """Convert target name to export header name (lowercase + _export.h)""" if not target_name: return None return target_name.lower() + "_export.h" def file_uses_export_macros(file_path, export_macro_name=None): """Check if file uses any export macros""" with open(file_path, 'r') as f: content = f.read() # Look for common export macro patterns patterns = [ r'\b\w+_EXPORT\b', # XXX_EXPORT r'\b\w+_EXPORTS\b', # XXX_EXPORTS ] for pattern in patterns: if re.search(pattern, content): return True return False def fix_export_include(file_path, correct_export_header): """Fix the export header include in a file""" with open(file_path, 'r') as f: content = f.read() # Remove wrong includes wrong_patterns = [ r'#include\s+"s_export\.h"', r'#include\s+"n_export\.h"', r'#include\s+"a_export\.h"', r'#include\s+"z_export\.h"', ] for pattern in wrong_patterns: content = re.sub(pattern, '', content) # Add correct include after pragma once or first include if correct_export_header: # Find position after pragma once or at beginning if '#pragma once' in content: content = re.sub( r'(#pragma once\s*\n)', f'\\1#include "{correct_export_header}"\n', content, count=1 ) else: # Add at the beginning after any comments match = re.match(r'(/\*.*?\*/\s*\n)?(#.*\n)*', content, re.DOTALL) if match: insert_pos = match.end() content = content[:insert_pos] + f'#include "{correct_export_header}"\n' + content[insert_pos:] with open(file_path, 'w') as f: f.write(content) def main(): base_dir = Path("/home/torsten/swy/sandbox/qt-migration-legatus/qt6-after/qt6-migrated-legatus") os.chdir(base_dir) # Find all files with wrong export header includes wrong_includes = ['s_export.h', 'n_export.h', 'a_export.h', 'z_export.h'] files_to_fix = [] for wrong_include in wrong_includes: result = subprocess.run( ['grep', '-rl', f'"{wrong_include}"', '.'], capture_output=True, text=True ) for line in result.stdout.strip().split('\n'): if line and 'external/' not in line: files_to_fix.append(Path(line)) print(f"Found {len(files_to_fix)} files with wrong export header includes") fixed_count = 0 removed_count = 0 for file_path in files_to_fix: if not file_path.exists(): continue print(f"\nProcessing: {file_path}") # Try to find the target target = find_cmake_target(file_path, base_dir) print(f" Target: {target}") if target: correct_header = get_export_header_name(target) print(f" Correct header: {correct_header}") # Check if file uses export macros uses_macros = file_uses_export_macros(file_path) print(f" Uses export macros: {uses_macros}") if uses_macros: fix_export_include(file_path, correct_header) print(f" ✓ Fixed to {correct_header}") fixed_count += 1 else: fix_export_include(file_path, None) print(f" ✓ Removed (no macros used)") removed_count += 1 else: # No target found, check if macros are used uses_macros = file_uses_export_macros(file_path) if uses_macros: print(f" ⚠ Cannot determine target, but file uses export macros") else: fix_export_include(file_path, None) print(f" ✓ Removed (no macros used, no target found)") removed_count += 1 print(f"\n=== Summary ===") print(f"Fixed: {fixed_count}") print(f"Removed: {removed_count}") if __name__ == '__main__': main()