Wie kann ich meine C-Erweiterungen mit MinGW-w64 in Python erstellen?

Lesezeit: 9 Minuten

Benutzer-Avatar
c00kiemonster

Ich habe also ein paar Python-C-Erweiterungen, die ich zuvor für 32-Bit-Python entwickelt und verwendet habe, das in Win7 ausgeführt wird. Ich bin jetzt jedoch auf 64-Bit-Python umgestiegen und habe Probleme, die C-Erweiterung mit MinGW-w64 zu erstellen.

Ich habe die Änderungen an distutils wie pro vorgenommen dieser Beitragaber ich erhalte einige seltsame Fehler, die darauf hindeuten, dass etwas nicht stimmt:

$ python setup.py build
running build
running build_ext
building 'MyLib' extension
c:\MinGW64\bin\x86_64-w64-mingw32-gcc.exe -mdll -O -Wall -Ic:\Python27\lib\site-packages\numpy\core\include -Ic:\Python27\include -Ic:\Python27\PC -c MyLib.c -o build\temp.win-amd64-2.7\Release\mylib.o
MyLib.c: In function 'initMyLib':
MyLib.c:631:5: warning: implicit declaration of function 'Py_InitModule4_64' [-Wimplicit-function-declaration]
writing build\temp.win-amd64-2.7\Release\MyLib.def
c:\MinGW64\bin\x86_64-w64-mingw32-gcc.exe -shared -s build\temp.win-amd64-2.7\Release\mylib.o build\temp.win-amd64-2.7\Release\MyLib.def -Lc:\Python27\libs -Lc:\Python27\PCbuild\amd64 -lpython27 -o build\lib.win-amd64-2.7\MyLib.pyd
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x13d): undefined reference to `__imp_PyExc_ValueError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1275): undefined reference to `__imp_PyExc_ValueError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1eef): undefined reference to `__imp_PyExc_ImportError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1f38): undefined reference to `__imp_PyExc_AttributeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1f4d): undefined reference to `__imp_PyCObject_Type'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1f61): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1fc7): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x1ffe): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x2042): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x206c): undefined reference to `__imp_PyExc_RuntimeError'
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x208a): more undefined references to `__imp_PyExc_RuntimeError' follow
build\temp.win-amd64-2.7\Release\mylib.o:MyLib.c:(.text+0x20a7): undefined reference to `__imp_PyExc_ImportError'
collect2.exe: error: ld returned 1 exit status
error: command 'x86_64-w64-mingw32-gcc' failed with exit status 1

Ich habe ziemlich viel gegoogelt, um Informationen zu finden, aber es ist nicht einfach, eine eindeutige Antwort zu finden. Könnte jemand etwas Licht ins Dunkel bringen? Welche weiteren Änderungen sollte ich vornehmen, um C-Erweiterungen für 64-Bit-Python in Win7 erfolgreich erstellen zu können?

BEARBEITEN:

Nach einigen hilfreichen Hinweisen in den Kommentaren von cgohlke unten gelang es mir, zu generieren libpython27.a. Nachdem Sie jedoch die Ratschläge befolgt haben dieser Beitrag (vorletzter) Ich hatte noch einen __imp_Py_InitModule4_64 Error. Nach einigem Google-Fu gelang es mir, darüber zu stolpern dieser Beitrag sagt mir, ich soll die umbenennen Py_InitModule4 Linie zu Py_InitModule4_64. Danach funktionierte alles wie am Schnürchen.

  • Sie müssen erstellen libpython27.a mit gendef.exe python27.dll und dlltool.exe --dllname python27.dll --def python27.def --output-lib libpython27.a und lege es hinein C:\Python27\libs

    – cgohlke

    25. Juni 2012 um 4:41 Uhr


  • Ich habe einige Beiträge gesehen, in denen gendef erwähnt wurde. Es ist jedoch nicht einfach, Informationen zum Generieren der Datei libpython27.a zu finden. Kennst du zufällig welche?

    – c00kiemonster

    25. Juni 2012 um 5:04 Uhr

  • Oh ok, gendef und dlltool sind zwei verschiedene Befehle. Werde versuchen. Vielen Dank.

    – c00kiemonster

    25. Juni 2012 um 5:10 Uhr

  • Ok, es ist in Ordnung kompiliert, aber wenn ich versuche, das Modul zu importieren, bekomme ich Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: DLL load failed: The specified procedure could not be found. Ich glaube, irgendwo muss eine Datei fehlen. Das einzige, was ich mit dem Gendef-Zeug gemacht habe, war zu setzen libpython27.a in C:\Python27\libs. Habe ich etwas verpasst?

    – c00kiemonster

    25. Juni 2012 um 5:50 Uhr

  • Also bin ich alle Schritte wie pro durchgegangen Dies Post (2. von unten). Aber jetzt wird es nicht kompiliert, und ich bekomme das build\temp.win-amd64-2.7\Release\cquant.o:cQuant.c:(.text+0x1f09): undefined reference to __imp_Py_InitModule4_64′ collect2.exe: Fehler: ld gab 1 Exit-Status zurück

    – c00kiemonster

    25. Juni 2012 um 6:47 Uhr

