8000 ENH: BLD: enable building SciPy with Meson by rgommers · Pull Request #14847 · scipy/scipy · GitHub
[go: up one dir, main page]

Skip to content

ENH: BLD: enable building SciPy with Meson #14847

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 33 commits into from
Dec 29, 2021
Merged

Conversation

rgommers
Copy link
Member
@rgommers rgommers commented Oct 12, 2021

This PR adds:

  • support for building SciPy with Meson on Linux and macOS
  • a single CI job, Python 3.9 on Linux, which builds with -Werror.
  • documentation on using Meson, as well as using act for running that job locally

As I explained in #13615 (comment), having the -Werror build merged into SciPy master will be valuable, because new build warnings will keep leaking in without CI (and it took a lot of effort to get to zero warnings).

I personally also want to develop on SciPy with Meson - it's far faster and more pleasant to use than the distutils-based build. I imagine some other maintainers may want to do this too.

There is enough left to do after this PR. In order of importance: Windows builds (EDIT: works now), non-OpenBLAS BLAS/LAPACK support, a more polished dev.py interface (similar to runtests.py) (EDIT: could be improved, but now has parity with runtests.py at least), and sdist/wheel generation (see the tracking issue).

I have completely rewritten the history of the meson integration branch in my fork, to have one commit per submodule or other tool/topic. I have carefully added other contributors as authors or co-authors (if I forgot anyone, please comment or ping me!), namely: @czgdp1807, @Smit-create, @HarshCasper, @matthew-brett and @dhruv9vats.

Right now the Meson version needed is 0.60.0rc1, or master (EDIT: all 0.60.x releases and master work now). This is pinned in environment_meson.yml. I have 8000 not included pyproject.toml or other changes, so this should not interfere with the regular setup.py based build or release process.

Once we merge this, I volunteer to resolve issues people may have with adding support, in case they are making changes in a setup.py file and then find that the Meson CI job doesn't pass. This should be very little work.

There are also improvements in here, like the CI caching and enabling the use of act, which we should sync to the other CI jobs because they're generally useful. But that's left for later, to not have any cross-talk with other PRs - this PR is Meson-only as much as possible.

For more context see:

@rgommers rgommers added enhancement A new feature or improvement Build issues Issues with building from source, including different choices of architecture, compilers and OS CI Items related to the CI tools such as CircleCI, GitHub Actions or Azure labels Oct 12, 2021
@eli-schwartz
Copy link
Contributor

Nice work!

@andyfaff
Copy link
Contributor

Exciting times! Thank you for this vital infra work @rgommers

@WarrenWeckesser
Copy link
Member

Thanks Ralf!

@WarrenWeckesser
Copy link
Member

Does the new build system provide a "smart" build+install yet, where I can edit, say scipy/special/_convex_analysis.pxd, issue a command that rebuilds based on only the changed files (i.e. like a true make command), and updates the installation?

@mckib2
Copy link
Contributor
mckib2 commented Dec 30, 2021

Does the new build system provide a "smart" build+install yet, where I can edit, say scipy/special/_convex_analysis.pxd, issue a command that rebuilds based on only the changed files (i.e. like a true make command), and updates the installation?

Yes, ninja does that intelligently and rebuilds only the subset of files+dependencies required

@WarrenWeckesser
Copy link
Member

If I'm reading the output correctly, it looks like the change is detected, but the .so files in the installation directory are not updated. I'll keeping poking, and if I can't figure it out (or find the reason in the docs), I'll open a new issue.

@eli-schwartz
Copy link
Contributor

meson install should update all files in the installation directory (after running ninja to make sure they are built and up to date in the build directory).

While you can pass --only-changed to meson install and skip updating files in the installation directory if they weren't rebuilt anyway, it does not sound like you used that option...

@WarrenWeckesser
Copy link
Member

I suspect what I am seeing is mesonbuild/meson#9049

@eli-schwartz
Copy link
Contributor

In that case, the change is NOT detected?

@WarrenWeckesser
Copy link
Member

Perhaps I misunderstood that issue; I'm also not up-to-date on any workarounds that are in the meson.build files, or on meson itself. Currently, I'm just a user who hasn't RTFM, hoping that https://github.com/scipy/scipy/blob/master/doc/source/dev/contributor/meson.rst is enough to get me going. Here's what I did.

First, I removed the build directory, and ran

python dev.py -t scipy.special.tests.test_basic::test_pseudo_huber_small_r

(That's a new test that I'm adding--it is not in the master branch.)
That does a complete build and install, and runs the specific test given. The result was as expected.

Then I changed scipy/special/_convex_analysis.pxd in a way that should make the test fail. But when I reran dev.py, the test still passed:

(scipy-meson) warren@pop-os:~/repos/git/forks/scipy$ python dev.py -t scipy.special.tests.test_basic::test_pseudo_huber_small_r
ninja: Entering directory `build'
[3/3] Generating scipy/generate-config with a custom command
Build OK
Installing, see meson-install.log...
Installation OK
Running tests for scipy version:1.9.0.dev0+1185.3fb6ba1, installed at:/home/warren/repos/git/forks/scipy/installdir/lib/python3.10/site-packages/scipy
========================================= test session starts ==========================================
platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /home/warren/repos/git/forks/scipy, configfile: pytest.ini
plugins: forked-1.4.0, xdist-2.5.0, cov-3.0.0
collected 1 item                                                                                       

scipy/special/tests/test_basic.py .                                                              [100%]

========================================== 1 passed in 1.32s ===========================================

When I ran the command again, with no additional changes, the output that was [3/3] changed to [2/2]. That difference is what I interpreted as the change being detected. (Is that a count of changed dependencies?)

(scipy-meson) warren@pop-os:~/repos/git/forks/scipy$ python dev.py -t scipy.special.tests.test_basic::test_pseudo_huber_small_r
ninja: Entering directory `build'
[2/2] Generating scipy/generate-config with a custom command
Build OK
Installing, see meson-install.log...
Installation OK
Running tests for scipy version:1.9.0.dev0+1185.3fb6ba1, installed at:/home/warren/repos/git/forks/scipy/installdir/lib/python3.10/site-packages/scipy
========================================= test session starts ==========================================
platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /home/warren/repos/git/forks/scipy, configfile: pytest.ini
plugins: forked-1.4.0, xdist-2.5.0, cov-3.0.0
collected 1 item                                                                                       

scipy/special/tests/test_basic.py .                                                              [100%]

========================================== 1 passed in 1.32s ===========================================

I've checked the timestamps on the .so files in the installation directory before and after editing _convex_analysis.pxd and running dev.py, and they haven't changed.

@rgommers
Copy link
Member Author

Thanks everyone!

@WarrenWeckesser yes indeed, that's mesonbuild/meson#9049. Dependency tracking of .pxd/.pxi files is not working correctly right now. We need to go fix that by adding depfile support in Cython. I have updated this in the tracking issue for Meson support (rgommers#22).

We touch .pxd files very rarely, so I didn't consider this a blocker. It's an annoying catch though right now.

@rgommers
Copy link
Member Author
rgommers commented Dec 30, 2021

I think in total we have 3 known issues:

  • 2 to be added as new features to Cython (depfile support, and adding --name input to fix the flakes with generated Cython source files)
  • 1 to be improved in Meson (virtualenv handling, and in particular something is weird on Debian).

Those are highest priority to work on. After that, we can deal with supporting other BLAS/LAPACK libraries, cross-compiling, and then switching over sdist/wheel generation.

@ev-br
Copy link
Member
ev-br commented Dec 30, 2021

With pxd/pxi mess, I'd mention a workaround (suggested by Ralf a while ago) which works today: use a two-step incantation in meson.build and set depend_files:

https://github.com/ev-br/mc_lib/blob/master/mc_lib/meson.build#L23

@andyfaff
Copy link
Contributor

then switching over sdist/wheel generation.

Is it currently possible to make a wheel with meson?

@eli-schwartz
Copy link
Contributor
eli-schwartz commented Dec 31, 2021

This is currently handled by https://pypi.org/project/mesonpep517/ which handles the pep 517 build backend and creates the dist-info metadata.

Meson could grow direct support, and we want to add it, but it's not perfectly clear how to. Part of the problem is that we probably need a toml parser, but the python steering council seems to be hesitant to add one to the stdlib despite it being a core requirement of the metadata specs, required for basically any part of the packaging ecosystem, a stable spec for a while now (which was the original explanation for why a toml module was not added years ago -- "we will, but first we want to release a toml 1.0 spec") and currently being vendored into pip, setuptools, flit, etc because it is a PEP violation (bootstrap cycle) to require flit to build tomli, and have flit depend on tomli, while pip and setuptools meanwhile have a "vendor everything because we cannot have dependencies" policy.

Meson has a "only stdlib, we do not vendor and we do not add dependencies either" policy. This is needed because we are being used as a low level tool for bootstrapping operating systems, and it needs to be easy to run meson with nothing but a python interpreter.

So, mesonpep517 is where people are testing out "wheel creation based on meson". It can require dependencies like a toml library, and once the ecosystem coalesces we may be able to merge mesonpep517 directly into meson, or use the experience and lessons of that project to design another API.

