@@ -5,12 +5,51 @@ load("//omd/packages/Python:version.bzl", "PYTHON_MAJOR_DOT_MINOR")
55
66def get_pip_options (module_name ):
77 return {
8+ # matplotlib's meson build defaults to downloading and building its own vendored
9+ # freetype as a subproject, which requires network access at build time.
10+ # Use the system library instead, which is already provided by the build image.
11+ # qhull and libraqm are left vendored (system-qhull/system-libraqm are NOT
12+ # set): our build images don't provide a usable libqhull_r, and ship
13+ # libraqm 0.10.1, older than the >=0.10.4 matplotlib requires. Their sources
14+ # (and harfbuzz/sheenbidi) are instead seeded offline, see get_extra_setup().
15+ "matplotlib" : '--config-settings=setup-args="-Dsystem-freetype=true"' ,
16+
817 # * avoid compiling with BLAS support - we don't need super fast numpy (yet)
918 "numpy" : '--config-settings=setup-args="-Dallow-noblas=true"' ,
1019 # pillow in version 11.2 and above would require libavif>=1.0.0 which is per default not available on debian-12, see https://github.com/radarhere/Pillow/commit/7d50816f0a6e607b04f9bdc8af7482a29ba578e3 and as we don't need avif support, we simply disable it
1120 "pillow" : "--config-settings=avif=disable" ,
1221 }.get (module_name , "" )
1322
23+ def get_extra_setup (module_name ):
24+ """Shell snippet executed right before `pip install`.
25+
26+ Used to seed a local meson subproject package cache (MESON_PACKAGE_CACHE_DIR)
27+ so meson resolves vendored C deps from disk instead of downloading them at
28+ build time. The Bazel-fetched srcs referenced here must be added to that
29+ module's `srcs` in the calling BUILD file.
30+ """
31+ return {
32+ "matplotlib" : """
33+ # meson runs harfbuzz's gen-hb-version.py through its
34+ # "#!/usr/bin/env python3" shebang. LD_LIBRARY_PATH (see build_cmd) puts
35+ # our bundled Python's lib dir first, so a system python3 that links
36+ # libpython dynamically -- sles-16.0 does, with a colliding 3.13 soname --
37+ # loads the wrong libpython and aborts before running the script. Resolve
38+ # python3 to the interpreter LD_LIBRARY_PATH already matches.
39+ export PATH="$$(dirname "$$PYTHON_EXECUTABLE"):$$PATH"
40+ # Build in a private, guaranteed-writable/empty TMPDIR instead of the shared
41+ # host /tmp: pip/meson-python stage the harfbuzz/libraqm/etc.
42+ export TMPDIR="$$HOME/tmp_matplotlib"
43+ mkdir -p "$$TMPDIR"
44+ export MESON_PACKAGE_CACHE_DIR="$$HOME/mpl_packagecache"
45+ mkdir -p "$$MESON_PACKAGE_CACHE_DIR"
46+ cp "$(execpath @matplotlib_harfbuzz_src//file)" "$$MESON_PACKAGE_CACHE_DIR/harfbuzz-14.1.0.tar.xz"
47+ cp "$(execpath @matplotlib_sheenbidi_src//file)" "$$MESON_PACKAGE_CACHE_DIR/sheenbidi-3.0.0.tar.gz"
48+ cp "$(execpath @matplotlib_libraqm_src//file)" "$$MESON_PACKAGE_CACHE_DIR/libraqm-0.10.5.tar.gz"
49+ cp "$(execpath @matplotlib_qhull_src//file)" "$$MESON_PACKAGE_CACHE_DIR/qhull-8.0.2.tgz"
50+ """ ,
51+ }.get (module_name , "" )
52+
1453def create_requirements_file (name , outs ):
1554 """This macro is creating a requirements file per module.
1655 """
@@ -31,6 +70,7 @@ def build_python_module(name, srcs, outs, requirements = "", **kwargs):
3170 openssl_dir = Label ("@openssl" ).repo_name
3271 freetds_dir = Label ("@freetds" ).repo_name
3372 python_dir = Label ("@python" ).repo_name
73+ extra_setup = get_extra_setup (name )
3474 native .genrule (
3575 name = name + "_compile" ,
3676 srcs = srcs ,
@@ -45,6 +85,7 @@ def build_python_module(name, srcs, outs, requirements = "", **kwargs):
4585 pyMajMin = PYTHON_MAJOR_DOT_MINOR ,
4686 requirements = requirements ,
4787 constraints = constraints ,
88+ extra_setup = extra_setup ,
4889 openssl_dir = openssl_dir ,
4990 freetds_dir = freetds_dir ,
5091 python_dir = python_dir ,
@@ -54,6 +95,7 @@ def build_python_module(name, srcs, outs, requirements = "", **kwargs):
5495 pyMajMin = PYTHON_MAJOR_DOT_MINOR ,
5596 requirements = requirements ,
5697 constraints = constraints ,
98+ extra_setup = extra_setup ,
5799 openssl_dir = openssl_dir ,
58100 freetds_dir = freetds_dir ,
59101 python_dir = python_dir ,
@@ -148,6 +190,7 @@ build_cmd = """
148190 export CFLAGS="-Wno-error=incompatible-pointer-types -ffile-prefix-map=$$HOME=."
149191 export CPPFLAGS="-I$$HOME/$$EXT_DEPS_PATH/{openssl_dir}/openssl/include -I$$HOME/$$EXT_DEPS_PATH/{freetds_dir}/freetds/include -I$$HOME/$$EXT_DEPS_PATH/{python_dir}/python/include/python{pyMajMin}/"
150192 export LDFLAGS="-L$$HOME/$$EXT_DEPS_PATH/{openssl_dir}/openssl/lib -L$$HOME/$$EXT_DEPS_PATH/{freetds_dir}/freetds/lib -L$$HOME/$$EXT_DEPS_PATH/{python_dir}/python/lib -Wl,--strip-debug"
193+ {extra_setup}
151194 {git_ssl_no_verify}\\
152195 $$PYTHON_EXECUTABLE -m pip install \\
153196 `: dont use precompiled things, build with our build env ` \\
@@ -163,7 +206,20 @@ build_cmd = """
163206 --use-feature=build-constraint \\
164207 --build-constraint="{constraints}" \\
165208 --prefix="$$HOME/$$MODULE_NAME" \\
166- {requirements} 2>&1 | tee "$$HOME/""$$MODULE_NAME""_pip_install.stdout"
209+ {requirements} 2>&1 | tee "$$HOME/""$$MODULE_NAME""_pip_install.stdout" || true
210+ # The `|| true` above keeps `set -e` from aborting on pip's exit code before
211+ # we get a chance to inspect PIPESTATUS and dump diagnostics below.
212+ PIP_INSTALL_STATUS=$${{PIPESTATUS[0]}}
213+ if [ "$$PIP_INSTALL_STATUS" -ne 0 ]; then
214+ # pip/meson swallow the actual subprocess output on failure and only point
215+ # to a meson-log.txt buried in the (ephemeral) sandbox tmpdir -- e.g. the
216+ # harfbuzz subproject build inside matplotlib's meson-python backend just
217+ # reports "failed with status 1" with no further detail in the CI console.
218+ # Dump any such log here so the real traceback survives into the CI log.
219+ echo "pip install for $$MODULE_NAME failed (exit $$PIP_INSTALL_STATUS); dumping any meson-log.txt found under TMPDIR:"
220+ find "$$TMPDIR" -name meson-log.txt -print -exec cat {{}} \\ ; 2>/dev/null
221+ exit "$$PIP_INSTALL_STATUS"
222+ fi
167223
168224 tar cf $@ -C $$MODULE_NAME .
169225"""
0 commit comments