Benutzer-Avatar
Markieren

Das hat bei mir mit Python 3.3 funktioniert:

  1. Erstellen Sie eine statische Python-Bibliothek aus einer DLL

    Python-DLL befindet sich normalerweise in C:/Windows/System32; in der 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. Verwenden Sie swig, um Wrapper zu generieren

    z.B, swig -c++ -python myExtension.i

  3. Wrapper MUSS mit MS_WIN64 kompiliert werden, oder Ihr Computer stürzt ab, wenn Sie die Klasse in Python importieren

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

    g++ -shared -o _myExtension.pyd myExtension.o myExtension_wrap.o -lPython33 -lOtherSharedLibs -LC:/Python33/libs -LC:/path/to/other/shared/libs
    
  5. Stellen Sie sicher, dass sich alle gemeinsam genutzten Bibliotheken (gdal, OtherSharedLibs) in Ihrem PATH befinden (Windows verwendet LD_LIBRARY_PATH oder PYTHONPATH nicht).

  6. in Python einfach: import myExtension

voila!

Mir ist klar, dass dies eine alte Frage ist, aber es ist immer noch das beste Suchergebnis. Heute, im Jahr 2019, konnte ich dies tun:

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

Zusamenfassend:

  1. Stellen Sie sicher, dass sich eine 64-Bit-Version von mingw-w64 im PATH befindet.
  2. Monkey-Patch-Distutils:
    import distutils.cygwinccompiler
    distutils.cygwinccompiler.get_msvcr = lambda: []
    
  3. Einige Unterschiede in der Shell bezüglich des Entkommens.

  4. extra_link_args = ["-Wl,-Bstatic", "-lpthread"] um statisch zu verlinken und keine zusätzlichen Laufzeit-Deps zu haben.

  5. pipenv run python setup.py build -c mingw32 jetzt funktioniert.

  • Danke, ja, bei mir funktioniert es schon seit einiger Zeit. Wir sollten wahrscheinlich versuchen, etwas dauerhafteres in distutils einzuchecken….

    – Peter

    24. September 2019 um 10:11 Uhr

Benutzer-Avatar
csw

Hier ist ein Beispielcode für VC++ Build Tools
https://github.com/starnight/python-c-extension/tree/master/00-HelloWorld

Du könntest es versuchen:

python setup.py -c mingw32

Dies ist jedoch keine Arbeit für mich.

Meine Lösung ist:

  1. Installieren Sie Anaconda 64-Bit-Python 3.6

  2. Installieren mingw64

  3. mingw64/bin zu PATH hinzufügen
  4. Kompilieren Sie die DLL aus der C-Datei von

    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. Laden Sie die DLL-Datei im .py-Skript

    from ctypes import *  
    m = cdll.LoadLibrary(r"C:\{path_to_dll}\libmypy.dll")  
    print(m.hello())
    

Ich habe einen Monkey-Patch für Setuptools erstellt, damit Sie mit mingw64 unter Windows einfach build_ext erstellen können. Sehen https://github.com/imba-tjd/mingw64ccompiler

Benutzer-Avatar
hkr