tl;dr Let's see where the future takes us.

@andyfaff
Copy link
Contributor

Thanks for the response. Ive been thinking about experimenting with cibuildwheel for how we build scipy wheels, but it seems like it's too early at this point?

@astrojuanlu
Copy link
Contributor

Notice that there is already consensus on including tomli in the stdlib, just a PEP is missing https://discuss.python.org/t/adopting-recommending-a-toml-parser/4068/84?u=astrojuanlu

@rgommers
Copy link
Member Author
rgommers commented Jan 1, 2022

Is it currently possible to make a wheel with meson?

Yes it is, however (a) you need a patch, and (b) it's not tested yet so you may run into various sharp edges.

Building a wheel will not be too difficult in the future, with either mesonpep517 or meson-python. So I'd say it's fine to start playing with cibuildwheel. NumPy also merged cibuildwheel support recently (not yet used for the 1.22.0 release).

Here's the easiest way to get a wheel to build that you can install locally (note that it won't be manylinux compliant etc., so not suitable for redistribution - but fine for use in the env in which you built it), if you want to try:

  1. Install mesonpep517: pip install git+https://gitlab.com/thiblahute/mesonpep517.git
  2. Install pypa/build: pip install build
  3. Apply the below diff
  4. Build a wheel: python -m build --wheel --no-isolation --skip-dependency-check
  5. Install the wheel: pip install dist/SciPy-1.9.0.dev0*.whl
  6. Run the tests: cd doc && python -c "import scipy; scipy.test()"
diff --git a/pyproject.toml b/pyproject.toml
index d3a01ecfe..546c965d1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,8 +8,10 @@
 #     "pybind11>=2.4.3,<2.5.0",
 
 [build-system]
