-
Notifications
You must be signed in to change notification settings - Fork 18
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
RFC: replace setuptools with meson-python for more stable and predictable builds and installations #128
base: develop
Are you sure you want to change the base?
Conversation
…nce ninja shouldn't be required
…rsion.py is correct
Co-authored-by: Michael McKinsey <MichaelMcKinsey1@gmail.com>
Co-authored-by: Michael McKinsey <MichaelMcKinsey1@gmail.com>
Should |
meson.build
Outdated
# Get the Meson Python object, a dependency object to Python for extension modules, | ||
# and the path to the top-level install directory | ||
py = import('python').find_installation(pure: false) | ||
py_dep = py.dependency() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to note that I was able to build hatchet with meson on Quartz using conda and python 3.11.9. But when trying on local (Windows) using conda (python 3.11.9), I get the following error on this line:
$ pip install hatchet-meson/
Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.com
Processing c:\users\micha\documents\github\hatchet-meson
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'done'
Preparing metadata (pyproject.toml): started
Preparing metadata (pyproject.toml): finished with status 'error'
error: subprocess-exited-with-error
Preparing metadata (pyproject.toml) did not run successfully.
exit code: 1
[18 lines of output]
+ meson setup C:\Users\Micha\Documents\Github\hatchet-meson C:\Users\Micha\Documents\Github\hatchet-meson\.mesonpy-dnom1o2_ -Dbuildtype=release -Db_ndebug=if-release -Db_vscrt=md --native-file=C:\Users\Micha\Documents\Github\hatchet-meson\.mesonpy-dnom1o2_\meson-python-native-file.ini
The Meson build system
Version: 1.4.0
Source dir: C:\Users\Micha\Documents\Github\hatchet-meson
Build dir: C:\Users\Micha\Documents\Github\hatchet-meson\.mesonpy-dnom1o2_
Build type: native build
Project name: llnl-hatchet
Project version: 2024.1.1
Activating VS 16.11.26
Cython compiler for the host machine: cython (cython 3.0.10)
Host machine cpu family: x86_64
Host machine cpu: x86_64
Program python found: YES (C:\Users\Micha\miniconda3\envs\test-meson\python.exe)
Run-time dependency python found: NO
..\meson.build:9:12: ERROR: Python dependency not found
A full log can be found at C:\Users\Micha\Documents\Github\hatchet-meson\.mesonpy-dnom1o2_\meson-logs\meson-log.txt
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed
Encountered error while generating package metadata.
See above for output.
note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
Same error If i run . install_editable.sh
. I was able to install this way with setuptools
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two questions related to this @michaelmckinsey1:
- Do you have
pkgconfig
installed? - Where are your Python development libraries (i.e.,
libpython<version_stuff>.so
) installed?
Long story short, this is essentially caused by Windows being different from every other OS on the planet and doing certain things differently from every other OS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michaelmckinsey1 when you get the chance, can you try to download and install the following sdist in a Python venv?
Once the file is downloaded, you can install with
python3 -m pip install numpy-1.26.4.tar.gz
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious if that will fail with the same error. From what I can tell, the Python lookup Meson code is the same as what NumPy uses. If installing that sdist fails too, then there's likely an issue with your Windows install of Python. But, if it doesn't, then there's something wrong with my Meson stuff in Hatchet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I did not have
pkgconfig
, but installing it did not fix the issue. - They would be
.dll
not.so
right? I don't even see anylibpython*.dll
, all I see in conda is:
miniconda3/envs/test-meson/Lib/site-packages/Cython/Debugger/libpython.py
miniconda3/envs/test-meson/Lib/site-packages/Cython/Debugger/Tests/test_libpython_in_gdb.py
miniconda3/envs/test-meson/Lib/site-packages/Cython/Debugger/Tests/__pycache__/test_libpython_in_gdb.cpython-311.pyc
miniconda3/envs/test-meson/Lib/site-packages/Cython/Debugger/__pycache__/libpython.cpython-311.pyc
- I tried downloading the sdist and still got the same error
I also tried with venv
, and I tried on another windows device with conda, same error. I would assume for now it's a general issue with our meson build for Windows, unless someone else is able to successfully build on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michaelmckinsey1 can you run python3 -m sysconfig
and paste the output here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what it's worth, I can now reproduce on macOS when pkgconfig is not installed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$ python -m sysconfig
Platform: "win-amd64"
Python version: "3.11"
Current installation scheme: "nt"
Paths:
data = "C:\Users\Micha\miniconda3\envs\test-meson"
include = "C:\Users\Micha\miniconda3\envs\test-meson\Include"
platinclude = "C:\Users\Micha\miniconda3\envs\test-meson\Include"
platlib = "C:\Users\Micha\miniconda3\envs\test-meson\Lib\site-packages"
platstdlib = "C:\Users\Micha\miniconda3\envs\test-meson\Lib"
purelib = "C:\Users\Micha\miniconda3\envs\test-meson\Lib\site-packages"
scripts = "C:\Users\Micha\miniconda3\envs\test-meson\Scripts"
stdlib = "C:\Users\Micha\miniconda3\envs\test-meson\Lib"
Variables:
BINDIR = "C:\Users\Micha\miniconda3\envs\test-meson"
BINLIBDEST = "C:\Users\Micha\miniconda3\envs\test-meson\Lib"
EXE = ".exe"
EXT_SUFFIX = ".cp311-win_amd64.pyd"
INCLUDEPY = "C:\Users\Micha\miniconda3\envs\test-meson\Include"
LIBDEST = "C:\Users\Micha\miniconda3\envs\test-meson\Lib"
TZPATH = "C:\Users\Micha\miniconda3\envs\test-meson\share\zoneinfo"
VERSION = "311"
VPATH = "..\.."
abiflags = ""
base = "C:\Users\Micha\miniconda3\envs\test-meson"
exec_prefix = "C:\Users\Micha\miniconda3\envs\test-meson"
installed_base = "C:\Users\Micha\miniconda3\envs\test-meson"
installed_platbase = "C:\Users\Micha\miniconda3\envs\test-meson"
platbase = "C:\Users\Micha\miniconda3\envs\test-meson"
platlibdir = "DLLs"
prefix = "C:\Users\Micha\miniconda3\envs\test-meson"
projectbase = "C:\Users\Micha\miniconda3\envs\test-meson"
py_version = "3.11.9"
py_version_nodot = "311"
py_version_nodot_plat = "311"
py_version_short = "3.11"
srcdir = "C:\Users\Micha\miniconda3\envs\test-meson"
userbase = "C:\Users\Micha\AppData\Roaming\Python"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I've worked this out. For some (stupid) reason, Meson never tries to use Python's sysconfig
library to locate the development libraries or include dirs. Meson has 2 lookup modes for the Python dependency:
pkgconfig
: invokes pkg-config to locate the libraries. Will fail if pkg-config is not installed (unlikely on Linux, but likely on macOS and Windows), ifPKG_CONFIG_PATH
is not properly set, or if the Python install does not have a.pc
filesystem
: uses variables insysconfig
to build the expected library name and searches for that library in recognized compiler search paths (e.g.,LD_LIBRARY_PATH
on UNIX). This is why I said Meson's a bit stupid because it's already usingsysconfig
to build library names, but it's not using thesysconfig
variables that directly point to the recognized libpython
So, because we build extension modules (i.e., the Cython code), users need one of the following to be true:
pkg-config
must be installed- Library search variables (e.g.,
LD_LIBRARY_PATH
) need to be properly set
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michaelmckinsey1 when you get the chance, can you try at least one of these solutions on Windows? I'll try on macOS. If this works, I'll try to see if there's a way I can add pkg-config to the build dependencies
`install.sh` was used for debugging builds on LLNL systems. However, it was based on deprecated and likely to break functionality from `setuptools`. With `setuptools` being removed, this script will no longer work. Instead, users should use the new `install_editable.sh` script
Good catch. Fixed |
We've had quite a few issues with building and installing Hatchet. Although some (e.g., #125) are out of our control, many of the issues we've encountered (e.g., issues with editable installs) stem from our use of
setuptools
.In general,
setuptools
is great for pure Python packages. However, as soon as you start having any non-Python code,setuptools
becomes really painful to use and error prone. This is mostly due to the fact thatsetuptools
is built on top of and inspired by the super olddisutils
package.These issues will likely only get worse in the future, especially with
disutils
(finally) being killed in Python 3.12. Sincesetuptools
depends ondisutils
, this is a big problem. The team behindsetuptools
has already copied their own vendored version ofdisutils
, and they plan on eventually replacingdisutils
with their own code. However, thesetuptools
team is notoriously slow in making changes, so this major change will likely take years. In the meantime,setuptools
will be operating on a vendored, dead library that will only receive as much support as thesetuptools
team can give it while working onsetuptools
itself. This almost guarantees that the number of odd, difficult to fix bugs insetuptools
will increase in the coming years.Given both our issues with
setuptools
and its pending future with the death ofdisutils
, I feel like it's a great time to look into alternatives for building Hatchet (and later Thicket). I looked through several options (e.g., flit, hatchling, and poetry), but in the end, I decided to try to follow the trend started by NumPy and SciPy and use meson-python. This package is a PEP 517-compliant build backend that allows Python packages to be built with the Meson build system. Meson is a multi-language build system built in Python and supporting Ninja-based compilation of code. It is essentially a CMake competitor with a more restrictive and opinionated, but easier to use design.Speaking of Meson being easy to use, in the course of a couple hours, I was able to completely replace
setuptools
with meson-python in Hatchet and confirm that it is working correctly. For comparison, the initial implementation of oursetuptools
integration took several weeks to complete.With all this said, this PR is meant to be a Request for Comment (RFC) on the idea of switching from
setuptools
to meson-python in Hatchet (and eventually Thicket). Use this PR as a centralized place for all discussion, ideas, thoughts, opinions, etc. about this proposed switch to meson-python and build systems for Hatchet and Thicket in general.In this rest of this initial PR comment, I'm going to explain how support for meson-python in Hatchet works, how this support impacts developers, and what are the downsides to this approach.
How meson-python works in Hatchet
Support for meson-python can be broken down into three parts:
pyproject.toml
meson.build
.gitattributes
Providing metadata and dependency info with
pyproject.toml
Like all PEP 517-compliant build systems, the integration of meson-python starts with
pyproject.toml
. Likesetuptools
, meson-python must be specified under thebuild-system
table as both a build dependency and the build backend. Currently, that TOML code looks like this:These three lines tells PEP 517-compliant installers/builders (e.g.,
pip
) that (1) meson-python and Cython must be installed to build Hatchet and (2) the "build backend" that will do all the heavy lifting is "mesonpy" (the backend implemented by meson-python). In other words, these lines enable the use of meson-python.Unlike
setuptools
, all metadata and dependency configuration for meson-python is also done inpyproject.toml
. Additionally, meson-python supports all possible package metadata that can be tracked by indexes like PyPI (i.e., the index behindpip
). Currently, this TOML code looks like:Defining the build and binary distribution creation processes with
meson.build
After creating and populating
pyproject.toml
, all that's left to integrating meson-python is setting up Meson like you would any other project. For reference, Meson's documentation is extremely detailed and useful for this process.Like CMake, Meson expects there to be a special file in each source directory. In Meson, those special files are called
meson.build
. Hatchet currently provides ameson.build
file for all source directories containing the main Python or Cython source code. The only directories not containingmeson.build
are:hatchet/external/roundtrip
hatchet/vis
hatchet/tests
For
hatchet/external/roundtrip
and subdirectories ofhatchet/vis
, I don't includemeson.build
because these directories will be installed in their entirety into Python sdist or wheels. As a result, I can just install the directories themselves instead of the individual files. Forhatchet/tests
, I don't includemeson.build
because we don't want the tests to be installed into Python sdists and wheels.Each
meson.build
file contains the relevant Meson code to install and/or build the source files in its directory. Eachmeson.build
file then invokessubdir
as needed to navigate into subdirectories. Thesemeson.build
files can be grouped into 4 categories.The first category consists of the top level
meson.build
file. This file (shown below) configures the Meson project, locates Python and sets up the relevant Meson objects, and confirms that the version inversion.py
matches the Meson project version.The second category of
meson.build
files consists of files in directories containing only pure Python code (and subdirectories). These files simply install a list of.py
files, as shown below. Note that, in Meson, variables are not scoped, so each variable, such as the list of.py
files, needs to have a different name.The third category of
meson.build
files consists of files in directories containing both pure Python code and other code that needs to be installed alongside the Python code without being built. An example of this is thehatchet/external
directory. In this case, the pure Python files are installed as normal (see the second category example), and the non-Python files are installed by calling Meson'sinstall
functions with theinstall_dir
argument set. An example is shown below:The fourth and final category of
meson.build
files consists of files in directories containing Python extensions that need to be compiled. An example of this is thehatchet/cython_modules
directory. Thankfully, Meson makes building and installing this extensions trivial with thePython.extension_module
function. An example of this category is shown below:Defining rules for source distribution creation with
.gitattributes
The only other aspect of this integration of meson-python to keep in mind is the
.gitattributes
file. To create sdists, meson-python invokes themeson dist
command on the repo, which itself usesgit archive
. Becausegit archive
is used, meson-python will, by default, collect all files committed to version control. Files and directories can be excluded from the sdist by adding them to.gitattributes
with theexport-ignore
attribute.And that's it! In summary, the integration of meson-python consists of:
pyproject.toml
for specifying package metadata, dependencies, and configurationmeson.build
files for building software and specifying the rules for making binary distributions (i.e., wheels).gitattributes
to prevent files from being added to source distributionsHow does support for meson-python impact developers
Using meson-python does require developers to think a bit more about what is getting distributed to users, but it's not very hard. Essentially, developers just need to ask themselves the following questions:
tests
directory), check.gitattributes
, and make sure your code falls under one of the entries in that file. If it doesn't, add an entrypy.extension_module
(or any other relevant Meson code to compile your code) in themeson.build
for your code's directory (see category 4 above)meson.build
that gets passed topy.install_sources
install
functions (e.g.,install_subdir
for directory,install_data
for single files) and set theinstall_dir
argument appropriatelyDownsides to using meson-python
No tool can only provide benefits, so it's useful to understand what the downsides of using meson-python are. As I see it, there are 3 downsides to using meson-python:
pip
when provided the--no-build-isolation
flag) where that doesn't happen. These corner cases will be more problematic with meson-python than withsetuptools
(albeit not by much).install_editable.sh
that will do this for you.Personally, I don't think these issues are that major, and I believe the benefits of using meson-python (i.e., more control over what gets installed and flexibility to easily build and install any extension module we want) outweigh these minor downsides.