141 lines
4.0 KiB
Bash
Executable File
141 lines
4.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# Duplicate Symbol Checker - Analyze symbol database for conflicts
|
|
#
|
|
# Usage: ./scripts/check-duplicate-symbols.sh [SYMBOL_DB] [--verbose] [--fix-suggestions]
|
|
# SYMBOL_DB: Path to symbol database JSON (default: build/symbol_database.json)
|
|
# --verbose: Show all symbols (not just conflicts)
|
|
# --fix-suggestions: Include suggested fixes for conflicts
|
|
|
|
set -euo pipefail
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
# Configuration
|
|
SYMBOL_DB="${1:-.}"
|
|
VERBOSE=false
|
|
FIX_SUGGESTIONS=false
|
|
|
|
# If first arg is a flag, use default database
|
|
if [[ "${SYMBOL_DB}" == --* ]]; then
|
|
SYMBOL_DB="."
|
|
fi
|
|
|
|
# Handle case where SYMBOL_DB is a directory
|
|
if [[ -d "${SYMBOL_DB}" ]]; then
|
|
SYMBOL_DB="${SYMBOL_DB}/symbol_database.json"
|
|
fi
|
|
|
|
# Parse additional arguments
|
|
for arg in "$@"; do
|
|
case "${arg}" in
|
|
--verbose) VERBOSE=true ;;
|
|
--fix-suggestions) FIX_SUGGESTIONS=true ;;
|
|
esac
|
|
done
|
|
|
|
# Validation
|
|
if [[ ! -f "${SYMBOL_DB}" ]]; then
|
|
echo -e "${RED}Error: Symbol database not found: ${SYMBOL_DB}${NC}"
|
|
echo "Generate it first with: ./scripts/extract-symbols.sh"
|
|
exit 1
|
|
fi
|
|
|
|
# Function to show a symbol conflict with details
|
|
show_conflict() {
|
|
local symbol="$1"
|
|
local count="$2"
|
|
local definitions_json="$3"
|
|
|
|
echo -e "\n${RED}SYMBOL CONFLICT DETECTED${NC}"
|
|
echo -e " Symbol: ${CYAN}${symbol}${NC}"
|
|
echo -e " Defined in: ${RED}${count} object files${NC}"
|
|
|
|
# Parse JSON and show each definition
|
|
python3 << PYTHON_EOF
|
|
import json
|
|
import sys
|
|
|
|
definitions = json.loads('''${definitions_json}''')
|
|
|
|
for i, defn in enumerate(definitions, 1):
|
|
obj_file = defn.get('object_file', '?')
|
|
sym_type = defn.get('type', '?')
|
|
print(f" {i}. {obj_file} (type: {sym_type})")
|
|
PYTHON_EOF
|
|
|
|
# Show fix suggestions if requested
|
|
if ${FIX_SUGGESTIONS}; then
|
|
echo -e "\n ${YELLOW}Suggested fixes:${NC}"
|
|
echo " 1. Add 'static' or 'inline' to make the symbol have internal linkage"
|
|
echo " 2. Move definition to a header file with inline/constexpr"
|
|
echo " 3. Use anonymous namespace {} in .cc file"
|
|
echo " 4. Use 'extern' keyword to declare without defining"
|
|
echo " 5. Use ODR-friendly patterns (Meyers' singleton, etc.)"
|
|
fi
|
|
}
|
|
|
|
# Main analysis
|
|
echo -e "${BLUE}=== Duplicate Symbol Checker ===${NC}"
|
|
echo -e "Database: ${SYMBOL_DB}"
|
|
echo ""
|
|
|
|
# Parse JSON and check for conflicts
|
|
python3 << PYTHON_EOF
|
|
import json
|
|
import sys
|
|
|
|
try:
|
|
with open("${SYMBOL_DB}", "r") as f:
|
|
data = json.load(f)
|
|
except Exception as e:
|
|
print(f"${RED}Error reading database: {e}${NC}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
metadata = data.get("metadata", {})
|
|
conflicts = data.get("conflicts", [])
|
|
symbols = data.get("symbols", {})
|
|
|
|
# Display metadata
|
|
print(f"Platform: {metadata.get('platform', '?')}")
|
|
print(f"Build directory: {metadata.get('build_dir', '?')}")
|
|
print(f"Timestamp: {metadata.get('timestamp', '?')}")
|
|
print(f"Object files scanned: {metadata.get('object_files_scanned', 0)}")
|
|
print(f"Total symbols: {metadata.get('total_symbols', 0)}")
|
|
print(f"Total conflicts: {len(conflicts)}")
|
|
print("")
|
|
|
|
# Show conflicts
|
|
if conflicts:
|
|
print(f"${RED}CONFLICTS FOUND:${NC}\n")
|
|
|
|
for i, conflict in enumerate(conflicts, 1):
|
|
symbol = conflict.get("symbol", "?")
|
|
count = conflict.get("count", 0)
|
|
definitions = conflict.get("definitions", [])
|
|
|
|
print(f"${RED}[{i}/{len(conflicts)}]${NC} {symbol} (x{count})")
|
|
for j, defn in enumerate(definitions, 1):
|
|
obj = defn.get("object_file", "?")
|
|
sym_type = defn.get("type", "?")
|
|
print(f" {j}. {obj} (type: {sym_type})")
|
|
print("")
|
|
|
|
print(f"${RED}=== Summary ===${NC}")
|
|
print(f"Total conflicts: ${RED}{len(conflicts)}${NC}")
|
|
print(f"Fix these before linking!${NC}")
|
|
sys.exit(1)
|
|
else:
|
|
print(f"${GREEN}No conflicts found! Symbol table is clean.${NC}")
|
|
sys.exit(0)
|
|
|
|
PYTHON_EOF
|
|
|
|
exit_code=$?
|
|
exit ${exit_code}
|