Skip to content

ENH: add a pkg-config file and a numpy-config script #25730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 31, 2024

Conversation

rgommers
Copy link
Member

@rgommers rgommers commented Jan 31, 2024

This will make it much easier to support getting at the location for headers and to support using numpy as a dependency in downstream build config files. It should enable removing the complexity of importing numpy and parsing the output of calling np.get_include and co. manually. Instead, things should work transparently with (in the Meson case): dependency('numpy'). CMake is also able to consume pkg-config files and/or a config tool.

Note that the numpy.pc file may or may not be installable in the standard location expected by pkg-config. By default in a wheel it isn't; distros are in principle able to target the correct location (however, no flag to do so is added here, it can be done by hand only right now).

The advantage of the numpy-config tool is that it goes into the scripts directory (i.e., site-packages/bin) and hence is always available. The advantage of the pkg-config file is that it works without running Python, and hence is better for cross-compiling.

Support for getting at the numpy/f2py/src directory isn't included here, because that isn't a regular include directory but rather includes a source file. And hence a compile arg -I/path/to/numpy/f2py/src is not enough. How to better support that requires some more thought. In its current form, this should already help most packages using the NumPy C API.

The numpy.pc file can be used with Meson directly, without needing an upstream change. To do so, try:

$ export PKG_CONFIG_PATH=$(numpy-config --pkgconfigdir)
$ numpy-config --version
2.0.0.dev0+git20240126.3e7b299
$ numpy-config --cflags
-I/home/rgommers/mambaforge/envs/scipy-dev/lib/python3.10/site-packages/numpy/_core/include

To add numpy-config support to Meson does require an upstream change, but it's a straightforward ~12 LoC diff: https://github.com/mesonbuild/meson/compare/master...rgommers:meson:add-numpy-dependency?expand=1

I wanted to get this in for 2.0.0, since that may be the lowest supported version for quite a while. Having this in will allow most downstream projects to drop their verbose handling of NumPy include paths completely.

@eli-schwartz maybe you want to have a look at this?

Copy link

@eli-schwartz eli-schwartz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something interesting that pybind11 does is support installing to the system includedir.

# -------------------------

# Note: we can't use Meson's built-in pkgconfig module, because we have to
# install numpy.pc within site-packages rather than in its normal location.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically not true because you can tell pkgconfig.generate() to use a specific install_dir.

Note that in order to handle relocatable wheels you'd then still want to define pkgconfig.relocatable=true inside cibuildwheel and then calculating it as offset from the wheel root instead of /usr would be a bit interesting to negotiate, because no one has actually tried to account for pkg-config files plus headers installed to something that isn't actually the --prefix. Hence it assumes that it needs to relativize everything based on prefix in order to recurse back down to includedir.

So you may prefer configure_file but not for the reasons this comment suggests. Or you may wish to propose changes to the pkgconfig module too. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hence it assumes that it needs to relativize everything based on prefix in order to recurse back down to includedir.

Indeed. I did try to use pkgconfig.generate(), the problem is that there is no way to tell it where the include dir is.

Or you may wish to propose changes to the pkgconfig module too.

There's two things indeed:

  • the docs assume that a library is the first input, it's unclear that header-only support is actually working
  • includedir is now actually a reserved variable; to make this work that restriction should be dropped or a new keyword to set the include dir relative to the install dir should be added.

@mattip
Copy link
Member

mattip commented Jan 31, 2024

Something interesting that pybind11 does is support installing to the system includedir.

This is simpler (advantage) but possibly pollutes the include directory and makes updating/removing more compicated (disadvantage). It also get confusing when that system includedir is managed by the operating system package manager (disadvantage).

@rgommers
Copy link
Member Author

Something interesting that pybind11 does is support installing to the system includedir.

I'd be interested in doing this as a follow-up perhaps. The complication though is that it only makes sense I think if we install the headers to <prefix>/include/numpy, and I'm not sure that the headers are current robust against being placed outside of site-packages.

@rgommers
Copy link
Member Author

@mattip that's true for wheels installed by the user (and hence it can never be the default), but it doesn't quite apply to distro packaging. Distros that only ship one Python version (and hence one NumPy version) may prefer to have things in the standard lib/include directories.

@eli-schwartz
Copy link

@mattip that's true for wheels installed by the user (and hence it can never be the default), but it doesn't quite apply to distro packaging. Distros that only ship one Python version (and hence one NumPy version) may prefer to have things in the standard lib/include directories.

Not even.

Gentoo allows multiple python versions and your choice of numpy versions, but only one numpy version can be installed at a time (and will be installed for all python versions you ask for).

For a set of static headers there is no reason they have to be installed multiple times. The only reason they are installed multiple times if installed to site-packages is as a side effect of making it easier to pip install some non-python content. But if they can be merged then there are potential space savings.

(It's not a significant savings, I'll grant you that.)

@rgommers
Copy link
Member Author

For a set of static headers there is no reason they have to be installed multiple times.

Good point. However, we do have generated headers as well, and some of their contents may not only be platform-dependent but also depend on Python.h content (I'm not certain that's the case for anything publicly accessible, but I've certainly seen logic like "if HAVE_xxx not already defined by Python, then define it ourselves).

This will make it much easier to support getting at the location
for headers and to support using numpy as a dependency in downstream
build config files. It should enable removing the complexity of
importing numpy and parsing the output of calling `np.get_include` and
co manually. Instead, things should work transparently with (in the
Meson case): `dependency('numpy')`. CMake is also able to consume
pkg-config files and/or a config tool.

Note that the `numpy.pc` file may or may not be installable in the
standard location expected by pkg-config. By default in a wheel it
isn't; distros are in principle able to target the correct location
(however, no flag to do so is added here, it can be done by hand only
right now).

The advantage of the `numpy-config` tool is that it goes into the
scripts directory (i.e., `site-packages/bin`) and hence is always
available. The advantage of the pkg-config file is that it works without
running Python, and hence is better for cross-compiling.

Support for getting at the numpy/f2py/src directory isn't included here,
because that isn't a regular include directory but rather includes
a source file. And hence a compile arg `-I/path/to/numpy/f2py/src`
is not enough. How to better support that requires some more thought.
In its current form, this should already help most packages using the
NumPy C API.
@eli-schwartz
Copy link

For a set of static headers there is no reason they have to be installed multiple times.

Good point. However, we do have generated headers as well, and some of their contents may not only be platform-dependent but also depend on Python.h content (I'm not certain that's the case for anything publicly accessible, but I've certainly seen logic like "if HAVE_xxx not already defined by Python, then define it ourselves).

And to close the loop on the pybind11 comparison, pybind11 doesn't generate headers -- if it does care about the python version it does it in the preprocessor and not in a generator script that creates headers at build time.

@mattip
Copy link
Member

mattip commented Jan 31, 2024

LGTM, thanks @rgommers. Let's put this in as-is, we can iterate on it as we see how it works with downstream projects.

@mattip mattip merged commit 2634f80 into numpy:main Jan 31, 2024
@rgommers rgommers deleted the configtool branch January 31, 2024 17:37
@rgommers
Copy link
Member Author

Thanks for the quick reviews & merge. On to a Meson PR to now use this:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants