find-unused-library-symbols: apply "ruff format" and "ruff check --fix"
This commit is contained in:
@@ -39,10 +39,10 @@ def get_exported_symbols(library_path):
|
||||
['nm', '--dynamic', '--defined-only', '--extern-only', library_path],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error: Failed to run nm on {library_path}: {e}", file=sys.stderr)
|
||||
print(f'Error: Failed to run nm on {library_path}: {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
print("Error: 'nm' command not found. Please install binutils.", file=sys.stderr)
|
||||
@@ -79,10 +79,10 @@ def get_undefined_symbols(executable_path):
|
||||
['nm', '--dynamic', '--undefined-only', executable_path],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Warning: Failed to run nm on {executable_path}: {e}", file=sys.stderr)
|
||||
print(f'Warning: Failed to run nm on {executable_path}: {e}', file=sys.stderr)
|
||||
return set()
|
||||
except FileNotFoundError:
|
||||
print("Error: 'nm' command not found. Please install binutils.", file=sys.stderr)
|
||||
@@ -112,7 +112,7 @@ def verify_executable_links_library(executable_path, library_name):
|
||||
['ldd', executable_path],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
check=True,
|
||||
)
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
# If ldd fails or doesn't exist, we'll skip the verification
|
||||
@@ -137,14 +137,16 @@ def get_library_internal_references(library_path, exported_symbols):
|
||||
['objdump', '-R', library_path],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Warning: Failed to run objdump on {library_path}: {e}", file=sys.stderr)
|
||||
print(f'Warning: Failed to run objdump on {library_path}: {e}', file=sys.stderr)
|
||||
return set()
|
||||
except FileNotFoundError:
|
||||
print("Warning: 'objdump' command not found. Internal references won't be detected.",
|
||||
file=sys.stderr)
|
||||
print(
|
||||
"Warning: 'objdump' command not found. Internal references won't be detected.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return set()
|
||||
|
||||
internal_refs = set()
|
||||
@@ -181,7 +183,7 @@ def find_unused_symbols(library_path, executable_paths, verify_linkage=True):
|
||||
exported_symbols = get_exported_symbols(library_path)
|
||||
|
||||
if not exported_symbols:
|
||||
print(f"Warning: No exported symbols found in {library_path}", file=sys.stderr)
|
||||
print(f'Warning: No exported symbols found in {library_path}', file=sys.stderr)
|
||||
return set(), set(), set()
|
||||
|
||||
# Collect all symbols used by the executables
|
||||
@@ -194,8 +196,7 @@ def find_unused_symbols(library_path, executable_paths, verify_linkage=True):
|
||||
for exe_path in executable_paths:
|
||||
# Optionally verify linkage
|
||||
if verify_linkage and not verify_executable_links_library(exe_path, library_name):
|
||||
print(f"Warning: {exe_path} does not appear to link against {library_name}",
|
||||
file=sys.stderr)
|
||||
print(f'Warning: {exe_path} does not appear to link against {library_name}', file=sys.stderr)
|
||||
|
||||
undefined_symbols = get_undefined_symbols(exe_path)
|
||||
# Only count symbols that are actually exported by our library
|
||||
@@ -209,31 +210,31 @@ def find_unused_symbols(library_path, executable_paths, verify_linkage=True):
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Find unused exported symbols in a shared library'
|
||||
description='Find unused exported symbols in a shared library',
|
||||
)
|
||||
parser.add_argument(
|
||||
'library',
|
||||
help='Path to the shared library to analyze'
|
||||
help='Path to the shared library to analyze',
|
||||
)
|
||||
parser.add_argument(
|
||||
'executables',
|
||||
nargs='+',
|
||||
help='Paths to executables that link against the library'
|
||||
help='Paths to executables that link against the library',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-verify-linkage',
|
||||
action='store_true',
|
||||
help='Skip verification that executables actually link against the library'
|
||||
help='Skip verification that executables actually link against the library',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--show-used',
|
||||
action='store_true',
|
||||
help='Also show used symbols'
|
||||
help='Also show used symbols',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--stats-only',
|
||||
action='store_true',
|
||||
help='Only show statistics, not individual symbols'
|
||||
help='Only show statistics, not individual symbols',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
@@ -241,7 +242,7 @@ def main():
|
||||
# Verify library exists
|
||||
library_path = Path(args.library)
|
||||
if not library_path.exists():
|
||||
print(f"Error: Library not found: {library_path}", file=sys.stderr)
|
||||
print(f'Error: Library not found: {library_path}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Verify executables exist
|
||||
@@ -249,47 +250,45 @@ def main():
|
||||
for exe in args.executables:
|
||||
exe_path = Path(exe)
|
||||
if not exe_path.exists():
|
||||
print(f"Warning: Executable not found: {exe_path}", file=sys.stderr)
|
||||
print(f'Warning: Executable not found: {exe_path}', file=sys.stderr)
|
||||
else:
|
||||
executable_paths.append(str(exe_path))
|
||||
|
||||
if not executable_paths:
|
||||
print("Error: No valid executables provided", file=sys.stderr)
|
||||
print('Error: No valid executables provided', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Analyze symbols
|
||||
unused, exported, used = find_unused_symbols(
|
||||
str(library_path),
|
||||
executable_paths,
|
||||
verify_linkage=not args.no_verify_linkage
|
||||
str(library_path), executable_paths, verify_linkage=not args.no_verify_linkage
|
||||
)
|
||||
|
||||
# Print results
|
||||
print(f"Analysis of {library_path.name}")
|
||||
print("=" * 70)
|
||||
print(f"Total exported symbols: {len(exported)}")
|
||||
print(f" (excluding public API symbols starting with 'sd_')")
|
||||
print(f"Used symbols: {len(used)}")
|
||||
print(f"Unused symbols: {len(unused)}")
|
||||
print(f"Usage rate: {len(used)/len(exported)*100:.1f}%" if exported else "N/A")
|
||||
print(f'Analysis of {library_path.name}')
|
||||
print('=' * 70)
|
||||
print(f'Total exported symbols: {len(exported)}')
|
||||
print(" (excluding public API symbols starting with 'sd_')")
|
||||
print(f'Used symbols: {len(used)}')
|
||||
print(f'Unused symbols: {len(unused)}')
|
||||
print(f'Usage rate: {len(used) / len(exported) * 100:.1f}%' if exported else 'N/A')
|
||||
print()
|
||||
|
||||
if not args.stats_only:
|
||||
if unused:
|
||||
print("Unused symbols:")
|
||||
print("-" * 70)
|
||||
print('Unused symbols:')
|
||||
print('-' * 70)
|
||||
for symbol in sorted(unused):
|
||||
print(f" {symbol}")
|
||||
print(f' {symbol}')
|
||||
print()
|
||||
else:
|
||||
print("All exported symbols are used!")
|
||||
print('All exported symbols are used!')
|
||||
print()
|
||||
|
||||
if args.show_used and used:
|
||||
print("Used symbols:")
|
||||
print("-" * 70)
|
||||
print('Used symbols:')
|
||||
print('-' * 70)
|
||||
for symbol in sorted(used):
|
||||
print(f" {symbol}")
|
||||
print(f' {symbol}')
|
||||
print()
|
||||
|
||||
# Exit with non-zero if there are unused symbols (useful for CI)
|
||||
|
||||
Reference in New Issue
Block a user