-
Notifications
You must be signed in to change notification settings - Fork 86
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
Building wheels with GMP et al #352
Comments
Hi Oscar, This is a fine forum for these discussions. I skimmed your work that you've done on python-flint. I think you've encountered most of the same issues with complex builds. Regarding Apple arm64 builds - yes, the patch is required. Apple reserved a register for their use. GMP 6.2.1 uses that register. The patch modifies GMP 6.2.1 to save/restore that register. (https://gmplib.org/list-archives/gmp-discuss/2022-July/006821.html) Without the patch, it will crash frequently. (See #350) Some comments on Windows Compiling gmpy for Windows has always been a challenge. -cmingw32 worked well for 32-bit versions of Python but required extensive hacking to use mingw64 compilers on 64-bit Windows. (I originally used MPIR and MSVC but MSVC didn't support --enable-fat. I didn't want to compile for the lowest common CPU type nor try to release CPU specific versions.) I compile the Windows binaries locally. I just extracted a copy of the cygwincompiler.py file from numpy and replace the file that comes with Python with a slightly modified copy. I don't compile anything else on Windows so it works for me. It would be great if the numpy version of -cmingw32 could be added to setuptools as -cmingw64. That would eliminate any risk of breakage for existing code that patches -cmingw32 on the fly. I know it is possible to compile Cython extensions on Windows using MSVC and link to the GMP/MPFR/MPC dlls. (See #320) At some point, I'd like to compile GMP/MPFR/MPC with a version of mingw64 that links to Microsoft's ucrt and then compile gmpy with MSVC. The ucrt dlls could be release as "wingmpy2-lib" package and become a basis for other projects. Regarding meson or cmake, I'm open to anything that it easier and more predictable, especially over the long run. Regards, |
Thanks. That's what I was wondering. It seems this topic comes up monthly on the GMP mailing list. I wonder when there might be a release with this patch.
I guess that's implicitly what we're depending on by using numpy.distutils in python-flint. I suspect that adding this to setuptools is not going to happen but I might be wrong. AFAICT Core Python and PyPA etc basically expect that MSVC will be used on Windows. That doesn't work for many key scientific packages (e.g. scipy) but it seems that their fix is to move away from setuptools to things like meson. I might be wrong but it seems like setuptools doesn't have resource to support non-MSVC compilers and the packages that do want other compilers are moving away from setuptools.
It would be a lot better if we could depend on something like that. How exactly would it work for building a downstream project that depended on these DLLs at the C level? I'd still need all headers etc to build python-flint but can that all be packaged up so that python-flint CI just installs the wingmpy2-lib wheel and then uses plain setuptools/MSVC to build a Cython extension based on that? That would be good although I'd still need to then build Flint and Arb so I'm not sure how much it would simplify anything for making python-flint wheels... I guess not duplicating the DLLs on disk or in memory is also a good thing and not having to carry patches for GMP etc. So yes if it just works(!) then it would simplify things. Then again it would be better if it was just easier to build stuff on Windows using either mingw64 or MSVC and have everything else taken care of. Ideally I'd just say in the cibuildwheel config what sort of compiler I'd want to use and everything else would be figured out by the build tools without me needing to manually code everything. It should be possible for both C projects and C-based Python extension modules to specify their build in a sufficiently platform independent way that which compiler is used is just a configuration variable or something but it definitely doesn't feel that simple right now... Since you mention ucrt the python-flint wheels currently link against msvcrt.dll. They seem to work fine but I assume that's potentially problematic and it would be better to link against ucrt. I'm sure I saw somewhere that msys2's ucrt support was somehow experimental or not production ready or something but I can't find that now although there's some information about ucrt here: More generally though it seems like you really need to be an expert in packaging to make any of this work and it's really not my domain of expertise. I know of this project to help with these general problems: |
It's here that I see the note about it being experimental but I'm not sure what exactly it means: |
AFAIK the |
Thanks Ralf. I don't particularly want to become a maintainer of these parts of setuptools so if no one else is interested working on it then I'd rather switch towards tools that other projects are going to use and that people with better expertise than me are going to maintain. |
I have opened a more recent python-flint issue to discuss the Python 3.12 problem: @casevh What are the current plans for gmpy2 in Python 3.12? |
My current approach relies on hacking the local copies of setuptools by overwriting cygwincompiler.py. It is not a realistic option for anyone else to use. The following would be nice but it's probably too late to be viable - add a new compiler type called mingw64.
@rgommers Would such a change be acceptable for consideration into @oscarbenjamin I will add comments to flintlib/python-flint#52 regarding GMP builds. |
I'm not a |
Current update:
More details to follow. |
This sounds like my epxperience in: |
I've added the GMP, MPFR, and MPC DLLs and library files to the gmpy2 repository. Look in But no hacks or modifications are needed to compile with MSVC and link to those DLLs. |
Is this line correct: Line 105 in 8c58be9
It still has -cmingw32 ...
|
That is a typo. Updates should be pushed later today.
…On Fri, Oct 13, 2023 at 4:01 AM Oscar Benjamin ***@***.***> wrote:
Is this line correct:
https://github.com/aleaxit/gmpy/blob/8c58be91e47a2781bd6aae4cdb25b7450d599d6d/mingw64/msys2_build.txt#L105
It still has -cmingw32...
—
Reply to this email directly, view it on GitHub
<#352 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAMR2333KON6VG3S5OWLS73X7ENSFAVCNFSM6AAAAAATFAGB22VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONRRGMZDMNBVGQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Are these all linked with ucrt? I think this means that they are linked with msvcrt: Line 18 in 8c58be9
|
These are linked with msvcrt. I haven't encountered any issues with linking
to msvcrt in the past. And I wanted to prove that I can compile with MSVC
and link to the DLLs that are linked to msvcrt.
I plan to compile a new set of DLLs that link to ucrt. They'll probably be
placed in a directory called winlibs_ucrt. I'll try to debug the ucrt issue
with those DLLs. I suspect there is a behavioral difference in memory
allocation between msvcrt and ucrt. Since GMP allows changing the memory
allocation code at startup, I will try replacing them with the ones exposed
by CPython. You do need to be caution in C code to always use the correct
method to deallocate memory. I'll have more details on this after I test.
I changed mp_bitcnt_t to unsigned long long.
I'll be pushing an update very soon.
…On Sat, Oct 14, 2023 at 9:13 AM Oscar Benjamin ***@***.***> wrote:
I've added the GMP, MPFR, and MPC DLLs and library files to the gmpy2
repository.
Are these all linked with ucrt? I think this means that they are linked
with msvcrt:
https://github.com/aleaxit/gmpy/blob/8c58be91e47a2781bd6aae4cdb25b7450d599d6d/mingw64/msys2_build.txt#L18
—
Reply to this email directly, view it on GitHub
<#352 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAMR233XHEOFBFL6SBRQ3ZDX7K2Z7AVCNFSM6AAAAAATFAGB22VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONRTGAZDOMRSGI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I have successfully built gmpy2 with GMP, MPFR, and MPC linked to ucrt.
The new library files have been pushed.
More details to follow.
…On Sat, Oct 14, 2023 at 9:59 AM Case Van Horsen ***@***.***> wrote:
These are linked with msvcrt. I haven't encountered any issues with
linking to msvcrt in the past. And I wanted to prove that I can compile
with MSVC and link to the DLLs that are linked to msvcrt.
I plan to compile a new set of DLLs that link to ucrt. They'll probably be
placed in a directory called winlibs_ucrt. I'll try to debug the ucrt issue
with those DLLs. I suspect there is a behavioral difference in memory
allocation between msvcrt and ucrt. Since GMP allows changing the memory
allocation code at startup, I will try replacing them with the ones exposed
by CPython. You do need to be caution in C code to always use the correct
method to deallocate memory. I'll have more details on this after I test.
I changed mp_bitcnt_t to unsigned long long.
I'll be pushing an update very soon.
On Sat, Oct 14, 2023 at 9:13 AM Oscar Benjamin ***@***.***>
wrote:
> I've added the GMP, MPFR, and MPC DLLs and library files to the gmpy2
> repository.
>
> Are these all linked with ucrt? I think this means that they are linked
> with msvcrt:
>
> https://github.com/aleaxit/gmpy/blob/8c58be91e47a2781bd6aae4cdb25b7450d599d6d/mingw64/msys2_build.txt#L18
>
> —
> Reply to this email directly, view it on GitHub
> <#352 (comment)>, or
> unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAMR233XHEOFBFL6SBRQ3ZDX7K2Z7AVCNFSM6AAAAAATFAGB22VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONRTGAZDOMRSGI>
> .
> You are receiving this because you were mentioned.Message ID:
> ***@***.***>
>
|
It's a bit off-topic, but could python-flint use |
If you build things locally then there is no reason why python-flint and gmpy2 cannot share the same libgmp. That is also what would happen with conda or with e.g. Linux distros (if they start shipping python-flint). It is just for PyPI wheels that gmpy2 and python-flint need to bundle libgmp. There is not currently a clear way to have an ABI dependency between wheels. Basically what you want is to be able to say "this exact python-flint wheel depends on that exact gmpy2 wheel" even though the source compatibility constraints are much looser than that. There is currently no way to express that dependency relationship though. For python-flint this does not save much in terms of disk space because libflint is about 100x larger than libgmp anyway. Also mpfr is a shared dependency but this is still much smaller than libflint. In my local build of python-flint I have a 69MB lib directory of which 64MB is libflint.so. Another potential benefit of having python-flint depend on gmpy2 is to enable conversion between e.g. |
Note that at present any package which needs cython-level interface to gmpy2 cannot simply use its binary wheel, as they lack GMP headers, and compilation will fail. Shouldn't gmpy2 also ship Well, it's probably a general deficiency of binary wheels, not only ones here. |
The headers for GMP, MPFR, and MPC will be included in 2.2.0a2.
I'll get it released as soon as context manager clean-up is completed.
…On Mon, Dec 4, 2023 at 3:38 AM Dima Pasechnik ***@***.***> wrote:
Note that at present any package which needs cython-level interface to
gmpy2 cannot simply use its binary wheel, as they lack GMP headers, and
compilation will fail. Shouldn't gmpy2 also ship gmp.h and all the other
library headers used?
Well, it's probably a general deficiency of binary wheels, not only ones
here.
—
Reply to this email directly, view it on GitHub
<#352 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAMR235BOD5VHNNMOW6HAO3YHWY4XAVCNFSM6AAAAAATFAGB22VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMZYGQ2TINZYGE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Here are quick instructions on how to build a gmpy2 binary wheel for Windows. The commands are run from the "x64 Native Tools Command Prompt"
The headers and DLLs are installed in the same location as gmpy2.h (site-packages\gmpy2\gmpy2). A Cython test program is in gmpy\test_cython. It should run with GMP, MPFR, and MPC were compiled with MinGW64 and linked against UCRT. The only change made to GMP is Any help from this point is appreciated. |
Here is how it works in our CI workflow: gmpy/.github/workflows/pip_install_gmpy2.yml Lines 104 to 107 in 831782a
As you can see, cython tests are working. Unfortunately, I don't know yet how to adapt this approach for cibuildwheel builds (i.e. change compiler from MSVC). |
Update on gmpy2 binaries for Windows I currently compile GMP, MPFR, and MPC using MSYS2 with a version of MinGW64 linked to ucrt. The resulting header, library, and DLLs are added to the git repository. The actual gmpy2 binaries can be compiled by MSVC with just a git checkout and then "py -3.12 -m build --wheel". When the resulting wheel is installed, Cython and C extensions can use the DLLs bundled with binary wheel. Challenges Cython and C-API extentions should use the same libraries as gmpy2. To avoid naming collisions, I want to rename DLLs. I've done this but it requires the renaming must be done before compiling gmpy2. I'm locally using Are there any concerns with predictable name-mangling of the GMP, MPFR, and MPC DLLs? (Note: the header and lib file names do not change.) Including Windows specfic DLLs in a source distribution is not appropriate. So compiling gmpy2 from source would need to trigger a MSYS2/MingGW64 phase and then a DOS/MSVC phase to create the actual binary wheels. I don't know how to automate a build workflow that requires both MSYS2/MinGW64 and DOS/MSVC. Are there any examples of such a workflow? The current state is that it is easy to create binary wheels for Windows as long as you start with a git checkout and have MSVC. That is a significant improvement over prior versions. I consider it good-enough. I've committed the latest name-mangled version for testing. |
Why not use delvewheel for this? More generally it would be good to use cibuildwheel and have all of this running in CI.
Neither do I unfortunately. I think though that unless you pass |
I'm trying to support extentions that use gmpy2's C-API. The fundamental issue is that GMP allows its memory allocation functions to be changed. This is a global change that is inherited by MPFR and MPC. Any code that relies on gmpy2's C-API must use the same memory management functions. I think this is best done by having those extensions use the same DLLs and I think that is best done with consistent, predictable names for the DLLs. The C-API used to work well on *NIX platforms because gmpy2 and extensions would generally use the system provided GMP, MPFR, and MPC libraries. Modern development environments and the proliferation of binary wheels make this a difficult problem. Since Windows doesn't provide standardized versions of GMP, MPFR, and MPC, I'm trying to use gmpy2's versions as the "system" libraries for extensions that use gmpy2's C-API. And it really works well. If you have gmpy2 installed, compiling C/Cython extensions is really quick and easy and only relies on the standard MSVC toolchain.
The MSYS2/MinGW64 toolchain is only needed to create the GMP, MPFR, and MPC libraries. The actual gmpy2 build only uses MSVC. A solution for running the |
maybe it's time to create pip-installable wheels for gmp,mpfr, mpc? just like what scipy project has done for openblas (which is in a similar league to gmp, but for numeric linear algebra) |
I'm wondering if this approach could work for python-flint. We would still need to build libflint though and I am not sure if that could be done with MSVC while still being compatible with the MinGW builds of GMP and MPFR. If it meant that python-flint could avoid needing to use MinGW then it might be worth doing.
You can see how this is done here: |
The GMP, MPFR, and MPC libraries are linked to Microsoft's ucrt. If you are creating a Windows binary wheel of gmpy2, there is a pre-work phase which requires MSYS2 and a version of MinGW64 that links to ucrt, and some copying of files to appropriate locations (DOS). Then the actual compilation of gmpy2 just uses MSVC. I've not had any issue with gmpy2. To compile a C-API extension, all that is required is use of a Python interpreter that has gmpy2 installed. Just need to use that installation of Python for compiling the extension. See
That sounds perfect. I'll look at it. |
In the case of python-flint we also need a prework phase to build GMP, MPFR and FLINT before building the python-flint extension modules. Leveraging gmpy2's C API we could get GMP and MPFR for free but would then still need to build FLINT which as a C library depends on both GMP and MPFR. I am wondering about whether we could build FLINT with MSVC. The only example I know of that builds FLINT with MSVC is this one which uses GMP, MPFR and pthreads from vcpkg: I am not sure how I could do the same to build FLINT against GMP and MPFR from gmpy2 using MSVC. Maybe this is not difficult but I don't have much experience with MSVC, vcpkg, cmake, ... Somehow we need to pass some information from gmpy2 to say where the headers and DLLs are for GMP and MPFR and then when libflint.dll and the flint headers are built we need to have those somewhere that MSVC would find when the extension modules are being built. If we still need MinGW to build FLINT then there is not much benefit in trying to use the GMP and MPFR that are provided by gmpy2 because it's easy to build them with MinGW as well, they don't add much to build-time or wheel-size etc. There would be some benefit but also the downside of the ABI coupling between gmpy2 and python-flint wheels. |
I got
is this the same as your error? To check i dont make something else wrong. |
I spun up a new VM and recreated the issue. Will investigate. |
Are the contents of |
I get |
IMHO on Windows it's pretty much hopeless to get symbolic links working properly. Better just copy files. |
I have updated the Windows build process. Please see msys2_build.txt and
begin at "6. Compile Windows binary wheels"
Changes:
- Undo name-mangling of the GMP, MPFR, and MPC dlls
- Copy gmpy2.h and gmpy2.pxd into the gmpy2 directory when running on
Windows
…On Tue, Feb 27, 2024 at 3:55 AM Dima Pasechnik ***@***.***> wrote:
IMHO on Windows it's pretty much hopeless to get symbolic links working
properly. Better just copy files.
—
Reply to this email directly, view it on GitHub
<#352 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAMR23ZWDGNVOPIFONAV6WLYVXCRLAVCNFSM6AAAAAATFAGB22VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNRWGM4DGNRYGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
dll2lib.bat is still mentioned in msys2_build.txt |
dll2lib.bat isn't used for name-mangling and is still needed to create the required lib files. I used a different utility called rename-dll (sp?) for name-mangling. |
Yes. And it's missing from in sources.
Why not delvewheel? It seems to be working for flint people. |
I have a fundamental conflict with name-mangling to random names and supporting the C-API. I will only support the C-API if the same DLL names for GMP, MPFR, and MPC are used for all offical Windows binary wheels of gmpy2 2.2.x. There is no other way to guarantee that extensions that use gmpy2's C-API will work consistently. I could remove the C-API on Windows but I actually want to use it. I would like to disable the C-API for all binary wheels since there is no way to gurarantee that an extension will use the same DLLs as gmpy2. But I don't know if that is possible. It's not an issue of name-mangling, the key issue is that the GMP, MPFR, and MPC names can change for every release. So extensions would need to be re-compiled for every different release of a binary wheel. |
I did attempts to use bundled winlibs/ files to built win wheels in CI (this branch: https://github.com/skirpichev/gmpy/tree/win-wheels), but without success: https://github.com/skirpichev/gmpy/actions/runs/8129156379/job/22215901783 (Maybe I should try different win version?) |
It doesn't look GMP was built. Should that not be done in |
Source tree has built libraries. The idea was first try to use this. |
It is better if everything is built in CI. If mingw is used to build GMP etc then the process should not be much different from what python-flint does. Just there are some steps needed to process the DLLs which would need to be different. In the |
I tried this (https://github.com/skirpichev/gmpy/tree/win-wheels2), following the python-flint build scripts. Perhaps, I miss something (got
I'll try to follow mingw64/msys2_build.txt, if above variant fails. |
Some comments. Please follow the instructions in mingw64/msys2_build.txt precisely. I use the Microsoft developer VMs ( https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/ ) to create the wheels for Windows. It would be much easier if there was support for OS specific source distributions. But I doubt that will happen. My apologies for delays in responsding, I have too many demands on my time. I would like to focus on releasing gmpy2 2.2.0. The gmpy2 code is in a good state (Thanks Sergey!!) What is required to make the formal release? |
Are we run out of time? Maybe some projects (e.g. SymPy) want this due to their release plans? If not, I think that the current issue is most important one: how to automate building and testing binary wheels for M$ Windows in CI. I would like to see some alpha release with support for CPython 3.13. Probably, we should also document how to build cython extensions with provided macos/linux binary wheels (this is only tested on CI in #447). Maybe we should also update changelog (see #329), i.e. move all that to a single place, preferably to the sphinx docs. (I would like also get rid of using private CPython API, see #467: there is some time, before CPython 3.13 beta...) |
It seems the error on my side was simple: I forgot to blacklist win32. Here is a PR, that uses mixed toolchain: #469. |
If this is a bad place to open this discussion then let me know and I'll take it elsewhere.
I've been working on python-flint which is another project that packages similar libraries to gmpy. Along with GMP and MPFR, python-flint also includes Flint and Arb so it is similar in some ways to gmpy but with a different overall scope. The main thing I've been working on is producing wheels (flintlib/python-flint#1) and I'm pretty close to having that working with some of that work inspired by the way that gmpy does things.
I wonder if there is scope for collaborating and learning from each other about exactly what is a good way to build something like this because it seems like a very much uphill struggle with current Python packaging infrastructure (although things are getting better over time).
In particular I have questions right now about how exactly gmpy makes wheels for Apple arm64. I see that recent commits include a patch to GMP for this platform. Is that necessary? Does something not work without it?
Has the gmpy project considered moving to meson or cmake etc because I see some suggestion that other scientific Python projects are moving that way. Could there be any scope to work together on moving towards new build systems?
The text was updated successfully, but these errors were encountered: