BUG: meson fails to properly detect numpy, pybind11 and (sort of) pythran when cross compiling
See original GitHub issueThe new dependency detection in scipy/meson.build
works suitably for native builds of SciPy, but does not correctly detect build-arch dependencies for cross compilation. The meson rules invoke the host Python interpreter, there called py3
, to import the numpy
, pybind11
and pythran
packages (all installed for the host arch) and deduce the proper paths for includes and, in the case of NumPy, infer a search path for the npymath
and npyrandom
libraries.
NOTE: the Pythran search is incorrect but doesn’t really cause a problem because the it is only used on the host to render files; the include path returned by the problematic search is never referenced by any subsequent meson build logic. The entire
incdir_pythran
block could be removed without adverse effects.
If the requisite dependencies are installed for the host arch (whether or not they are also installed for the build arch), the detection will return paths for the host arch, which might cause subtle problems in header files and fails outright when the linker attempts to link object files for the build arch with the native npymath
or npyrandom
libraries. If the dependencies are installed only for the build arch, the interpreter will fail entirely and meson will never even configure the build.
Resolution attempts
I have tried a couple simple workarounds, to no avail:
- Install only the dependencies only for the build arch. On Void Linux, we set a lot of environment variables to tell the host Python to use the sysconfig data for the build arch and also add the build root to
PYTHONPATH
, allowing the host Python to find these modules and grabbing relevant information (field sizes, shlib suffixes, etc.) for the build arch rather than the host. This would work with the existing meson detection forpybind11
andpythran
, but does not work fornumpy
becauseimport numpy
triggers a bunch of shared object loads and the build arch libraries are incompatible with the host. (A more targeted import, such asfrom numpy.__config__ import get_include
, might work in this situation, but I haven’t bothered to try.) - Install dependencies for host and build arches, use the detection to find paths to the host, but then manually prepend the build root to the returned paths. This almost works on Void Linux because we install packages for the build arch under a
/usr/<triple>
prefix that otherwise mirrors the native layout. In generally, most of the compilation commands include the right-I
flags to find headers for the build arch. However, some commands still include paths to the host interpreter, and thefind_library
calls to identifynpymath
andnpyrandom
somehow still pick up the host versions and trigger a linker failure. I don’t know enough about how meson sets the Python environment when searching for it to understand how these host paths are creeping in or whyfind_library
still seems to prefer the host paths even though I add the correct paths to the search paths in that function. (I wouldn’t really expectfind_library
to dig into the numpy tree to find the libraries, so it seems an additional search path is creeping in before I add one explicitly.)
Possible fixes
Although I’m speculating, it seems a few approaches could be taken to resolve this issue, in order of decreasing “niceness”:
- Convince
numpy
(and, probably,pybind11
) to ship pkg-config files. This is probably desirable, was mentioned in the [related meson issue], and sidesteps a lot of problems. The trouble withpybind11
is that it wants to be entirely self-contained within the Python package tree; however, even if it ships a.pc
file within its package tree instead of in a system-specific path, Void can probably work around the issue with relative ease. (Void already wraps pkg-config for cross builds so that it loads descriptors for the build arch and manipulates the paths appropriately.) The determination forpythran
should just be dropped altogether (also, rather than invoking a Python interpreter to readSCIPY_USE_PYTHRAN
from the environment, Pythran should just be a meson build option). The trouble here is backwards compatibility; if SciPy will build with old versions of NumPy or pybind11, it will still need fallback detection. Hence… - Existing logic can be improved, even if only as a fallback for older versions of dependencies. I’m not sure what this should look like, but reading variables from the environment might make sense (e.g.,
NUMPY_ROOT
,PYBIND11_INCLUDE_DIR
); when these variables are defined, they are used as-is; otherwise, the existing interpreter invocations can provide sensible defaults for native builds. Of course, this assumes thatfind_library
can be made to find NumPy libraries for the build arch even though it now prefers the host versions. - The existing search for a Python interpreter could allow a custom path rather than always using the default, which seems to be the same interpreter that is running meson. This might allow some clever wrapping of the interpreter but is probably an incomplete (and maybe completely ineffective) solution. For example, no amount of sensible wrapping will allow
print(numpy.get_include())
to dump some modified path; however, a successfulfrom numpy.__config__ import get_include
using the build-arch NumPy might make this workable if ugly.
Related issue
This issue was opened in response to https://github.com/mesonbuild/meson/issues/9598#issuecomment-1201475862 as a means to track SciPy specifics and provide a link target for inclusion in https://github.com/scipy/scipy/issues/14812.
cc: @rgommers
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:24 (14 by maintainers)
I wouldn’t say there aren’t places where you can use it (
pybind11_global
does use it!), but it’s somewhat discouraged due to the ability to do exactly what it was supposed to do - install to any arbitrary place at the root of your python environment - which includes/
if you are not in a venv. That’s why we have a “safe”pybind11
package and a “you know what you are doing”pybind11_global
package.I think different people have different ideas of what it should mean, probably.
For example, I would consider the data directory an officially sanctioned method for messing with the base system on the grounds that it is my desire to mess with the base system.
Obviously,
pip install package
installs things outside of site-packages and people are okay with this, becauseconsole_scripts
is installed outside of site-packages. It’s just installed to the “scripts” directory instead of the “data” directory, so it’s arbitrarily declared to be acceptable to install to the scripts directory specifically. After all, scripts are really common. Common enough that I supposebrew doctor
doesn’t consider it something to complain about.