initial commit
This commit is contained in:
182
libraries/FastLED/ci/util/sccache_config.py
Normal file
182
libraries/FastLED/ci/util/sccache_config.py
Normal file
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SCCACHE Configuration for FastLED Builds
|
||||
|
||||
Provides sccache (distributed compiler cache) support for faster compilation.
|
||||
SCCACHE is faster and more reliable than ccache, especially for CI/CD environments.
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class PlatformIOEnv(Protocol):
|
||||
"""Type hint for PlatformIO environment object."""
|
||||
|
||||
def get(self, key: str) -> str | None:
|
||||
"""Get environment variable value."""
|
||||
...
|
||||
|
||||
def Replace(self, **kwargs: Any) -> None:
|
||||
"""Replace environment variables."""
|
||||
...
|
||||
|
||||
|
||||
def is_sccache_available() -> bool:
|
||||
"""Check if sccache is available in the system."""
|
||||
try:
|
||||
subprocess.run(["sccache", "--version"], capture_output=True, check=True)
|
||||
return True
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
return False
|
||||
|
||||
|
||||
def get_sccache_path() -> str | None:
|
||||
"""Get the full path to sccache executable."""
|
||||
# Use shutil.which for cross-platform executable finding
|
||||
sccache_path = shutil.which("sccache")
|
||||
if sccache_path:
|
||||
return sccache_path
|
||||
|
||||
# Additional Windows-specific paths
|
||||
if platform.system() == "Windows":
|
||||
additional_paths = [
|
||||
"C:\\ProgramData\\chocolatey\\bin\\sccache.exe",
|
||||
os.path.expanduser("~\\scoop\\shims\\sccache.exe"),
|
||||
os.path.expanduser("~\\.cargo\\bin\\sccache.exe"),
|
||||
]
|
||||
for path in additional_paths:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def configure_sccache(env: PlatformIOEnv) -> None:
|
||||
"""Configure SCCACHE for the build environment."""
|
||||
if not is_sccache_available():
|
||||
print("SCCACHE is not available. Skipping SCCACHE configuration.")
|
||||
return
|
||||
|
||||
sccache_path = get_sccache_path()
|
||||
if not sccache_path:
|
||||
print("Could not find SCCACHE executable. Skipping SCCACHE configuration.")
|
||||
return
|
||||
|
||||
print(f"Found SCCACHE at: {sccache_path}")
|
||||
|
||||
# Set up SCCACHE environment variables
|
||||
project_dir = env.get("PROJECT_DIR")
|
||||
if project_dir is None:
|
||||
project_dir = os.getcwd()
|
||||
|
||||
# Use board-specific sccache directory if PIOENV (board environment) is available
|
||||
board_name = env.get("PIOENV")
|
||||
if board_name:
|
||||
sccache_dir = os.path.join(project_dir, ".sccache", board_name)
|
||||
else:
|
||||
sccache_dir = os.path.join(project_dir, ".sccache", "default")
|
||||
|
||||
# Create sccache directory
|
||||
Path(sccache_dir).mkdir(parents=True, exist_ok=True)
|
||||
print(f"Using board-specific SCCACHE directory: {sccache_dir}")
|
||||
|
||||
# Configure SCCACHE environment variables
|
||||
os.environ["SCCACHE_DIR"] = sccache_dir
|
||||
os.environ["SCCACHE_CACHE_SIZE"] = "2G" # Larger cache for better hit rates
|
||||
|
||||
# Optional: Configure distributed caching (Redis/Memcached) if available
|
||||
# This can be enabled by setting environment variables before build:
|
||||
# export SCCACHE_REDIS=redis://localhost:6379
|
||||
# export SCCACHE_MEMCACHED=localhost:11211
|
||||
|
||||
# Configure compression for better storage efficiency
|
||||
if platform.system() != "Windows":
|
||||
# Only set on Unix-like systems where it's more reliable
|
||||
os.environ["SCCACHE_LOG"] = "info"
|
||||
|
||||
# Get current compiler paths
|
||||
original_cc = env.get("CC")
|
||||
original_cxx = env.get("CXX")
|
||||
|
||||
# Note: For PlatformIO, we don't need to manually wrap CC/CXX here
|
||||
# Instead, we'll use build_flags to wrap the compiler commands
|
||||
# This is handled in the Board configuration via extra_scripts
|
||||
|
||||
print(f"SCCACHE configuration completed")
|
||||
print(f"Cache directory: {sccache_dir}")
|
||||
print(f"Cache size limit: 2G")
|
||||
|
||||
# Show SCCACHE stats if available
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[sccache_path, "--show-stats"], capture_output=True, text=True, check=False
|
||||
)
|
||||
if result.returncode == 0:
|
||||
print("SCCACHE Statistics:")
|
||||
print(result.stdout)
|
||||
except Exception:
|
||||
pass # Don't fail build if stats aren't available
|
||||
|
||||
|
||||
def get_sccache_wrapper_script_content() -> str:
|
||||
"""Generate content for sccache wrapper script for PlatformIO extra_scripts."""
|
||||
return '''
|
||||
# SCCACHE wrapper script for PlatformIO builds
|
||||
# This script automatically wraps compiler commands with sccache
|
||||
|
||||
Import("env")
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
def setup_sccache_wrapper():
|
||||
"""Setup sccache wrapper for compiler commands."""
|
||||
|
||||
# Check if sccache is available
|
||||
sccache_path = shutil.which("sccache")
|
||||
if not sccache_path:
|
||||
print("SCCACHE not found, compilation will proceed without caching")
|
||||
return
|
||||
|
||||
print(f"Setting up SCCACHE wrapper: {sccache_path}")
|
||||
|
||||
# Get current build environment
|
||||
project_dir = env.get("PROJECT_DIR", os.getcwd())
|
||||
board_name = env.get("PIOENV", "default")
|
||||
|
||||
# Setup sccache directory
|
||||
sccache_dir = os.path.join(project_dir, ".sccache", board_name)
|
||||
Path(sccache_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Configure sccache environment
|
||||
os.environ["SCCACHE_DIR"] = sccache_dir
|
||||
os.environ["SCCACHE_CACHE_SIZE"] = "2G"
|
||||
|
||||
# Wrap compiler commands
|
||||
current_cc = env.get("CC", "gcc")
|
||||
current_cxx = env.get("CXX", "g++")
|
||||
|
||||
# Only wrap if not already wrapped
|
||||
if "sccache" not in current_cc:
|
||||
env.Replace(
|
||||
CC=f'"{sccache_path}" {current_cc}',
|
||||
CXX=f'"{sccache_path}" {current_cxx}',
|
||||
)
|
||||
print(f"Wrapped CC with SCCACHE: {env.get('CC')}")
|
||||
print(f"Wrapped CXX with SCCACHE: {env.get('CXX')}")
|
||||
|
||||
# Setup sccache wrapper
|
||||
setup_sccache_wrapper()
|
||||
'''
|
||||
|
||||
|
||||
# This script can be executed directly by PlatformIO as an extra_script
|
||||
if __name__ == "__main__":
|
||||
# For direct execution by PlatformIO extra_scripts
|
||||
pass
|
||||
Reference in New Issue
Block a user