Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions OneBranchPipelines/build-release-package-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ parameters:
- name: linuxConfigs
type: object
default:
# manylinux (glibc-based) for x86_64 and ARM64
- { tag: 'manylinux', arch: 'x86_64', platform: 'linux/amd64' }
- { tag: 'manylinux', arch: 'aarch64', platform: 'linux/arm64' }
# manylinux_2_28 (glibc 2.28, AlmaLinux 8 / RHEL 8+) for x86_64 and ARM64
# manylinux_2_28 wheels are forward-compatible: pip on glibc 2.34+ systems installs them fine
- { tag: 'manylinux_2_28', arch: 'x86_64', platform: 'linux/amd64' }
- { tag: 'manylinux_2_28', arch: 'aarch64', platform: 'linux/arm64' }
# musllinux (musl-based) for x86_64 and ARM64
- { tag: 'musllinux', arch: 'x86_64', platform: 'linux/amd64' }
- { tag: 'musllinux', arch: 'aarch64', platform: 'linux/arm64' }
Expand Down Expand Up @@ -394,14 +395,14 @@ extends:
# LINUX BUILD STAGES
# =========================
# Strategy: One stage per distribution × architecture
# Total: 4 stages (manylinux×2 + musllinux×2)
# Total: 4 stages (manylinux_2_28×2 + musllinux×2)
# Each stage builds ALL Python versions (3.10-3.14) in a loop
# Distributions:
# - manylinux: glibc-based (Ubuntu, CentOS, etc.)
# - manylinux_2_28: glibc 2.28+ (RHEL 8, Ubuntu 20.04+, etc.) — forward-compatible with newer glibc
# - musllinux: musl-based (Alpine Linux)
# Architectures: x86_64 (AMD/Intel), aarch64 (ARM64)
# Each stage:
# 1. Starts PyPA Docker container (manylinux_2_34 or musllinux_1_2)
# 1. Starts PyPA Docker container (manylinux_2_28 or musllinux_1_2)
# 2. Starts SQL Server Docker container
# 3. For each Python version (cp310-cp314):
# a. Builds .so native extension
Expand Down Expand Up @@ -452,8 +453,8 @@ extends:
- MacOS_py313
- MacOS_py314
# Linux dependencies (4 stages)
- Linux_manylinux_x86_64
- Linux_manylinux_aarch64
- Linux_manylinux_2_28_x86_64
- Linux_manylinux_2_28_aarch64
- Linux_musllinux_x86_64
- Linux_musllinux_aarch64
jobs:
Expand Down
25 changes: 14 additions & 11 deletions OneBranchPipelines/stages/build-linux-single-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
# Builds for Python 3.10, 3.11, 3.12, 3.13, 3.14 within single job
# Tests each wheel after building with isolated pytest execution
parameters:
# Stage identifier (e.g., 'Linux_manylinux_x86_64')
# Stage identifier (e.g., 'Linux_manylinux_2_28_x86_64')
- name: stageName
type: string
# Job identifier within the stage
- name: jobName
type: string
default: 'BuildWheels'
# Linux distribution type: 'manylinux' (glibc-based) or 'musllinux' (musl libc-based)
# Linux distribution type: 'manylinux_2_28' (glibc 2.28+) or 'musllinux' (musl libc-based)
- name: linuxTag
type: string
# CPU architecture: 'x86_64' (AMD64) or 'aarch64' (ARM64)
Expand Down Expand Up @@ -114,12 +114,15 @@ stages:
- script: |
# Determine image based on LINUX_TAG and ARCH
# Images are mirrored weekly from Quay.io into tdslibrs.azurecr.io
# manylinux_2_34 = AlmaLinux 9 (glibc 2.34)
# manylinux_2_28 = AlmaLinux 8 / RHEL 8 compatible (glibc 2.28)
# musllinux_1_2 = Alpine-based (musl libc)
if [[ "$(LINUX_TAG)" == "musllinux" ]]; then
if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then
IMAGE="tdslibrs.azurecr.io/import/python-build/manylinux_2_28_$(ARCH):latest"
elif [[ "$(LINUX_TAG)" == "musllinux" ]]; then
IMAGE="tdslibrs.azurecr.io/import/python-build/musllinux_1_2_$(ARCH):latest"
else
IMAGE="tdslibrs.azurecr.io/import/python-build/manylinux_2_34_$(ARCH):latest"
echo "ERROR: Unsupported LINUX_TAG '$(LINUX_TAG)'. Expected: manylinux_2_28 or musllinux" >&2
exit 1
fi

docker run -d --name build-$(LINUX_TAG)-$(ARCH) \
Expand All @@ -133,7 +136,7 @@ stages:
- script: |
set -euxo pipefail
export PATH=$PATH:`pwd`/docker
if [[ "$(LINUX_TAG)" == "manylinux" ]]; then
if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then
docker exec build-$(LINUX_TAG)-$(ARCH) bash -lc '
set -euxo pipefail
if command -v dnf >/dev/null 2>&1; then
Expand Down Expand Up @@ -191,7 +194,7 @@ stages:
# Build wheels for all Python versions (3.10-3.14) and test each one
- script: |
set -euxo pipefail
if [[ "$(LINUX_TAG)" == "manylinux" ]]; then SHELL_EXE=bash; else SHELL_EXE=sh; fi
if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then SHELL_EXE=bash; else SHELL_EXE=sh; fi
docker exec build-$(LINUX_TAG)-$(ARCH) $SHELL_EXE -lc 'mkdir -p /workspace/dist'

# Loop through all Python versions: build wheel -> test wheel -> repeat
Expand All @@ -201,9 +204,9 @@ stages:
echo "Building and testing $PYBIN on $(LINUX_TAG)/$(ARCH)"
echo "====================================================="

if [[ "$(LINUX_TAG)" == "manylinux" ]]; then
if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then
# Manylinux (glibc-based) - use bash
docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD="$(DB_PASSWORD)" build-$(LINUX_TAG)-$(ARCH) bash -lc '
docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD="$(DB_PASSWORD)" -e MANYLINUX_TAG="$(LINUX_TAG)" build-$(LINUX_TAG)-$(ARCH) bash -lc '
set -euxo pipefail;

# Step 1: Setup Python environment
Expand Down Expand Up @@ -271,7 +274,7 @@ stages:
'
else
# Musllinux (musl libc-based) - use sh
docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD="$(DB_PASSWORD)" build-$(LINUX_TAG)-$(ARCH) sh -lc '
docker exec -e PYBIN=$PYBIN -e SQL_IP=$(SQL_IP) -e DB_PASSWORD="$(DB_PASSWORD)" -e MANYLINUX_TAG="$(LINUX_TAG)" build-$(LINUX_TAG)-$(ARCH) sh -lc '
set -euxo pipefail;

# Step 1: Setup Python environment
Expand Down Expand Up @@ -361,7 +364,7 @@ stages:
# Copy native .so bindings for artifact archival
echo "Copying .so bindings to host..."
mkdir -p "$(ob_outputDirectory)/bindings/$(LINUX_TAG)-$(ARCH)"
docker exec build-$(LINUX_TAG)-$(ARCH) $([[ "$(LINUX_TAG)" == "manylinux" ]] && echo bash -lc || echo sh -lc) '
docker exec build-$(LINUX_TAG)-$(ARCH) $([[ "$(LINUX_TAG)" == "manylinux_2_28" ]] && echo bash -lc || echo sh -lc) '
OUT="/tmp/ddbc-out";
rm -rf "$OUT"; mkdir -p "$OUT";
find /workspace/mssql_python -maxdepth 1 -type f -name "*.so" -exec cp -v {} "$OUT"/ \; || true
Expand Down
7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ def get_platform_info():
libc_name, _ = platform.libc_ver()
is_musl = libc_name == "" or "musl" in libc_name.lower()

# Allow explicit override via MANYLINUX_TAG env var (defaults to manylinux_2_28)
manylinux_tag = os.environ.get("MANYLINUX_TAG", "manylinux_2_28")

if target_arch == "x86_64":
return "x86_64", "musllinux_1_2_x86_64" if is_musl else "manylinux_2_34_x86_64"
return "x86_64", f"musllinux_1_2_x86_64" if is_musl else f"{manylinux_tag}_x86_64"
elif target_arch in ["aarch64", "arm64"]:
return "aarch64", "musllinux_1_2_aarch64" if is_musl else "manylinux_2_34_aarch64"
return "aarch64", f"musllinux_1_2_aarch64" if is_musl else f"{manylinux_tag}_aarch64"
else:
raise OSError(
f"Unsupported architecture '{target_arch}' for Linux; expected 'x86_64' or 'aarch64'."
Expand Down
Loading