chore(radio): remove hardware definitions present in JSON (#6437)
Co-authored-by: philmoz <phil.a.mitchell@gmail.com>
This commit is contained in:
co-authored by
philmoz
parent
2ca8e3e7b6
commit
df981597c6
@@ -44,9 +44,6 @@ get_target_build_options() {
|
||||
tlite)
|
||||
BUILD_OPTIONS+="-DPCB=X7 -DPCBREV=TLITE"
|
||||
;;
|
||||
tlitef4)
|
||||
BUILD_OPTIONS+="-DPCB=X7 -DPCBREV=TLITEF4"
|
||||
;;
|
||||
tpro)
|
||||
BUILD_OPTIONS+="-DPCB=X7 -DPCBREV=TPRO"
|
||||
;;
|
||||
|
||||
@@ -14,11 +14,6 @@ boards = {
|
||||
"PCBREV": "TLITE",
|
||||
"DEFAULT_MODE": "2",
|
||||
},
|
||||
"TLITEF4": {
|
||||
"PCB": "X7",
|
||||
"PCBREV": "TLITEF4",
|
||||
"DEFAULT_MODE": "2",
|
||||
},
|
||||
"TPRO": {
|
||||
"PCB": "X7",
|
||||
"PCBREV": "TPRO",
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Program to remove #define statements from C/C++ files based on a list of names.
|
||||
"""
|
||||
|
||||
import re
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def load_names_to_remove(names_file):
|
||||
"""Load the list of names to remove from the specified file."""
|
||||
try:
|
||||
with open(names_file, 'r', encoding='utf-8') as f:
|
||||
names = [line.strip() for line in f if line.strip()]
|
||||
return set(names) # Use set for faster lookup
|
||||
except FileNotFoundError:
|
||||
print(f"Error: Names file '{names_file}' not found.")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error reading names file: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def remove_defines_from_file(file_path, names_to_remove, dry_run=False):
|
||||
"""Remove #define statements from a file based on the names list."""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
except Exception as e:
|
||||
print(f"Error reading file '{file_path}': {e}")
|
||||
return False
|
||||
|
||||
modified_lines = []
|
||||
removed_count = 0
|
||||
i = 0
|
||||
|
||||
# Pattern to match #define statements
|
||||
# Matches: #define NAME or #define NAME value
|
||||
define_pattern = re.compile(r'^\s*#define\s+(\w+)')
|
||||
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
line_num = i + 1
|
||||
|
||||
match = define_pattern.match(line)
|
||||
if match:
|
||||
define_name = match.group(1)
|
||||
if define_name in names_to_remove:
|
||||
# Found a #define to remove, collect all continuation lines
|
||||
lines_to_remove = []
|
||||
current_line = line
|
||||
current_line_num = line_num
|
||||
|
||||
# Keep collecting lines while they end with backslash
|
||||
while current_line.rstrip().endswith('\\'):
|
||||
lines_to_remove.append((current_line_num, current_line))
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
current_line = lines[i]
|
||||
current_line_num = i + 1
|
||||
else:
|
||||
break
|
||||
|
||||
# Add the final line (without backslash or last line of file)
|
||||
lines_to_remove.append((current_line_num, current_line))
|
||||
|
||||
# Print what we're removing
|
||||
if not dry_run:
|
||||
print(f"Removing multi-line #define from {file_path}:")
|
||||
for ln, l in lines_to_remove:
|
||||
print(f" Line {ln}: {l.rstrip()}")
|
||||
else:
|
||||
print(f"Would remove multi-line #define from {file_path}:")
|
||||
for ln, l in lines_to_remove:
|
||||
print(f" Line {ln}: {l.rstrip()}")
|
||||
|
||||
removed_count += 1
|
||||
i += 1 # Move to next line after the #define block
|
||||
continue
|
||||
|
||||
# Line is not a #define to remove, keep it
|
||||
modified_lines.append(line)
|
||||
i += 1
|
||||
|
||||
# Write back to file if not dry run and changes were made
|
||||
if not dry_run and removed_count > 0:
|
||||
try:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.writelines(modified_lines)
|
||||
print(f"Successfully processed '{file_path}' - removed {removed_count} #define(s)")
|
||||
except Exception as e:
|
||||
print(f"Error writing file '{file_path}': {e}")
|
||||
return False
|
||||
elif dry_run and removed_count > 0:
|
||||
print(f"Would process '{file_path}' - {removed_count} #define(s) to remove")
|
||||
elif removed_count == 0:
|
||||
print(f"No matching #define statements found in '{file_path}'")
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Remove #define statements from C/C++ files based on a list of names"
|
||||
)
|
||||
parser.add_argument(
|
||||
"names_file",
|
||||
help="File containing names to remove (one name per line)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"source_files",
|
||||
nargs="+",
|
||||
help="Source files to process"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Show what would be removed without actually modifying files"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Load names to remove
|
||||
names_to_remove = load_names_to_remove(args.names_file)
|
||||
print(f"Loaded {len(names_to_remove)} names to remove")
|
||||
|
||||
if args.dry_run:
|
||||
print("DRY RUN MODE - No files will be modified")
|
||||
|
||||
# Process each source file
|
||||
success_count = 0
|
||||
for source_file in args.source_files:
|
||||
file_path = Path(source_file)
|
||||
if not file_path.exists():
|
||||
print(f"Warning: File '{source_file}' not found, skipping")
|
||||
continue
|
||||
|
||||
if remove_defines_from_file(file_path, names_to_remove, args.dry_run):
|
||||
success_count += 1
|
||||
|
||||
print(f"\nProcessed {success_count} out of {len(args.source_files)} files successfully")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Program to check if #define names are used anywhere in C++ code files.
|
||||
Use this to verify that defines are safe to remove.
|
||||
"""
|
||||
|
||||
import re
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
|
||||
def load_names_to_check(names_file):
|
||||
"""Load the list of names to check from the specified file."""
|
||||
try:
|
||||
with open(names_file, 'r', encoding='utf-8') as f:
|
||||
names = [line.strip() for line in f if line.strip()]
|
||||
return names
|
||||
except FileNotFoundError:
|
||||
print(f"Error: Names file '{names_file}' not found.")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error reading names file: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def check_usage_in_file(file_path, names_to_check, exclude_defines=True):
|
||||
"""Check if any of the names are used in the given file."""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
content = f.read()
|
||||
except Exception as e:
|
||||
print(f"Error reading file '{file_path}': {e}")
|
||||
return {}
|
||||
|
||||
lines = content.splitlines()
|
||||
usage_found = defaultdict(list)
|
||||
|
||||
# Pattern to match #define statements (to potentially exclude them)
|
||||
define_pattern = re.compile(r'^\s*#define\s+(\w+)')
|
||||
|
||||
# Pre-compile regex patterns for better performance
|
||||
name_patterns = {name: re.compile(r'\b' + re.escape(name) + r'\b') for name in names_to_check}
|
||||
|
||||
for line_num, line in enumerate(lines, 1):
|
||||
# Skip #define lines if exclude_defines is True
|
||||
if exclude_defines and define_pattern.match(line):
|
||||
continue
|
||||
|
||||
# Skip comments (basic comment detection)
|
||||
# Remove single-line comments
|
||||
if '//' in line:
|
||||
line = line.split('//')[0]
|
||||
|
||||
# Skip lines that are mostly comments (basic /* */ detection)
|
||||
if line.strip().startswith('/*') or line.strip().startswith('*'):
|
||||
continue
|
||||
|
||||
# Check each name using pre-compiled patterns
|
||||
for name, pattern in name_patterns.items():
|
||||
if pattern.search(line):
|
||||
usage_found[name].append({
|
||||
'line_num': line_num,
|
||||
'line': line.strip(),
|
||||
'file': str(file_path)
|
||||
})
|
||||
|
||||
return usage_found
|
||||
|
||||
def find_cpp_files(directories, extensions=None):
|
||||
"""Find all C++ files in the given directories."""
|
||||
if extensions is None:
|
||||
extensions = {'.cpp', '.cxx', '.cc', '.c', '.hpp', '.hxx', '.h', '.hh'}
|
||||
|
||||
cpp_files = []
|
||||
for directory in directories:
|
||||
dir_path = Path(directory)
|
||||
if dir_path.is_file():
|
||||
if dir_path.suffix.lower() in extensions:
|
||||
cpp_files.append(dir_path)
|
||||
elif dir_path.is_dir():
|
||||
for ext in extensions:
|
||||
cpp_files.extend(dir_path.rglob(f'*{ext}'))
|
||||
else:
|
||||
print(f"Warning: '{directory}' is not a valid file or directory")
|
||||
|
||||
return cpp_files
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Check if #define names are used anywhere in C++ code"
|
||||
)
|
||||
parser.add_argument(
|
||||
"names_file",
|
||||
help="File containing names to check (one name per line)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"paths",
|
||||
nargs="+",
|
||||
help="Files or directories to search (directories are searched recursively)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--include-defines",
|
||||
action="store_true",
|
||||
help="Include #define statements in the search (default: exclude them)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--extensions",
|
||||
default=".cpp,.cxx,.cc,.c,.hpp,.hxx,.h,.hh",
|
||||
help="Comma-separated list of file extensions to search (default: .cpp,.cxx,.cc,.c,.hpp,.hxx,.h,.hh)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--summary-only",
|
||||
action="store_true",
|
||||
help="Show only summary of used/unused names"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Parse extensions
|
||||
extensions = {ext.strip() for ext in args.extensions.split(',') if ext.strip()}
|
||||
|
||||
# Load names to check
|
||||
names_to_check = load_names_to_check(args.names_file)
|
||||
print(f"Checking usage of {len(names_to_check)} names")
|
||||
|
||||
# Find C++ files
|
||||
cpp_files = find_cpp_files(args.paths, extensions)
|
||||
print(f"Found {len(cpp_files)} C++ files to search")
|
||||
|
||||
if not cpp_files:
|
||||
print("No C++ files found to search!")
|
||||
sys.exit(1)
|
||||
|
||||
# Check usage in all files
|
||||
all_usage = defaultdict(list)
|
||||
files_processed = 0
|
||||
|
||||
for cpp_file in cpp_files:
|
||||
usage = check_usage_in_file(cpp_file, names_to_check, exclude_defines=not args.include_defines)
|
||||
files_processed += 1
|
||||
|
||||
for name, occurrences in usage.items():
|
||||
all_usage[name].extend(occurrences)
|
||||
|
||||
# Progress indicator for large codebases
|
||||
if files_processed % 100 == 0:
|
||||
print(f"Processed {files_processed} files...")
|
||||
|
||||
# Analyze results
|
||||
used_names = set()
|
||||
unused_names = set()
|
||||
|
||||
for name in names_to_check:
|
||||
if name in all_usage:
|
||||
used_names.add(name)
|
||||
else:
|
||||
unused_names.add(name)
|
||||
|
||||
# Display results
|
||||
print(f"\n{'='*60}")
|
||||
print("USAGE ANALYSIS RESULTS")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if used_names:
|
||||
print(f"\n❌ USED NAMES ({len(used_names)}) - DO NOT REMOVE:")
|
||||
for name in sorted(used_names):
|
||||
print(f" • {name}")
|
||||
if not args.summary_only:
|
||||
print(f" Used in {len(set(occ['file'] for occ in all_usage[name]))} file(s):")
|
||||
for occurrence in all_usage[name][:5]: # Show first 5 occurrences
|
||||
print(f" {occurrence['file']}:{occurrence['line_num']}: {occurrence['line']}")
|
||||
if len(all_usage[name]) > 5:
|
||||
print(f" ... and {len(all_usage[name]) - 5} more occurrences")
|
||||
print()
|
||||
|
||||
if unused_names:
|
||||
print(f"\n✅ UNUSED NAMES ({len(unused_names)}) - SAFE TO REMOVE:")
|
||||
for name in sorted(unused_names):
|
||||
print(f" • {name}")
|
||||
|
||||
# Summary
|
||||
print(f"\n{'='*60}")
|
||||
print("SUMMARY:")
|
||||
print(f" Total names checked: {len(names_to_check)}")
|
||||
print(f" Names in use: {len(used_names)}")
|
||||
print(f" Names unused: {len(unused_names)}")
|
||||
print(f" Files searched: {files_processed}")
|
||||
|
||||
if used_names:
|
||||
print(f"\n⚠️ WARNING: {len(used_names)} names are still in use!")
|
||||
print(" Review the usage before removing these #define statements.")
|
||||
else:
|
||||
print(f"\n✅ All {len(names_to_check)} names appear to be unused and safe to remove.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
: "${SRCDIR:=$(dirname "$(pwd)/$0")/..}"
|
||||
|
||||
: ${FLAVOR:="nv14;el18;pl18;pl18ev;nb4p;st16;t12;t12max;t15;t15pro;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;tx16smk3;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v14;v12;tx15"}
|
||||
: ${FLAVOR:="nv14;el18;pl18;pl18ev;pl18u;nb4p;st16;pa01;t12;t12max;t15;t15pro;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;tx16smk3;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v16;v14;v12;tx15"}
|
||||
: ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"}
|
||||
|
||||
# wipe build directory clean
|
||||
@@ -17,8 +17,6 @@ rm -rf build && mkdir -p build && cd build
|
||||
|
||||
target_names=$(echo "$FLAVOR" | tr '[:upper:]' '[:lower:]' | tr ';' '\n')
|
||||
|
||||
TARGET_DIR="${SRCDIR}/radio/src/targets/hw_defs"
|
||||
|
||||
for target_name in $target_names
|
||||
do
|
||||
BUILD_OPTIONS=${COMMON_OPTIONS}
|
||||
@@ -35,8 +33,5 @@ do
|
||||
cmake --build . --target arm-none-eabi-configure
|
||||
cmake --build arm-none-eabi --target hardware_defs
|
||||
|
||||
mkdir -p ${TARGET_DIR}
|
||||
mv arm-none-eabi/radio/src/*.json* ${TARGET_DIR}
|
||||
|
||||
rm -f CMakeCache.txt arm-none-eabi/CMakeCache.txt
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user