Skip to content

Commit 70f400a

Browse files
committed
ci: build wheel
1 parent e613828 commit 70f400a

5 files changed

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

0 commit comments

Comments
 (0)