Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 53
FEAT: Modernize build system with pyproject.toml and custom build backend#408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
7966b90a5668d32fefac9cc357ee2aa2c053409a704129ff556186bda1667e6c42f8192084bb1f797db36a50152394b63a43337f84b2a5cfaf72b639aa716bda350deaa36078ee794b5515b673a27b0236bfe9fee363b721e01c8174ba9fff3c6ce1a6d1525e254995aaff546d1b96019afe5d566c7808File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -63,3 +63,4 @@ build/ | ||
| # learning files | ||
| learnings/ | ||
| .coverage | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| """ | ||
| build_backend - Build system for mssql-python native extensions. | ||
| This package provides: | ||
| 1. A CLI tool: `python -m build_backend` | ||
| 2. A PEP 517 build backend that auto-compiles ddbc_bindings | ||
| Usage: | ||
| python -m build_backend # Compile ddbc_bindings only | ||
| python -m build_backend --arch arm64 # Specify architecture (Windows) | ||
| python -m build_backend --coverage # Enable coverage (Linux) | ||
| python -m build # Compile + create wheel (automatic) | ||
| """ | ||
| from .compiler import compile_ddbc | ||
| from .platform_utils import get_platform_info | ||
| __all__ = ["compile_ddbc", "get_platform_info"] | ||
| __version__ = "1.3.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| """ | ||
| CLI entry point for build_backend. | ||
| Usage: | ||
| python -m build_backend # Compile ddbc_bindings | ||
| python -m build_backend --arch arm64 # Specify architecture (Windows) | ||
| python -m build_backend --coverage # Enable coverage (Linux) | ||
| python -m build_backend --help # Show help | ||
| """ | ||
| import argparse | ||
| import sys | ||
| from . import __version__ | ||
| from .compiler import compile_ddbc | ||
| from .platform_utils import get_platform_info | ||
| def main() -> int: | ||
| """Main entry point for the CLI.""" | ||
| parser = argparse.ArgumentParser( | ||
| prog="python -m build_backend", | ||
| description="Compile ddbc_bindings native extension for mssql-python", | ||
| formatter_class=argparse.RawDescriptionHelpFormatter, | ||
| epilog=""" | ||
| Examples: | ||
| python -m build_backend # Build for current platform | ||
| python -m build_backend --arch arm64 # Build for ARM64 (Windows) | ||
| python -m build_backend --coverage # Build with coverage (Linux) | ||
| python -m build_backend --quiet # Build without output | ||
| """, | ||
| ) | ||
| parser.add_argument( | ||
| "--arch", "-a", | ||
| choices=["x64", "x86", "arm64", "x86_64", "aarch64", "universal2"], | ||
| help="Target architecture (Windows: x64, x86, arm64)", | ||
| ) | ||
| parser.add_argument( | ||
| "--coverage", "-c", | ||
| action="store_true", | ||
| help="Enable coverage instrumentation (Linux only)", | ||
| ) | ||
| parser.add_argument( | ||
| "--quiet", "-q", | ||
| action="store_true", | ||
| help="Suppress build output", | ||
| ) | ||
| parser.add_argument( | ||
| "--version", "-V", | ||
| action="version", | ||
| version=f"%(prog)s {__version__}", | ||
| ) | ||
| args = parser.parse_args() | ||
| # Show platform info | ||
| if not args.quiet: | ||
| arch, platform_tag = get_platform_info() | ||
| print(f"[build_backend] Platform: {sys.platform}") | ||
| print(f"[build_backend] Architecture: {arch}") | ||
| print(f"[build_backend] Platform tag: {platform_tag}") | ||
| print() | ||
| try: | ||
| compile_ddbc( | ||
| arch=args.arch, | ||
| coverage=args.coverage, | ||
| verbose=not args.quiet, | ||
| ) | ||
| return 0 | ||
| except FileNotFoundError as e: | ||
| print(f"Error: {e}", file=sys.stderr) | ||
| return 1 | ||
| except RuntimeError as e: | ||
| print(f"Build failed: {e}", file=sys.stderr) | ||
| return 1 | ||
| if __name__ == "__main__": | ||
| sys.exit(main()) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| """Core compiler logic for ddbc_bindings. | ||
| Locates and runs the platform-specific build script | ||
| (``build.sh`` / ``build.bat``) in ``mssql_python/pybind/``. | ||
| """ | ||
| import sys | ||
| import subprocess | ||
| from pathlib import Path | ||
| from typing import Optional | ||
| from .platform_utils import get_platform_info | ||
| def find_pybind_dir() -> Path: | ||
| """Find the pybind directory containing build scripts.""" | ||
| # Try relative to this file first (for installed package) | ||
| possible_paths = [ | ||
| Path(__file__).parent.parent / "mssql_python" / "pybind", | ||
| Path.cwd() / "mssql_python" / "pybind", | ||
| ] | ||
| # Check for platform-appropriate build script | ||
| build_script = "build.bat" if sys.platform.startswith("win") else "build.sh" | ||
| for path in possible_paths: | ||
| if path.exists() and (path / build_script).exists(): | ||
| return path | ||
| raise FileNotFoundError( | ||
| f"Could not find mssql_python/pybind directory with {build_script}. " | ||
| "Make sure you're running from the project root." | ||
| ) | ||
| def compile_ddbc( | ||
| arch: Optional[str] = None, | ||
| coverage: bool = False, | ||
| verbose: bool = True, | ||
| ) -> bool: | ||
| """ | ||
| Compile ddbc_bindings using the platform-specific build script. | ||
| Args: | ||
| arch: Target architecture (Windows only: x64, x86, arm64) | ||
| coverage: Enable coverage instrumentation (Linux/macOS only) | ||
| verbose: Print build output | ||
| Returns: | ||
| True if build succeeded, False otherwise | ||
| Raises: | ||
| FileNotFoundError: If build script is not found | ||
| RuntimeError: If build fails | ||
| """ | ||
| pybind_dir = find_pybind_dir() | ||
| if arch is None: | ||
| arch, _ = get_platform_info() | ||
| if sys.platform.startswith("win"): | ||
| return _run_windows_build(pybind_dir, arch, verbose) | ||
| else: | ||
| return _run_unix_build(pybind_dir, coverage, verbose) | ||
| def _run_windows_build(pybind_dir: Path, arch: str, verbose: bool) -> bool: | ||
| """Run build.bat on Windows.""" | ||
| build_script = pybind_dir / "build.bat" | ||
| if not build_script.exists(): | ||
| raise FileNotFoundError(f"Build script not found: {build_script}") | ||
| cmd = [str(build_script), arch] | ||
| if verbose: | ||
| print(f"[build_backend] Running: {' '.join(cmd)}") | ||
| print(f"[build_backend] Working directory: {pybind_dir}") | ||
| result = subprocess.run( | ||
| cmd, | ||
| cwd=pybind_dir, | ||
| check=False, | ||
| capture_output=not verbose, | ||
| ) | ||
| if result.returncode != 0: | ||
| if not verbose: | ||
| if result.stdout: | ||
| print(result.stdout.decode(), file=sys.stderr) | ||
| if result.stderr: | ||
| print(result.stderr.decode(), file=sys.stderr) | ||
| raise RuntimeError(f"build.bat failed with exit code {result.returncode}") | ||
| if verbose: | ||
| print("[build_backend] Windows build completed successfully!") | ||
| return True | ||
| def _run_unix_build(pybind_dir: Path, coverage: bool, verbose: bool) -> bool: | ||
| """Run build.sh on macOS/Linux.""" | ||
| build_script = pybind_dir / "build.sh" | ||
| if not build_script.exists(): | ||
| raise FileNotFoundError(f"Build script not found: {build_script}") | ||
| # Make sure the script is executable | ||
| build_script.chmod(0o755) | ||
| cmd = ["bash", str(build_script)] | ||
| if coverage: | ||
| cmd.append("--coverage") | ||
| if verbose: | ||
| print(f"[build_backend] Running: {' '.join(cmd)}") | ||
| print(f"[build_backend] Working directory: {pybind_dir}") | ||
| result = subprocess.run( | ||
| cmd, | ||
| cwd=pybind_dir, | ||
| check=False, | ||
| capture_output=not verbose, | ||
| ) | ||
| if result.returncode != 0: | ||
| if not verbose: | ||
| if result.stdout: | ||
| print(result.stdout.decode(), file=sys.stderr) | ||
| if result.stderr: | ||
| print(result.stderr.decode(), file=sys.stderr) | ||
| raise RuntimeError(f"build.sh failed with exit code {result.returncode}") | ||
| if verbose: | ||
| print("[build_backend] Unix build completed successfully!") | ||
| return True |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.