How can I build my C extensions with MinGW-w64 in Python?

后端 未结 4 1138
星月不相逢
星月不相逢 2020-12-07 16:03

So I have a few Python C extensions I have previously built for and used in 32 bit Python running in Win7. I have now however switched to 64 bit Python, and I am having issu

相关标签:
4条回答
  • 2020-12-07 16:23

    I realize this is an old question, but it is still the top search result. Today, in 2019, I was able to do this:

    https://github.com/PetterS/quickjs/commit/67bc2428b8c0716538b4583f4f2b0a2a5a49106c

    In short:

    1. Make sure a 64-bit version of mingw-w64 is in the PATH.
    2. Monkey-patch distutils:
      import distutils.cygwinccompiler
      distutils.cygwinccompiler.get_msvcr = lambda: []
      
    3. Some differences in the shell w.r.t. escaping.

    4. extra_link_args = ["-Wl,-Bstatic", "-lpthread"] in order to link statically and not have extra runtime deps.

    5. pipenv run python setup.py build -c mingw32 now works.

    0 讨论(0)
  • 2020-12-07 16:24

    This worked for me with Python 3.3 :

    1. create static python lib from dll

      python dll is usually in C:/Windows/System32; in msys shell:

      gendef.exe python33.dll
      
      dlltool.exe --dllname python33.dll --def python33.def --output-lib libpython33.a
      
      mv libpython33.a C:/Python33/libs
      
    2. use swig to generate wrappers

      e.g., swig -c++ -python myExtension.i

    3. wrapper MUST be compiled with MS_WIN64, or your computer will crash when you import the class in Python

      g++ -c myExtension.cpp -I/other/includes
      
      g++ -DMS_WIN64 -c myExtension_wrap.cxx -IC:/Python33/include
      
    4. shared library

      g++ -shared -o _myExtension.pyd myExtension.o myExtension_wrap.o -lPython33 -lOtherSharedLibs -LC:/Python33/libs -LC:/path/to/other/shared/libs
      
    5. make sure all shared libs (gdal, OtherSharedLibs) are in your PATH (windows does not use LD_LIBRARY_PATH or PYTHONPATH)

    6. in Python, just: import myExtension

    voila!

    0 讨论(0)
  • 2020-12-07 16:30

    Here is a example code for VC++ Build Tools https://github.com/starnight/python-c-extension/tree/master/00-HelloWorld

    You could try:

    python setup.py -c mingw32
    

    However this is not work for me.

    My Solution is:

    1. install Anaconda 64bit python 3.6

    2. install mingw64

    3. add mingw64/bin to PATH
    4. compile dll from c file by

      gcc -c libmypy.c -IC:\Users\{user_name}\Anaconda3\pkgs\python-3.6.4-h6538335_1\include  
      gcc -shared -o libmypy.dll libmypy.o  -LC:\Users\{user_name}\Anaconda3\pkgs\python-3.6.4-h6538335_1\libs -lPython36
      
    5. load dll file in .py script

      from ctypes import *  
      m = cdll.LoadLibrary(r"C:\{path_to_dll}\libmypy.dll")  
      print(m.hello())
      
    0 讨论(0)
  • 2020-12-07 16:40

    I used this thread to wade through learning how to make a C extension, and since most of what I learned is in it, I thought I'd put the final discovery here too, so that someone else can find it if they are looking.

    I wasn't trying to compile something big, just the example in Hetland's Beginning Python. Here is what I did (the example C pgm is called palindrome.c). I'm using Anaconda with python 3.7 in it, and the TDM-GCC version of MinGW64. I put all of the tools used into my Path, and all of the paths needed in PYTHONPATH, and the ..\Anaconda3 directory into PYTHON_HOME. I still ended up using explicit paths on some things.

    I created the libpython37.a library with gendef.exe and dlltool.exe as Mark said above, and put it in ..\Anaconda3\libs.

    I followed the prescription in Hetland:

    gcc -c palindrome.c

    gcc -I$PYTHON_HOME -I$PYTHON_HOME/Include -c palindrome_wrap.c

    The second failed, the compiler couldn't find Python.h, the following worked:

    gcc -I[somedirectories]\Anaconda3\Include -c palindrome_wrap.c

    I then did, as many have said, including Hetland 3rd ed.,

    gcc -shared palindrome.o palindrome_wrap.o [somedirectories]/Anaconda3/libs/libpython37.a -o _palindrome.dll

    This did not work. Even with the Load Library cswu used (which I found elsewhere, too).

    So I gendef'd _palindrome.dll and couldn't find the function in it, "is_palindrome" in the exports. I went through some of the SWIG documentation, and declared the function both in the %{ %} section and below it, both extern, that finally got the function extern'd in palindrome_wrap.c as it should have been. But no export, so I went back into palindrome.c and redeclared the function as:

    declspec(dllexport) extern int __stdcall is_palindrome(char* text)

    and redeclared it in palindrome.i in both places as above with this signature.

    Partial success! It got listed in the Export section when I gendef'd _palindrome.dll and I could do cswu's call using Load Library. But still not do what Hetland says and do

    import _palindrome

    in Python.

    Going back to all the sources again, I could not figure this out. I finally started reading the SWIG documentation from the beginning leaving no stone unturned -- Searching through the manual doesn't produce the place found.

    At the end of Introduction Sec. 2.7 Incorporating Into a Build System, under the sample Make process, it says:

    "The above example will generate native build files such as makefiles, nmake files and Visual Studio projects which will invoke SWIG and compile the generated C++ files into _example.so (UNIX) or _example.pyd (Windows). For other target languages on Windows a dll, instead of a .pyd file, is usually generated."

    And that's the answer to the last problem:

    The compile step for the dll should read:

    gcc -shared palindrome.o palindrome_wrap.o [somedirectories]/Anaconda3/libs/libpython37.a -o _palindrome.pyd

    (I didn't go back and change out my declspec declarations so I don't know whether they were necessary, so they were still there too).

    I got a file, _palindrome.pyd

    Which if in the PYTHONPATH (mine was local) works, and one can then do

    import _palindrome

    from _palindrome import is_palindrome

    and use the exported, properly wrapped and packaged C function, compiled with TDM-GCC, in python as promised. gcc, which is MinGW64 in a different installation, knows how to do the .pyd file. I diffed the dll and pyd since they were the same byte length. They are not the same at hundreds of points.

    Hope this helps someone else.

    0 讨论(0)
提交回复
热议问题