Skip to content

Commit 46e2449

Browse files
committed
ci: build wheel
1 parent e613828 commit 46e2449

5 files changed

Lines changed: 336 additions & 60 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: Setup Mapnik build env
2+
description: Configure cibuildwheel env vars for Mapnik builds
3+
runs:
4+
using: composite
5+
steps:
6+
- name: Export cibuildwheel env vars
7+
shell: bash
8+
run: |
9+
{
10+
echo "CIBW_BUILD_FRONTEND=pip"
11+
echo "CIBW_ENVIRONMENT_LINUX=PKG_CONFIG_PATH=/usr/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig:/opt/lib/pkgconfig:\$PKG_CONFIG_PATH"
12+
echo "CIBW_BEFORE_ALL_LINUX=bash .github/actions/setup-mapnik/setup-manylinux.sh"
13+
} >> "$GITHUB_ENV"
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
BOOST_VER=1.83.0
5+
BOOST_VER_UNDERSCORE=1_83_0
6+
PROJ_VER=9.7.1
7+
GDAL_VER=3.12.1
8+
MAPNIK_VER=4.2.0
9+
10+
log() {
11+
echo ">> $*"
12+
}
13+
14+
find_mapnik_pc() {
15+
log "libmapnik.pc locations (if any):"
16+
find /usr /opt /usr/local -name "libmapnik.pc" -print 2>/dev/null || true
17+
}
18+
19+
install_with_apt() {
20+
mkdir -p /etc/apt/sources.list.d /etc/apt/preferences.d
21+
echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list
22+
echo 'Package: *
23+
Pin: release a=sid
24+
Pin-Priority: 100' > /etc/apt/preferences.d/sid
25+
apt-get update
26+
apt-get install -y build-essential pkg-config libbz2-dev
27+
apt-get install -y -t sid libmapnik-dev fonts-noto-cjk
28+
}
29+
30+
detect_dnf() {
31+
if command -v dnf >/dev/null 2>&1; then
32+
echo "dnf"
33+
return
34+
fi
35+
if command -v yum >/dev/null 2>&1; then
36+
echo "yum"
37+
return
38+
fi
39+
return 1
40+
}
41+
42+
prepare_dnf() {
43+
local dnf_bin="$1"
44+
if command -v dnf >/dev/null 2>&1; then
45+
dnf install -y dnf-plugins-core
46+
# Enable repo variants across EL8/EL9.
47+
dnf config-manager --set-enabled powertools || true
48+
dnf config-manager --set-enabled crb || true
49+
else
50+
yum install -y yum-utils || true
51+
fi
52+
"$dnf_bin" install -y epel-release || true
53+
}
54+
55+
install_base_deps_dnf() {
56+
local dnf_bin="$1"
57+
"$dnf_bin" install -y \
58+
bzip2-devel \
59+
gcc gcc-c++ make \
60+
pkgconfig
61+
}
62+
63+
install_fonts_dnf() {
64+
local dnf_bin="$1"
65+
"$dnf_bin" install -y google-noto-sans-cjk-ttc-fonts || \
66+
"$dnf_bin" install -y google-noto-cjk-fonts || \
67+
"$dnf_bin" install -y noto-sans-cjk-fonts || true
68+
}
69+
70+
install_build_deps_dnf() {
71+
local dnf_bin="$1"
72+
"$dnf_bin" install -y \
73+
boost-devel \
74+
freetype-devel \
75+
libpng-devel \
76+
libjpeg-turbo-devel \
77+
libtiff-devel \
78+
libicu-devel \
79+
zlib-devel \
80+
libxml2-devel \
81+
proj-devel \
82+
geos-devel \
83+
gdal-devel \
84+
harfbuzz-devel \
85+
cairo-devel \
86+
libcurl-devel \
87+
sqlite-devel \
88+
git \
89+
curl \
90+
wget \
91+
tar \
92+
cmake
93+
# Optional deps for more Mapnik features; ignore if not available on EL8.
94+
"$dnf_bin" install -y libwebp-devel || true
95+
"$dnf_bin" install -y libavif-devel || true
96+
"$dnf_bin" install -y postgresql-devel || true
97+
"$dnf_bin" install -y expat-devel || true
98+
}
99+
100+
python_for_build() {
101+
ls -d /opt/python/cp312-cp312/bin/python /opt/python/cp3*/bin/python | head -1
102+
}
103+
104+
build_boost() {
105+
log "Building Boost ${BOOST_VER}"
106+
local workdir="/tmp/boost-src"
107+
rm -rf "$workdir"
108+
mkdir -p "$workdir"
109+
cd "$workdir"
110+
local tarball="boost_${BOOST_VER_UNDERSCORE}.tar.bz2"
111+
curl -L -o "$tarball" "https://archives.boost.io/release/${BOOST_VER}/source/boost_${BOOST_VER_UNDERSCORE}.tar.bz2"
112+
tar -xjf "$tarball"
113+
cd "boost_${BOOST_VER_UNDERSCORE}"
114+
./bootstrap.sh --prefix=/usr/local --with-libraries=regex,program_options,system,filesystem,thread
115+
if ! ./b2 -d0 --abbreviate-paths -j"$(nproc)" link=shared runtime-link=shared install > /tmp/boost-build.log 2>&1; then
116+
echo "Boost build failed. Last 200 lines:"
117+
tail -200 /tmp/boost-build.log
118+
exit 1
119+
fi
120+
ldconfig
121+
export LD_LIBRARY_PATH="/usr/local/lib:/usr/local/lib64:${LD_LIBRARY_PATH:-}"
122+
}
123+
124+
build_proj() {
125+
log "Building PROJ ${PROJ_VER}"
126+
rm -rf /tmp/proj-src
127+
git -c advice.detachedHead=false clone --depth 1 --branch "${PROJ_VER}" https://github.com/OSGeo/PROJ.git /tmp/proj-src
128+
mkdir -p /tmp/proj-src/build
129+
cd /tmp/proj-src/build
130+
if ! {
131+
cmake /tmp/proj-src \
132+
-DCMAKE_BUILD_TYPE=Release \
133+
-DCMAKE_INSTALL_PREFIX=/usr/local \
134+
-DBUILD_TESTING=OFF \
135+
-DCMAKE_CXX_FLAGS="-Wno-psabi" \
136+
-DENABLE_TIFF=OFF \
137+
--log-level=WARNING
138+
make -s -j"$(nproc)"
139+
make -s install
140+
} > /tmp/proj-build.log 2>&1; then
141+
echo "PROJ build failed. Last 200 lines:"
142+
tail -200 /tmp/proj-build.log
143+
exit 1
144+
fi
145+
ldconfig
146+
}
147+
148+
build_gdal() {
149+
log "Building GDAL ${GDAL_VER}"
150+
rm -rf /tmp/gdal-src
151+
git -c advice.detachedHead=false clone --depth 1 --branch "v${GDAL_VER}" https://github.com/OSGeo/gdal.git /tmp/gdal-src
152+
cd /tmp/gdal-src
153+
git -c advice.detachedHead=false submodule update --init --recursive
154+
mkdir -p /tmp/gdal-src/build
155+
cd /tmp/gdal-src/build
156+
if ! {
157+
cmake /tmp/gdal-src \
158+
-DCMAKE_BUILD_TYPE=Release \
159+
-DCMAKE_INSTALL_PREFIX=/usr/local \
160+
-DBUILD_TESTING=OFF \
161+
-DCMAKE_CXX_FLAGS="-Wno-psabi" \
162+
-DGDAL_USE_INTERNAL_LIBS=ON \
163+
-DGDAL_USE_GEOS=ON \
164+
-DGDAL_USE_PROJ=ON \
165+
--log-level=WARNING
166+
make -s -j"$(nproc)"
167+
make -s install
168+
} > /tmp/gdal-build.log 2>&1; then
169+
echo "GDAL build failed. Last 200 lines:"
170+
tail -200 /tmp/gdal-build.log
171+
exit 1
172+
fi
173+
ldconfig
174+
}
175+
176+
build_mapnik() {
177+
local pybin="$1"
178+
log "Building Mapnik ${MAPNIK_VER}"
179+
rm -rf /tmp/mapnik-src
180+
git clone --depth 1 --branch "v${MAPNIK_VER}" https://github.com/mapnik/mapnik.git /tmp/mapnik-src
181+
cd /tmp/mapnik-src
182+
git -c advice.detachedHead=false submodule update --init --recursive
183+
mkdir -p /tmp/mapnik-src/build
184+
cd /tmp/mapnik-src/build
185+
if ! {
186+
cmake /tmp/mapnik-src \
187+
-DCMAKE_BUILD_TYPE=Release \
188+
-DCMAKE_INSTALL_PREFIX=/usr/local \
189+
-DBUILD_DEMO_VIEWER=OFF \
190+
-DBUILD_TESTING=OFF \
191+
-DCMAKE_CXX_FLAGS="-Wno-psabi" \
192+
-DWITH_JPEG=ON \
193+
-DWITH_PNG=ON \
194+
-DWITH_TIFF=ON \
195+
-DWITH_WEBP=ON \
196+
-DWITH_AVIF=ON \
197+
-DWITH_PROJ=ON \
198+
-DWITH_GDAL=ON \
199+
-DWITH_CAIRO=ON \
200+
-DWITH_HARFBUZZ=ON \
201+
-DWITH_FREETYPE=ON \
202+
-DWITH_SQLITE=ON \
203+
-DWITH_POSTGRESQL=ON \
204+
--log-level=WARNING
205+
make -s -j"$(nproc)"
206+
make -s install
207+
} > /tmp/mapnik-build.log 2>&1; then
208+
echo "Mapnik build failed. Last 200 lines:"
209+
tail -200 /tmp/mapnik-build.log
210+
exit 1
211+
fi
212+
ldconfig
213+
cd /
214+
}
215+
216+
build_mapnik_from_source() {
217+
local dnf_bin="$1"
218+
log "mapnik-devel not available in enabled repos; building Mapnik from source."
219+
"$dnf_bin" repolist || true
220+
"$dnf_bin" list available "mapnik*" || true
221+
install_build_deps_dnf "$dnf_bin"
222+
223+
local pybin
224+
pybin="$(python_for_build)"
225+
"$pybin" -m pip install --upgrade pip
226+
"$pybin" -m pip install scons
227+
228+
build_boost
229+
build_proj
230+
build_gdal
231+
build_mapnik "$pybin"
232+
}
233+
234+
if command -v apt-get >/dev/null 2>&1; then
235+
log "Using apt-get for Mapnik dependencies."
236+
install_with_apt
237+
elif dnf_bin="$(detect_dnf)"; then
238+
log "Using ${dnf_bin} for Mapnik dependencies."
239+
prepare_dnf "$dnf_bin"
240+
install_base_deps_dnf "$dnf_bin"
241+
if ! "$dnf_bin" install -y mapnik-devel; then
242+
build_mapnik_from_source "$dnf_bin"
243+
fi
244+
install_fonts_dnf "$dnf_bin"
245+
else
246+
echo "No supported package manager found (apt-get or dnf/yum)." >&2
247+
exit 1
248+
fi
249+
250+
find_mapnik_pc

