Files
klubhaus-doorbell/libraries/FastLED/scripts/all_source_build.py.disabled
2026-02-12 00:45:31 -08:00

247 lines
8.1 KiB
Python

#!/usr/bin/env python3
"""
FastLED All Source Build Script
This script implements the unified source build system for FastLED by:
1. Starting with ONE file for testing (allocator.cpp)
2. Copying original .cpp content to .cpp.hpp
3. Replacing .cpp with conditional wrapper code
4. Creating src/fastled_compile.cpp to include .cpp.hpp files
5. Adding FASTLED_ALL_SRC logic to compiler_control.h
CRITICAL: This script processes original .cpp content CORRECTLY:
- Step 1: Copy original .cpp -> .cpp.hpp (preserves source)
- Step 2: Replace .cpp with wrapper (conditional include)
"""
import os
import shutil
import glob
from pathlib import Path
from typing import List, Set
def find_cpp_files(base_dirs: List[str]) -> List[Path]:
"""Find all .cpp files in the specified directories and subdirectories."""
cpp_files = []
for base_dir in base_dirs:
if not os.path.exists(base_dir):
continue
pattern = os.path.join(base_dir, "**", "*.cpp")
cpp_files.extend(Path(f) for f in glob.glob(pattern, recursive=True))
return sorted(cpp_files)
def get_relative_include_path(file_path: Path, from_src: bool = True) -> str:
"""Get the relative include path from src/ directory."""
if from_src:
# Remove 'src/' prefix if present
parts = file_path.parts
if parts[0] == 'src':
return '/'.join(parts[1:])
return str(file_path)
return str(file_path)
def create_cpp_wrapper(original_cpp: Path, hpp_file: Path) -> str:
"""Create the wrapper .cpp file content with conditional includes."""
relative_hpp_path = get_relative_include_path(hpp_file)
content = f'''#include "fl/compiler_control.h"
#if !FASTLED_ALL_SRC
#include "{relative_hpp_path}"
#endif
'''
return content
def update_compiler_control_h(compiler_control_path: Path) -> None:
"""Add FASTLED_ALL_SRC logic to compiler_control.h."""
with open(compiler_control_path, 'r') as f:
content = f.read()
# Check if FASTLED_ALL_SRC is already defined
if 'FASTLED_ALL_SRC' in content:
print(f"FASTLED_ALL_SRC already defined in {compiler_control_path}")
return
# Add FASTLED_ALL_SRC logic at the end
fastled_all_src_logic = '''
// All Source Build Control
// When FASTLED_ALL_SRC is enabled, all source is compiled into a single translation unit
// Debug/testing builds use individual compilation for better error isolation
#ifndef FASTLED_ALL_SRC
#if defined(DEBUG) || defined(FASTLED_TESTING)
#define FASTLED_ALL_SRC 0
#elif !defined(RELEASE) || (RELEASE == 0)
#define FASTLED_ALL_SRC 1
#else
#define FASTLED_ALL_SRC 0
#endif
#endif
'''
updated_content = content + fastled_all_src_logic
with open(compiler_control_path, 'w') as f:
f.write(updated_content)
print(f"Updated {compiler_control_path} with FASTLED_ALL_SRC logic")
def create_fastled_compile_cpp(cpp_hpp_files: List[Path], output_path: Path) -> None:
"""Create src/fastled_compile.cpp with all .cpp.hpp includes."""
includes = []
for hpp_file in sorted(cpp_hpp_files):
relative_path = get_relative_include_path(hpp_file)
includes.append(f'#include "{relative_path}"')
content = f'''// FastLED All Source Build File
// This file includes all .cpp.hpp files for unified compilation
// Generated automatically by scripts/all_source_build.py
#include "fl/compiler_control.h"
#if FASTLED_ALL_SRC
{chr(10).join(includes)}
#endif // FASTLED_ALL_SRC
'''
with open(output_path, 'w') as f:
f.write(content)
print(f"Created {output_path} with {len(includes)} includes")
def process_single_cpp_file(cpp_file: Path, dry_run: bool = False) -> Path:
"""
Process a single .cpp file, converting it to the new format.
CRITICAL LOGIC:
1. Copy original .cpp content to .cpp.hpp (PRESERVES SOURCE)
2. Replace .cpp with wrapper code (CONDITIONAL INCLUDE)
Returns the .cpp.hpp file path.
"""
hpp_file = cpp_file.with_suffix('.cpp.hpp')
print(f"Processing {cpp_file} -> {hpp_file}")
if not dry_run:
# STEP 1: Copy original .cpp content to .cpp.hpp (PRESERVE ORIGINAL SOURCE)
print(f" Step 1: Copying original content {cpp_file} -> {hpp_file}")
shutil.copy2(cpp_file, hpp_file)
# STEP 2: Replace .cpp with wrapper code (CONDITIONAL INCLUDE)
print(f" Step 2: Replacing {cpp_file} with wrapper code")
wrapper_content = create_cpp_wrapper(cpp_file, hpp_file)
with open(cpp_file, 'w') as f:
f.write(wrapper_content)
return hpp_file
def process_cpp_files(cpp_files: List[Path], dry_run: bool = False) -> List[Path]:
"""Process all .cpp files, converting them to the new format."""
processed_hpp_files = []
for cpp_file in cpp_files:
hpp_file = process_single_cpp_file(cpp_file, dry_run)
processed_hpp_files.append(hpp_file)
return processed_hpp_files
def main():
"""Main function to run the all source build transformation."""
import argparse
parser = argparse.ArgumentParser(description='FastLED All Source Build Script')
parser.add_argument('--dry-run', action='store_true',
help='Show what would be done without making changes')
parser.add_argument('--src-dir', default='src',
help='Source directory (default: src)')
parser.add_argument('--single-file', action='store_true',
help='Process only allocator.cpp for testing')
args = parser.parse_args()
# Define target directories
target_dirs = [
os.path.join(args.src_dir, 'fl'),
os.path.join(args.src_dir, 'sensors'),
os.path.join(args.src_dir, 'fx')
]
# Check if directories exist
for dir_path in target_dirs:
if not os.path.exists(dir_path):
print(f"Warning: Directory {dir_path} does not exist")
# Find all .cpp files
all_cpp_files = find_cpp_files(target_dirs)
# If single-file mode, only process allocator.cpp
if args.single_file:
allocator_files = [f for f in all_cpp_files if f.name == 'allocator.cpp']
if not allocator_files:
print("ERROR: allocator.cpp not found!")
return
cpp_files = allocator_files
print(f"SINGLE FILE MODE: Processing only {cpp_files[0]}")
else:
cpp_files = all_cpp_files
print(f"Found {len(cpp_files)} .cpp files:")
for cpp_file in cpp_files:
print(f" {cpp_file}")
if not cpp_files:
print("No .cpp files found!")
return
if args.dry_run:
print("\n--- DRY RUN MODE ---")
print("The following actions would be performed:")
for cpp_file in cpp_files:
hpp_file = cpp_file.with_suffix('.cpp.hpp')
print(f" 1. Copy {cpp_file} -> {hpp_file} (preserve original)")
print(f" 2. Replace {cpp_file} with conditional wrapper")
print(f" 3. Update {args.src_dir}/fl/compiler_control.h")
print(f" 4. Create {args.src_dir}/fastled_compile.cpp")
return
print(f"\nStarting all source build transformation...")
# Process .cpp files
processed_hpp_files = process_cpp_files(cpp_files, dry_run=args.dry_run)
# Update compiler_control.h
compiler_control_path = Path(args.src_dir) / 'fl' / 'compiler_control.h'
if compiler_control_path.exists():
update_compiler_control_h(compiler_control_path)
else:
print(f"Warning: {compiler_control_path} not found")
# Create fastled_compile.cpp
fastled_compile_path = Path(args.src_dir) / 'fastled_compile.cpp'
create_fastled_compile_cpp(processed_hpp_files, fastled_compile_path)
print(f"\nAll source build transformation complete!")
print(f"Processed {len(cpp_files)} .cpp files")
print(f"Created {len(processed_hpp_files)} .cpp.hpp files")
if args.single_file:
print(f"\n*** SINGLE FILE MODE COMPLETE ***")
print(f"Test with: bash test")
print(f"If successful, run again without --single-file for full conversion")
if __name__ == '__main__':
main()