Skip to content

Commit b9c8f72

Browse files
committed
ci: build wheel
1 parent e613828 commit b9c8f72

5 files changed

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

0 commit comments

Comments
 (0)