.github/workflows/release.yml

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
name: Release
22

33
on:
4+
pull_request:
5+
branches: [ main, master, develop ]
46
push:
57
tags:
68
- 'v*.*.*'
@@ -30,7 +32,6 @@ jobs:
3032
echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT
3133
3234
build-wheels:
33-
needs: [extract-version]
3435
strategy:
3536
fail-fast: false
3637
matrix:
@@ -48,11 +49,40 @@ jobs:
4849
run: |
4950
python -m pip install --upgrade pip
5051
pip install cibuildwheel
52+
- name: Setup Mapnik build environment
53+
uses: ./.github/actions/setup-mapnik
5154

5255
- name: Build wheels
5356
env:
5457
CIBW_BUILD_VERBOSITY: 1
5558
CIBW_BEFORE_BUILD: "pip install uv && uv sync --frozen --no-dev || uv sync --no-dev"
59+
# Ensure pkg-config & mapnik-config are available during build requirements resolution.
60+
CIBW_ENVIRONMENT_MACOS: >-
61+
PATH=/usr/local/bin:/opt/homebrew/bin:$PATH
62+
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/opt/homebrew/lib/pkgconfig:/opt/homebrew/share/pkgconfig:/usr/local/opt/icu4c@78/lib/pkgconfig:/opt/homebrew/opt/icu4c@78/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig:/opt/homebrew/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH
63+
# macOS: install dependencies via Homebrew
64+
CIBW_BEFORE_ALL_MACOS: "brew install mapnik icu4c pkg-config boost gdal proj harfbuzz libx11 xorgproto libxext libxrender libxau libxdmcp xtrans"
65+
# macOS: set up build environment
66+
CIBW_BEFORE_BUILD_MACOS: |
67+
eval $(brew shellenv)
68+
HOMEBREW_PREFIX=$(brew --prefix)
69+
ICU4C_PREFIX=$(brew --prefix icu4c)
70+
BOOST_PREFIX=$(brew --prefix boost)
71+
GDAL_PREFIX=$(brew --prefix gdal)
72+
PROJ_PREFIX=$(brew --prefix proj)
73+
HARFBUZZ_PREFIX=$(brew --prefix harfbuzz)
74+
XORGPROTO_PREFIX=$(brew --prefix xorgproto)
75+
LIBX11_PREFIX=$(brew --prefix libx11)
76+
LIBXEXT_PREFIX=$(brew --prefix libxext)
77+
LIBXRENDER_PREFIX=$(brew --prefix libxrender)
78+
LIBXAU_PREFIX=$(brew --prefix libxau)
79+
LIBXDMCP_PREFIX=$(brew --prefix libxdmcp)
80+
XTRANS_PREFIX=$(brew --prefix xtrans)
81+
XORGPROTO_PKGCONFIG_DIR=$(find "$HOMEBREW_PREFIX/Cellar/xorgproto" -type d -name "pkgconfig" 2>/dev/null | head -1)
82+
[ -z "$XORGPROTO_PKGCONFIG_DIR" ] && XORGPROTO_PKGCONFIG_DIR="$XORGPROTO_PREFIX/share/pkgconfig"
83+
export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/lib/pkgconfig:$HOMEBREW_PREFIX/share/pkgconfig:$ICU4C_PREFIX/lib/pkgconfig:$GDAL_PREFIX/lib/pkgconfig:$PROJ_PREFIX/lib/pkgconfig:$HARFBUZZ_PREFIX/lib/pkgconfig:$LIBX11_PREFIX/lib/pkgconfig:$LIBXEXT_PREFIX/lib/pkgconfig:$LIBXRENDER_PREFIX/lib/pkgconfig:$LIBXAU_PREFIX/lib/pkgconfig:$LIBXDMCP_PREFIX/lib/pkgconfig:$XTRANS_PREFIX/share/pkgconfig:$XORGPROTO_PKGCONFIG_DIR:$XORGPROTO_PREFIX/share/pkgconfig:$XORGPROTO_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH"
84+
export CXXFLAGS="-I$BOOST_PREFIX/include -I$GDAL_PREFIX/include -I$PROJ_PREFIX/include -I$HARFBUZZ_PREFIX/include $CXXFLAGS"
85+
export LDFLAGS="-L$BOOST_PREFIX/lib -L$GDAL_PREFIX/lib -L$PROJ_PREFIX/lib -L$HARFBUZZ_PREFIX/lib $LDFLAGS"
5686
run: |
5787
cibuildwheel --output-dir wheelhouse
5888
@@ -63,40 +93,14 @@ jobs:
6393
path: wheelhouse/*.whl
6494
retention-days: 7
6595

66-
build-sdist:
67-
needs: [extract-version]
68-
runs-on: ubuntu-latest
69-
permissions:
70-
contents: write
71-
steps:
72-
- name: Checkout code
73-
uses: actions/checkout@v6
74-
with:
75-
submodules: recursive
76-
77-
- name: Install uv
78-
uses: astral-sh/setup-uv@v7
79-
80-
- name: Build sdist
81-
run: |
82-
uv build --sdist
83-
84-
- name: Upload sdist
85-
uses: actions/upload-artifact@v4
86-
with:
87-
name: sdist
88-
path: dist/*.tar.gz
89-
retention-days: 7
90-
9196
release:
9297
needs:
9398
- extract-version
9499
- build-wheels
95-
- build-sdist
96100
runs-on: ubuntu-latest
97101
permissions:
98102
contents: write
99-
if: github.event_name == 'push'
103+
if: (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || github.event_name == 'workflow_dispatch'
100104

101105
steps:
102106
- name: Download all artifacts
@@ -117,6 +121,7 @@ jobs:
117121
- name: Create GitHub Release
118122
uses: softprops/action-gh-release@v2
119123
with:
124+
token: ${{ secrets.GITHUB_TOKEN }}
120125
tag_name: ${{ needs.extract-version.outputs.version }}
121126
name: Release ${{ needs.extract-version.outputs.version }}
122127
body: |
@@ -152,8 +157,6 @@ jobs:
152157
dist/*.tar.gz
153158
draft: false
154159
prerelease: false
155-
env:
156-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
157160

158161
- name: Summary
159162
run: |

0 commit comments

Comments
 (0)