Ich habe diesen Thread verwendet, um zu lernen, wie man eine C-Erweiterung erstellt, und da das meiste, was ich gelernt habe, darin enthalten ist, dachte ich, ich würde die letzte Entdeckung auch hier einfügen, damit jemand anderes sie finden kann, wenn er sucht.

Ich habe nicht versucht, etwas Großes zu kompilieren, sondern nur das Beispiel in Hetlands Beginning Python. Folgendes habe ich getan (das Beispiel C pgm heißt palindrome.c). Ich verwende Anaconda mit Python 3.7 und die TDM-GCC-Version von MinGW64. Ich habe alle verwendeten Tools in meinen Pfad und alle benötigten Pfade in PYTHONPATH und das Verzeichnis ..\Anaconda3 in PYTHON_HOME eingefügt. Ich habe immer noch explizite Pfade für einige Dinge verwendet.

Ich habe die Bibliothek libpython37.a mit gendef.exe und dlltool.exe erstellt, wie Mark oben sagte, und sie in ..\Anaconda3\libs abgelegt.

Ich habe das Rezept in Hetland befolgt:

gcc -c palindrom.c

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

Der zweite schlug fehl, der Compiler konnte Python.h nicht finden, Folgendes funktionierte:

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

Ich habe dann, wie viele gesagt haben, einschließlich Hetland 3rd ed.,

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

Das hat nicht funktioniert. Sogar mit der verwendeten Load Library cswu (die ich auch woanders gefunden habe).

Also habe ich _palindrome.dll gendef’d und konnte die Funktion darin nicht finden, “is_palindrome” in den Exporten. Ich ging einen Teil der SWIG-Dokumentation durch und deklarierte die Funktion sowohl im Abschnitt %{ %} als auch darunter, beides extern, was schließlich die Funktion extern in palindrome_wrap.c erhielt, wie es hätte sein sollen. Aber kein Export, also ging ich zurück zu palindrome.c und deklarierte die Funktion wie folgt:

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

und es in palindrome.i an beiden Stellen wie oben mit dieser Signatur neu deklariert.

Teilerfolg! Es wurde im Export-Abschnitt aufgelistet, als ich _palindrome.dll gedef’d und ich cswus Aufruf mit Load Library ausführen konnte. Aber tun Sie immer noch nicht, was Hetland sagt und tut

Importiere _palindrome

in Python.

Wenn ich noch einmal auf alle Quellen zurückgehe, konnte ich das nicht herausfinden. Endlich fing ich an, die SWIG-Dokumentation von Anfang an zu lesen, und ließ nichts unversucht — Das Durchsuchen des Handbuchs ergab nicht den gefundenen Ort.

Am Ende des Einführungsabschnitts. 2.7 Integrieren in ein Build-System, unter dem Beispiel-Make-Prozess heißt es:

“Das obige Beispiel generiert native Build-Dateien wie Makefiles, nmake-Dateien und Visual Studio-Projekte, die SWIG aufrufen und die generierten C++-Dateien in _example.so (UNIX) oder _example.pyd (Windows) kompilieren. Für andere Zielsprachen unter Windows normalerweise wird eine dll anstelle einer .pyd-Datei generiert.”

Und das ist die Antwort auf das letzte Problem:

Der Kompilierschritt für die DLL sollte lauten:

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

(Ich bin nicht zurückgegangen und habe meine declspec-Deklarationen geändert, daher weiß ich nicht, ob sie notwendig waren, also waren sie auch noch da).

Ich habe eine Datei, _palindrome.pyd

Was wenn im PYTHONPATH (meins war local) funktioniert, und man das dann auch machen kann

Importiere _palindrome

aus _palindrome import is_palindrome

und verwenden Sie die exportierte, ordnungsgemäß verpackte und verpackte C-Funktion, die mit TDM-GCC kompiliert wurde, wie versprochen in Python. gcc, das MinGW64 in einer anderen Installation ist, weiß, wie man die .pyd-Datei macht. Ich habe die DLL und die Pyd unterschieden, da sie die gleiche Bytelänge hatten. Sie sind nicht das gleiche an Hunderten von Punkten.

Hoffe, das hilft jemand anderem.

1363100cookie-checkWie kann ich meine C-Erweiterungen mit MinGW-w64 in Python erstellen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy