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

后端 未结 4 1213
星月不相逢
星月不相逢 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: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.

提交回复
热议问题