Skip to content

Instantly share code, notes, and snippets.

@EncodeTheCode
Created March 19, 2025 13:58
Show Gist options
  • Save EncodeTheCode/8d89f84d9fa0a145d5e362125f9ad30a to your computer and use it in GitHub Desktop.
Save EncodeTheCode/8d89f84d9fa0a145d5e362125f9ad30a to your computer and use it in GitHub Desktop.
import os
import sys
import subprocess
import shutil
import argparse
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
SRC_DIR = os.path.join(PROJECT_ROOT, "src")
BUILD_DIR = os.path.join(PROJECT_ROOT, "build")
MODULES_DIR = os.path.join(BUILD_DIR, "modules")
os.makedirs(MODULES_DIR, exist_ok=True)
def get_python_include():
"""Returns the Python include path dynamically."""
return subprocess.check_output(
[sys.executable, "-c", "import sysconfig; print(sysconfig.get_path('include'))"],
text=True
).strip()
def compile_cpp_modules(arch):
"""Compiles C++ modules into shared libraries (DLL/SO) using GCC."""
cpp_modules = ["module1"]
python_include = get_python_include()
arch_flag = "-m64" if arch == "64" else "-m32"
for module in cpp_modules:
cpp_file = os.path.join(SRC_DIR, "modules", f"{module}.cpp")
output_file = os.path.join(MODULES_DIR, f"{module}_{arch}.so")
if sys.platform == "win32":
output_file = os.path.join(MODULES_DIR, f"{module}_{arch}.dll")
compile_cmd = [
"gcc", "-O3", "-Wall", "-shared", "-std=c++11", "-fPIC",
arch_flag, # Choose 32-bit or 64-bit
f"-I{python_include}", cpp_file, "-o", output_file
]
print(f"Compiling C++ module ({arch}-bit): {module}...")
try:
subprocess.run(compile_cmd, check=True)
print(f"✅ {module} ({arch}-bit) compiled successfully!")
except subprocess.CalledProcessError:
print(f"❌ Failed to compile {module} ({arch}-bit)")
sys.exit(1)
def compile_python_to_exe(arch):
"""Compiles Python script into an executable using Nuitka and GCC."""
print(f"Compiling Python script into a {arch}-bit executable...")
compile_cmd = [
"nuitka",
"--standalone",
"--follow-imports",
"--plugin-enable=pylint-warnings",
"--output-dir=build",
"--mingw64" if sys.platform == "win32" else "--lto",
"--clang" if sys.platform == "darwin" else "", # Use Clang for macOS
"--windows-icon=icon.ico" if sys.platform == "win32" else "",
os.path.join(SRC_DIR, "main.py"),
]
if arch == "32":
compile_cmd.append("--mingw32")
try:
subprocess.run([arg for arg in compile_cmd if arg], check=True)
print(f"✅ Python ({arch}-bit) compiled successfully!")
except subprocess.CalledProcessError:
print(f"❌ Python compilation ({arch}-bit) failed!")
sys.exit(1)
exe_name = "main.exe" if sys.platform == "win32" else "main"
exe_path = os.path.join(BUILD_DIR, exe_name)
new_exe_path = os.path.join(BUILD_DIR, f"my_application_{arch}.exe" if sys.platform == "win32" else f"my_application_{arch}")
if os.path.exists(exe_path):
shutil.move(exe_path, new_exe_path)
def finalize_build(arch):
"""Moves compiled modules to the correct location and verifies the build."""
compiled_exe = os.path.join(BUILD_DIR, f"my_application_{arch}.exe" if sys.platform == "win32" else f"my_application_{arch}")
if os.path.exists(compiled_exe):
print(f"🎉 Build completed successfully for {arch}-bit!")
print(f"Executable created: {compiled_exe}")
else:
print(f"❌ Error: Executable ({arch}-bit) not found!")
sys.exit(1)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Python Compiler with C++ Modules")
parser.add_argument("--arch", choices=["32", "64", "both"], default="64", help="Choose 32-bit, 64-bit, or both architectures")
args = parser.parse_args()
architectures = ["32", "64"] if args.arch == "both" else [args.arch]
for arch in architectures:
compile_cpp_modules(arch)
compile_python_to_exe(arch)
finalize_build(arch)
print("✅ All requested builds completed successfully!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment