From 6854a46a3b947d599b9e5d2bcf22d46378743e99 Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Wed, 29 Apr 2026 14:24:04 +0530 Subject: [PATCH 1/3] ci: add manylinux_2_28 build targets for RHEL 8 / glibc 2.28 compatibility --- .../build-release-package-pipeline.yml | 5 ++++- .../stages/build-linux-single-stage.yml | 15 +++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/OneBranchPipelines/build-release-package-pipeline.yml b/OneBranchPipelines/build-release-package-pipeline.yml index eff7fd9d0..5a9391b84 100644 --- a/OneBranchPipelines/build-release-package-pipeline.yml +++ b/OneBranchPipelines/build-release-package-pipeline.yml @@ -130,9 +130,12 @@ parameters: - name: linuxConfigs type: object default: - # manylinux (glibc-based) for x86_64 and ARM64 + # manylinux_2_34 (glibc 2.34, AlmaLinux 9) 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 compatible) for x86_64 and ARM64 + - { 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' } diff --git a/OneBranchPipelines/stages/build-linux-single-stage.yml b/OneBranchPipelines/stages/build-linux-single-stage.yml index 17815cadb..977bceb0c 100644 --- a/OneBranchPipelines/stages/build-linux-single-stage.yml +++ b/OneBranchPipelines/stages/build-linux-single-stage.yml @@ -114,10 +114,13 @@ 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) - # musllinux_1_2 = Alpine-based (musl libc) + # 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 IMAGE="tdslibrs.azurecr.io/import/python-build/musllinux_1_2_$(ARCH):latest" + elif [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then + IMAGE="tdslibrs.azurecr.io/import/python-build/manylinux_2_28_$(ARCH):latest" else IMAGE="tdslibrs.azurecr.io/import/python-build/manylinux_2_34_$(ARCH):latest" fi @@ -133,7 +136,7 @@ stages: - script: | set -euxo pipefail export PATH=$PATH:`pwd`/docker - if [[ "$(LINUX_TAG)" == "manylinux" ]]; then + if [[ "$(LINUX_TAG)" == "manylinux" || "$(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 @@ -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" || "$(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 @@ -201,7 +204,7 @@ stages: echo "Building and testing $PYBIN on $(LINUX_TAG)/$(ARCH)" echo "=====================================================" - if [[ "$(LINUX_TAG)" == "manylinux" ]]; then + if [[ "$(LINUX_TAG)" == "manylinux" || "$(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 ' set -euxo pipefail; @@ -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" || "$(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 From 944a66419323e59c7a78b22d6b02546c722c7f12 Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Wed, 29 Apr 2026 20:33:28 +0530 Subject: [PATCH 2/3] fix: address review comments - simplify to manylinux_2_28 only, fix wheel tag, explicit image selection --- .../build-release-package-pipeline.yml | 16 +++++------ .../stages/build-linux-single-stage.yml | 28 +++++++++---------- setup.py | 7 +++-- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/OneBranchPipelines/build-release-package-pipeline.yml b/OneBranchPipelines/build-release-package-pipeline.yml index 5a9391b84..04e67887a 100644 --- a/OneBranchPipelines/build-release-package-pipeline.yml +++ b/OneBranchPipelines/build-release-package-pipeline.yml @@ -130,10 +130,8 @@ parameters: - name: linuxConfigs type: object default: - # manylinux_2_34 (glibc 2.34, AlmaLinux 9) 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 compatible) for x86_64 and 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 @@ -397,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 @@ -455,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: diff --git a/OneBranchPipelines/stages/build-linux-single-stage.yml b/OneBranchPipelines/stages/build-linux-single-stage.yml index 977bceb0c..e1a9b02b8 100644 --- a/OneBranchPipelines/stages/build-linux-single-stage.yml +++ b/OneBranchPipelines/stages/build-linux-single-stage.yml @@ -10,7 +10,7 @@ parameters: - 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) @@ -114,15 +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 - IMAGE="tdslibrs.azurecr.io/import/python-build/musllinux_1_2_$(ARCH):latest" - elif [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then + # manylinux_2_28 = AlmaLinux 8 / RHEL 8 compatible (glibc 2.28) + # musllinux_1_2 = Alpine-based (musl libc) + 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) \ @@ -136,7 +136,7 @@ stages: - script: | set -euxo pipefail export PATH=$PATH:`pwd`/docker - if [[ "$(LINUX_TAG)" == "manylinux" || "$(LINUX_TAG)" == "manylinux_2_28" ]]; 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 @@ -194,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" || "$(LINUX_TAG)" == "manylinux_2_28" ]]; 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 @@ -204,9 +204,9 @@ stages: echo "Building and testing $PYBIN on $(LINUX_TAG)/$(ARCH)" echo "=====================================================" - if [[ "$(LINUX_TAG)" == "manylinux" || "$(LINUX_TAG)" == "manylinux_2_28" ]]; 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 @@ -274,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 @@ -364,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" || "$(LINUX_TAG)" == "manylinux_2_28" ]] && 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 diff --git a/setup.py b/setup.py index 0e719c48b..30a177fe3 100644 --- a/setup.py +++ b/setup.py @@ -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'." From 7325c4a3de108e40a942b6871ce61fe6fd4937e9 Mon Sep 17 00:00:00 2001 From: gargsaumya Date: Wed, 29 Apr 2026 20:39:30 +0530 Subject: [PATCH 3/3] fix: update stale stage identifier example comment --- OneBranchPipelines/stages/build-linux-single-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OneBranchPipelines/stages/build-linux-single-stage.yml b/OneBranchPipelines/stages/build-linux-single-stage.yml index e1a9b02b8..6d82f5a6f 100644 --- a/OneBranchPipelines/stages/build-linux-single-stage.yml +++ b/OneBranchPipelines/stages/build-linux-single-stage.yml @@ -3,7 +3,7 @@ # 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