backend-infra-engineer: Release v0.3.3 snapshot
This commit is contained in:
140
scripts/check-duplicate-symbols.sh
Executable file
140
scripts/check-duplicate-symbols.sh
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/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}
|
||||
Reference in New Issue
Block a user