+build-backend = "mesonpep517.buildapi"
 requires = [
     "wheel",
+    "mesonpep517",
     "setuptools<60.0",  # do not increase, 60.0 enables vendored distutils
     "Cython>=0.29.18",
     "pybind11>=2.4.3",
@@ -45,7 +47,7 @@ requires = [
 [project]
 name = "SciPy"
 license = {file = "LICENSE.txt"}
-
+version = "1.9.0.dev0"
 maintainers = [
     {name = "SciPy Developers", email = "scipy-dev@python.org"},
 ]
@@ -76,7 +78,6 @@ classifiers = [
     "Operating System :: Unix",
     "Operating System :: MacOS",
 ]
-dynamic = ['version', 'description']
 
 [project.optional-dependencies]
 test = [
@@ -109,3 +110,8 @@ documentation = "https://docs.scipy.org/doc/scipy/"
 source = "https://github.com/scipy/scipy"
 download = "https://github.com/scipy/scipy/releases"
 tracker = "https://github.com/scipy/scipy/issues"
+
+[tool.mesonpep517.metadata]
+name = 'scipy'
+version = '1.9.0.dev0'
+

I gave this a quick spin on Linux, and that does work. It should work cross-platform, and in conda envs too. As you can see from the commands, there's some things to fix UX-wise.

Meson could grow direct support, and we want to add it, but it's not perfectly clear how to.

I t 8000 hink it should require a separate package in the end, but ideally under the Meson org. A simple "zip up the result of meson install and add metadata" could live in Meson, but I think that things like dealing with things like post-processing the result of meson install with auditwheel, delocate etc. to ensure the various manylinux standards are met is probably a bit too involved and Python-specific to bore Meson maintainers who are not involved in Python packaging with.

@eli-schwartz
Copy link
Contributor

Notice that there is already consensus on including tomli in the stdlib, just a PEP is missing

"Consensus that it's okay to propose it in a PEP" != "consensus to add it", and the larger issue here is that the topic has been carefully bikeshedded on multiple fronts for multiple years for something that should not be permitted to be missing. :)

I hope it will happen, but I won't believe it until I see it.

A simple "zip up the result of meson install and add metadata" could live in Meson, but I think that things like dealing with things like post-processing the result of meson install with auditwheel, delocate etc. to ensure the various manylinux standards are met is probably a bit too involved and Python-specific to bore Meson maintainers who are not involved in Python packaging with.

I didn't think that meson should handle that.

setuptools via setup.py doesn't handle it either, if I understand correctly? Aren't these both command-line tools run after you have a wheel and want to convert "a wheel" to "a manylinuxed wheel" (or a macOS I-dont-know-what-to-call-it wheel)? It's definitely not something you want to run for any reason other than "I'm uploading a PyPI release for a project I maintain".

(It would be trivial to add a run_target() as a maintainer command to do this though.)

@rgommers
Copy link
Member Author
rgommers commented Jan 2, 2022

setuptools via setup.py doesn't handle it either, if I understand correctly? Aren't these both command-line tools run after you have a wheel and want to convert "a wheel" to "a manylinuxed wheel" (or a macOS I-dont-know-what-to-call-it wheel)?

correct, 2x. but, see below

It's definitely not something you want to run for any reason other than "I'm uploading a PyPI release for a project I maintain".

I agree. Unfortunately, the Python packaging crowd needs some educating/convincing there. Some of the design of pyproject.toml has gone in the direction that everything must match PyPI-wheels, because "what if I build a wheel locally, it ends up in cache, and now when I do pip install somepkg the cached result doesn't match the PyPI wheel and that may cause runtime issues". Which is theoretically possible of course, but it's a small concern in the big picture of things. I suspect >95% of people who type pip install . want the built wheel to use and match the environment that they're building in - but that's not what you're getting.

@eli-schwartz
Copy link
Contributor

That sounds like a truly concerning case, even more concerning than doing pip install . after locally editing some files and... Wait a minute.

Why is the PyPI wheel relevant at all, if you never use it? And if you do use it, then building from source is irrelevant. And even if you did care about making them the same, auditwheel repair won't help!!! It explicitly doesn't handle glibc versioned symbol differences, and it in general doesn't help at all for https://reproducible-builds.org

6D40

@rgommers
Copy link
Member Author
rgommers commented Jan 2, 2022

Yeah, I know it doesn't make too much sense (also, why cache local builds at all, they should be unique). I'm working on a set of docs for conceptual issues like these. I've also had discussions around UX of build tools, and even "what is a build system" that were truly mind-boggling. Setuptools for example has declared "it doesn't have a supported CLI, and no one should use a build system CLI anyway" - why would one ever need more than a single PEP 517 hook:)

@eli-schwartz
Copy link
Contributor

caching is much better done via a proper build system that does incremental builds + ccache :D

For local installs, roundtripping everything through a zip file "for consistency" is just a layer of bureaucracy... Meson doesn't consider it a burden to implement a CLI, that's our bread and butter -- and so is installing.

That's why I want the future to hold a core meson feature for doing pep 517 builds / pep 621 dist-info. Meson supports nearly everything that "a python package" needs and is only missing

  • dist-info creation to be fully compatible with a decade of python setup.py install
  • running /usr/bin/zip on $DESTDIR to be fully compatible with PyPI wheels

So it seems completely reasonable to support that, but... implementing brand new support for something and deliberately choosing a method that doesn't match current official recommendations for interoperability (pep 621) seems really, really bad, so for this reason alone we really, really want toml support.

And in order to provide the correct experience demanded by the rest of meson -- functionality should not randomly fail to work because of python dependency issues that cannot be bootstrapped -- our choices are either ignore pep 621 entirely, or leave dist-info and wheel creation to other layers like mesonpep517.

Otherwise we will end up with people developing base system libraries at the heart of an OS bootstrap, which include python bindings that either cannot be built due to errors or silently provide a broken install that is missing dist-info and cause heisenbugs when pip / build / importlib.metadata report that dependencies are missing and return errors.

I had at one time had high hopes that python 3.10 was going to include a toml library in fulfillment of the promise "we are just waiting for the format spec to stabilize as 1.0". :( :(

@WarrenWeckesser
Copy link
Member

Currently scipy/meson.build lists an explicit dependence on openblas. Is there a recommended workflow for using the new build system with a 9E88 numpy installation that already includes MKL? (I assume that dependence on openblas is temporary.)

@WarrenWeckesser
Copy link
Member

Responding to my own comment:

(I assume that dependence on openblas is temporary.)

Yes, @rgommers noted this over in #13615 (comment):

Windows support, generating release artifacts, and non-OpenBLAS BLAS/LAPACK libraries can be added afterwards.

@rgommers
Copy link
Member Author
rgommers commented Jan 3, 2022

There's no MKL support yet, and yes it will follow (and Netlib, BLIS, and generic BLAS). For order of next steps, see #14847 (comment). The issue for generic and configurable BLAS/LAPACK support in Meson is mesonbuild/meson#2835.

@astrojuanlu
Copy link
Contributor

FYI, re: TOML in the stdlib,

I hope it will happen, but I won't believe it until I see it.

PEP 680 was accepted and a PR to CPython was opened: python/cpython#31498

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Build issues Issues with building from source, including different choices of architecture, compilers and OS CI Items related to the CI tools such as CircleCI, GitHub Actions or Azure DX Everything related to making the experience of working on SciPy more pleasant enhancement A new feature or improvement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0