Spaces:
Running on Zero
Running on Zero
github-actions[bot]
Deploy DoppelGen compiled C-extension binary distribution to Hugging Face Space
95f2541 | #!/usr/bin/env python3 | |
| """ | |
| DoppelGen Hardened Native Compiler Script | |
| Compiles core Python packages into Cython native C-extensions (.so) | |
| with fallback to bytecode (.pyc) for dynamic modules, and strips raw .py source files. | |
| """ | |
| import os | |
| import sys | |
| import shutil | |
| import py_compile | |
| import subprocess | |
| from setuptools import setup, Extension | |
| from Cython.Build import cythonize | |
| def main(): | |
| print("=" * 60) | |
| print("🚀 Starting DoppelGen Cython Native Binary Compilation (.so)...") | |
| print("=" * 60) | |
| base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) | |
| os.chdir(base_dir) | |
| target_packages = ["doppelgen", "actora", "voxa", "sonora", "scenea", "captiona", "ocula"] | |
| compiled_so_count = 0 | |
| compiled_pyc_count = 0 | |
| deleted_count = 0 | |
| for pkg in target_packages: | |
| pkg_dir = os.path.join(base_dir, pkg) | |
| if not os.path.exists(pkg_dir): | |
| continue | |
| os.chdir(pkg_dir) | |
| py_files_in_pkg = [] | |
| for root, dirs, files in os.walk(pkg_dir): | |
| if "third_party" in root or "hf_cache" in root or ".cache" in root or "checkpoints" in root: | |
| continue | |
| if os.path.basename(root) in ["runners", "test", "tests", "docker", "build", "__pycache__"]: | |
| continue | |
| for file in files: | |
| if file.endswith(".py") and not file.startswith("."): | |
| if file in ["__init__.py", "preload_models.py", "app.py", "setup.py"]: | |
| continue | |
| full_path = os.path.join(root, file) | |
| rel_to_pkg = os.path.relpath(full_path, pkg_dir) | |
| module_name = rel_to_pkg[:-3].replace(os.sep, ".") | |
| py_files_in_pkg.append((full_path, rel_to_pkg, module_name)) | |
| print(f"📦 Compiling {len(py_files_in_pkg)} modules in {pkg}...") | |
| for full_path, rel_to_pkg, module_name in py_files_in_pkg: | |
| ext = Extension( | |
| module_name, | |
| sources=[rel_to_pkg], | |
| extra_compile_args=["-O3", "-fPIC", "-Wno-unused-variable"], | |
| ) | |
| success = False | |
| try: | |
| setup( | |
| ext_modules=cythonize( | |
| [ext], | |
| compiler_directives={ | |
| 'language_level': "3", | |
| 'always_allow_keywords': True, | |
| 'embedsignature': False, | |
| 'annotation_typing': False, | |
| }, | |
| quiet=True, | |
| ), | |
| script_args=["build_ext", "--inplace"], | |
| ) | |
| dir_name = os.path.dirname(rel_to_pkg) | |
| base_name = os.path.basename(rel_to_pkg)[:-3] | |
| search_dir = os.path.join(pkg_dir, dir_name) if dir_name else pkg_dir | |
| matching_so = [f for f in os.listdir(search_dir) if f.startswith(base_name) and f.endswith(".so")] | |
| if matching_so: | |
| success = True | |
| compiled_so_count += 1 | |
| except Exception as e: | |
| print(f"⚠️ Cython compilation fallback to .pyc for {rel_to_pkg}: {e}") | |
| if not success: | |
| pyc_path = full_path + "c" | |
| try: | |
| py_compile.compile(full_path, cfile=pyc_path, doraise=True, optimize=2) | |
| compiled_pyc_count += 1 | |
| except Exception as pe: | |
| print(f"❌ Bytecode compilation failed for {rel_to_pkg}: {pe}") | |
| for full_path, rel_to_pkg, module_name in py_files_in_pkg: | |
| dir_name = os.path.dirname(rel_to_pkg) | |
| base_name = os.path.basename(rel_to_pkg)[:-3] | |
| search_dir = os.path.join(pkg_dir, dir_name) if dir_name else pkg_dir | |
| matching_so = [f for f in os.listdir(search_dir) if f.startswith(base_name) and f.endswith(".so")] if os.path.exists(search_dir) else [] | |
| if matching_so: | |
| if os.path.exists(full_path): | |
| os.remove(full_path) | |
| deleted_count += 1 | |
| else: | |
| print(f"ℹ️ Preserved {rel_to_pkg} as .py source (no .so generated)", flush=True) | |
| os.chdir(base_dir) | |
| # Strip debugging symbols from generated .so files | |
| for root, dirs, files in os.walk(base_dir): | |
| if ".git" in root or "venv" in root or ".venv" in root: | |
| continue | |
| for file in files: | |
| if file.endswith(".so"): | |
| so_path = os.path.join(root, file) | |
| try: | |
| subprocess.run(["strip", "--strip-debug", so_path], check=False) | |
| except Exception: | |
| pass | |
| print(f"🔒 Compiled {compiled_so_count} Cython .so C-extensions (stripped symbols).") | |
| print(f"⚡ Compiled {compiled_pyc_count} modules to optimized .pyc bytecode.") | |
| # Clean up temporary Cython .c, .cpp, and build directories | |
| for root, dirs, files in os.walk(base_dir): | |
| for file in files: | |
| if file.endswith(".c") or file.endswith(".cpp"): | |
| if "third_party" not in root and not file.startswith("c_"): | |
| c_path = os.path.join(root, file) | |
| try: | |
| os.remove(c_path) | |
| except OSError: | |
| pass | |
| build_dir = os.path.join(root, "build") | |
| if os.path.exists(build_dir): | |
| shutil.rmtree(build_dir, ignore_errors=True) | |
| print(f"🧹 Removed {deleted_count} original source .py files (replaced with compiled binaries).") | |
| print("=" * 60) | |
| print("✨ DoppelGen Hardened Binary Build Complete!") | |
| print("=" * 60) | |
| if __name__ == "__main__": | |
| main() | |