Skip to content

Commit a6af975

Browse files
authored
Merge pull request #16 from Klebert-Engineering/manylinux-arm64
docker: Support arm64 manylinux image and wheel creation.
2 parents fe58095 + 6e7b831 commit a6af975

5 files changed

Lines changed: 101 additions & 32 deletions

File tree

Dockerfile.template

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,43 @@ RUN yum update -y && yum install -y \
2121
RUN rm -f /usr/local/bin/cmake /usr/local/bin/ctest /usr/local/bin/cpack
2222

2323
# Install CMake 3.31.8 (latest 3.x version)
24-
ADD https://github.com/Kitware/CMake/releases/download/v3.31.8/cmake-3.31.8-linux-x86_64.tar.gz /tmp/
25-
RUN cd /tmp && \
26-
tar -xzf cmake-3.31.8-linux-x86_64.tar.gz && \
27-
cp -r cmake-3.31.8-linux-x86_64/bin/* /usr/local/bin/ && \
28-
cp -r cmake-3.31.8-linux-x86_64/share/* /usr/local/share/ && \
24+
# Map Docker architecture to CMake architecture naming
25+
RUN if [ "${architecture}" = "x86_64" ]; then \
26+
CMAKE_ARCH="x86_64"; \
27+
elif [ "${architecture}" = "aarch64" ]; then \
28+
CMAKE_ARCH="aarch64"; \
29+
else \
30+
echo "Unsupported architecture: ${architecture}"; exit 1; \
31+
fi && \
32+
curl -L https://github.com/Kitware/CMake/releases/download/v3.31.8/cmake-3.31.8-linux-${CMAKE_ARCH}.tar.gz -o /tmp/cmake.tar.gz && \
33+
cd /tmp && \
34+
tar -xzf cmake.tar.gz && \
35+
cp -r cmake-3.31.8-linux-${CMAKE_ARCH}/bin/* /usr/local/bin/ && \
36+
cp -r cmake-3.31.8-linux-${CMAKE_ARCH}/share/* /usr/local/share/ && \
2937
rm -rf /tmp/cmake*
3038

31-
# Install Python
32-
ADD https://www.python.org/ftp/python/${pyver_long}/Python-${pyver_long}.tgz /usr/local/src
33-
RUN cd /usr/local/src && \
34-
tar -xzvf Python-${pyver_long}.tgz && \
35-
cd Python-${pyver_long} && \
36-
./configure --enable-shared && \
37-
make -j$(nproc) install
38-
RUN ln -sf /usr/local/src/Python-${pyver_long}/libpython${pyver_short}.so.1.0 /lib64/libpython${pyver_short}.so.1.0
39-
RUN pip${pyver_short} install wheel
40-
RUN pip${pyver_short} install -U pip
39+
# Use pre-installed Python from manylinux image
40+
# The manylinux images already have Python versions in /opt/python/
41+
# Create symlinks to make the Python version available system-wide
42+
RUN if [ -d /opt/python/cp$(echo ${pyver_short} | tr -d '.')-cp$(echo ${pyver_short} | tr -d '.') ]; then \
43+
# Create versioned symlinks
44+
ln -sf /opt/python/cp$(echo ${pyver_short} | tr -d '.')-cp$(echo ${pyver_short} | tr -d '.')/bin/python /usr/local/bin/python${pyver_short} && \
45+
ln -sf /opt/python/cp$(echo ${pyver_short} | tr -d '.')-cp$(echo ${pyver_short} | tr -d '.')/bin/pip /usr/local/bin/pip${pyver_short} && \
46+
# Override the generic python3 to point to our specific version
47+
ln -sf /opt/python/cp$(echo ${pyver_short} | tr -d '.')-cp$(echo ${pyver_short} | tr -d '.')/bin/python /usr/local/bin/python3 && \
48+
ln -sf /opt/python/cp$(echo ${pyver_short} | tr -d '.')-cp$(echo ${pyver_short} | tr -d '.')/bin/pip /usr/local/bin/pip3 && \
49+
# Also create python symlink for maximum compatibility
50+
ln -sf /opt/python/cp$(echo ${pyver_short} | tr -d '.')-cp$(echo ${pyver_short} | tr -d '.')/bin/python /usr/local/bin/python && \
51+
ln -sf /opt/python/cp$(echo ${pyver_short} | tr -d '.')-cp$(echo ${pyver_short} | tr -d '.')/bin/pip /usr/local/bin/pip && \
52+
echo "Using pre-installed Python ${pyver_short}"; \
53+
else \
54+
echo "Python ${pyver_short} not found in /opt/python/"; \
55+
exit 1; \
56+
fi
57+
58+
# Ensure wheel is installed (should already be present in manylinux images)
59+
RUN pip${pyver_short} install --upgrade pip wheel
60+
61+
# Set environment variables to help CMake find the correct Python
62+
# Note: We set PATH to prioritize /usr/local/bin where our symlinks are
63+
ENV PATH=/usr/local/bin:$PATH

README.md

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,24 @@ add_wheel_test(mylib-test
108108
)
109109
```
110110

111+
## Building Docker Images
112+
113+
To build the manylinux Docker images for different architectures:
114+
115+
```bash
116+
# Build x86_64 images (default)
117+
./deploy.bash
118+
119+
# Build ARM64/aarch64 images
120+
./deploy.bash --arch aarch64
121+
122+
# Build and push images with version tag
123+
./deploy.bash --version 2025.1 --push
124+
125+
# Build, tag as latest, and push
126+
./deploy.bash --version 2025.1 --push --latest
127+
```
128+
111129
## CI Utilities
112130

113131
This repository also provides several utilities to facilitate additional wheel deployment steps that are needed on macOS and Linux.
@@ -116,16 +134,22 @@ This repository also provides several utilities to facilitate additional wheel d
116134

117135
For CI jobs, this repo provides the following docker images:
118136

137+
**x86_64 architecture:**
119138
* `manylinux-cpp17-py3.9-x86_64`
120139
* `manylinux-cpp17-py3.10-x86_64`
121140
* `manylinux-cpp17-py3.11-x86_64`
122141
* `manylinux-cpp17-py3.12-x86_64`
123142
* `manylinux-cpp17-py3.13-x86_64`
124143

125-
This images are based on GLIBC 2.28, so e.g. the minimum Ubuntu version
126-
for wheels from your CI will be 21.04.
144+
**aarch64 (ARM64) architecture:**
145+
* `manylinux-cpp17-py3.9-aarch64`
146+
* `manylinux-cpp17-py3.10-aarch64`
147+
* `manylinux-cpp17-py3.11-aarch64`
148+
* `manylinux-cpp17-py3.12-aarch64`
149+
* `manylinux-cpp17-py3.13-aarch64`
127150

128-
Note: `aarch64` images are not yet deployed. Let us know if you need them!
151+
These images are based on GLIBC 2.28, so e.g. the minimum Ubuntu version
152+
for wheels from your CI will be 21.04.
129153

130154
You may use a Github Actions Snippet like this to build your wheels:
131155

@@ -135,8 +159,9 @@ jobs:
135159
strategy:
136160
matrix:
137161
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
162+
architecture: ["x86_64", "aarch64"]
138163
runs-on: ubuntu-latest
139-
container: ghcr.io/klebert-engineering/manylinux-cpp17-py${{ matrix.python-version }}-x86_64:latest
164+
container: ghcr.io/klebert-engineering/manylinux-cpp17-py${{ matrix.python-version }}-${{ matrix.architecture }}:latest
140165
steps:
141166
- uses: actions/checkout@v3
142167
with:

deploy.bash

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ image_name="manylinux-cpp17-py"
44
version="2025.1"
55
push=""
66
latest=""
7-
python_versions=(3.9.13 3.10.9 3.11.1 3.12.4 3.13.1)
7+
python_versions=(3.9 3.10 3.11 3.12 3.13)
88
architecture=x86_64
99

1010
while [[ $# -gt 0 ]]; do
@@ -30,21 +30,24 @@ while [[ $# -gt 0 ]]; do
3030
esac
3131
done
3232

33+
# Validate architecture
34+
if [[ "$architecture" != "x86_64" && "$architecture" != "aarch64" ]]; then
35+
echo "Error: Unsupported architecture '$architecture'. Supported architectures are: x86_64, aarch64"
36+
exit 1
37+
fi
3338

34-
for pyver_long in "${python_versions[@]}"; do
3539

36-
pyver_short=$(echo "$pyver_long" | sed "s/\\.[0-9]\+\$//")
40+
for pyver in "${python_versions[@]}"; do
3741

38-
echo "Building $architecture manylinux Docker image for Python $pyver_short ($pyver_long)..."
42+
echo "Building $architecture manylinux Docker image for Python $pyver..."
3943

40-
dockerfile="Dockerfile-$pyver_long-$architecture"
44+
dockerfile="Dockerfile-$pyver-$architecture"
4145

42-
sed -e "s/\${pyver_long}/$pyver_long/g" \
43-
-e "s/\${pyver_short}/$pyver_short/g" \
46+
sed -e "s/\${pyver_short}/$pyver/g" \
4447
-e "s/\${architecture}/$architecture/g" \
4548
Dockerfile.template > $dockerfile
4649

47-
image_name_full="ghcr.io/klebert-engineering/$image_name$pyver_short-$architecture"
50+
image_name_full="ghcr.io/klebert-engineering/$image_name$pyver-$architecture"
4851
docker build -t "$image_name_full:$version" -f $dockerfile .
4952

5053
if [[ -n "$latest" ]]; then

python-wheel-globals.cmake

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
1+
find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED)
22

33
# Some RPATH setup for macOS
44
if (APPLE)
@@ -31,9 +31,27 @@ elseif (APPLE)
3131
"-c" "import platform; print('_'.join(platform.mac_ver()[0].split('.')[:2]))"
3232
OUTPUT_VARIABLE MACOS_VER
3333
OUTPUT_STRIP_TRAILING_WHITESPACE)
34-
set(PY_WHEEL_PLATFORM "macosx_${MACOS_VER}_x86_64")
34+
execute_process(
35+
COMMAND
36+
"${Python3_EXECUTABLE}"
37+
"-c" "import platform; print(platform.machine())"
38+
OUTPUT_VARIABLE MACHINE_ARCH
39+
OUTPUT_STRIP_TRAILING_WHITESPACE)
40+
if(MACHINE_ARCH STREQUAL "arm64")
41+
set(PY_WHEEL_PLATFORM "macosx_${MACOS_VER}_arm64")
42+
else()
43+
set(PY_WHEEL_PLATFORM "macosx_${MACOS_VER}_x86_64")
44+
endif()
3545
else()
36-
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
46+
execute_process(
47+
COMMAND
48+
"${Python3_EXECUTABLE}"
49+
"-c" "import platform; print(platform.machine())"
50+
OUTPUT_VARIABLE MACHINE_ARCH
51+
OUTPUT_STRIP_TRAILING_WHITESPACE)
52+
if(MACHINE_ARCH STREQUAL "aarch64")
53+
set(PY_WHEEL_PLATFORM "linux_aarch64")
54+
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
3755
set(PY_WHEEL_PLATFORM "linux_x86_64")
3856
else()
3957
set(PY_WHEEL_PLATFORM "linux_i686")

python-wheel.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ endfunction()
3535

3636
function (add_wheel WHEEL_TARGET)
3737
set(Python_FIND_VIRTUALENV FIRST) # Favor venv over system install
38-
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
38+
find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED)
3939

4040
# Parse arguments
4141
cmake_parse_arguments(WHEEL
@@ -189,7 +189,7 @@ endfunction()
189189

190190
function (add_wheel_test TEST_NAME)
191191
set(Python_FIND_VIRTUALENV FIRST) # Favor venv over system install
192-
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
192+
find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED)
193193

194194
# Parse arguments
195195
cmake_parse_arguments(WHEEL_TEST

0 commit comments

Comments
 (0)