Website-Icon Embarcadero RAD Studio, Delphi, & C++Builder Blogs

Probleme beim Mischen von Classic- und Clangobjekten: Linker-Warnungen & Verbesserung der App-Stabilität

mixing classic and clang large size 2

Der C++Builder-Linker warnt Sie, wenn Sie mit Classic verknüpfte Objektdateien mischen und zusammenklammern, und hilft Ihnen so, Linker- oder Laufzeitfehler zu vermeiden.

Heute, im Jahr 2020, empfehlen wir die Verwendung der modernen Clang-Compiler, insbesondere mit der Arbeit, die wir für Win64 geleistet haben (z.B. völlig neuer Debugger) und den RTL-Verbesserungen, um ein Upgrade vom Klassiker einfach zu machen. Viele Kunden rüsten jedoch in Schritten auf: zuerst von klassischem Win32 auf Clang Win32 und danach Hinzufügen von Win64. Tatsächlich empfehlen wir dies oft direkt als Upgrade-Strategie, um in zwei Schritten zuerst auf Clang und dann auf Win64 umzusteigen.

Es gibt jedoch ein häufiges Problem, wenn man vom klassischen zum Clang-Compiler wechselt. Objektdateien (.obj- und .lib-Bibliotheken), die von den klassischen und Clang Win32-Compilern erzeugt werden, sind binär nicht miteinander kompatibel. (Sowohl Classic als auch Clang können gegen Delphi linken, aber Classic und Clang können nicht gegeneinander linken). Wenn Sie versuchen, eine Anwendung zu erstellen, bei der einige Teile mit Clang und andere mit Classic gemischt sind, können Sie alles von Linker-Fehlern bis hin zu Laufzeitinstabilität erwarten. Es ist jedoch leicht, dies versehentlich zu tun, sowohl bei einem Upgrade als auch einfach nur beim Hinzufügen einer neuen Bibliothek oder EXE zu Ihrem Projekt.

In 10.3.3, und dies wurde in der Online-Hilfe dokumentiert, aber damals nicht in einem Blog darüber berichtet, haben wir eine neue Linker-Warnung hinzugefügt, um Ihnen zu helfen, diese Situationen zu erkennen.

Bevor wir die Lösung zeigen, wollen wir einen kurzen Blick darauf werfen, was passieren kann, wenn Sie diesen Fehler in Ihren Builds haben.

Probleme bei inkompatiblen Compilern

In 10.3.3 und neuer erhalten Sie eine Linker-Warnung – siehe unten – vor einer der folgenden Meldungen. Wenn Sie jedoch eine ältere Version verwenden, bevor wir die Warnung zur Diagnose des Problems hinzugefügt haben, sehen Sie möglicherweise nur die folgenden Fehler. Diese erscheinen beim Verlinken der App.

Fehler bei der Verlinkung

Wenn eine mit der Clang-Toolchain erstellte Anwendung gegen eine Classic-Bibliothek gelinkt wird, können die folgenden Fehler auftreten:

[crayon-67687b536ec3d454541358/]

Wenn eine mit der Classic-Toolchain erstellte Anwendung gegen eine von Clang erstellte Bibliothek gelinkt wird, können die folgenden Fehler auftreten:

[crayon-67687b536ec49501054055/]

Laufzeitfehler

In einigen Fällen sehen Sie möglicherweise überhaupt keine Linker-Fehler, und Sie werden Ihre Anwendung ausführen. Höchstwahrscheinlich wird Ihre Anwendung irgendwann abstürzen und es wird schwierig sein, herauszufinden, warum, denn der Code sieht gut aus. In Wirklichkeit wird es daran liegen, dass zwei verschiedene Compiler Dinge auf unterschiedliche Weise tun – unterschiedliches Speicherlayout, Ausrichtung, Erwartungen an die Laufzeitbibliothek, Ausnahmebehandlung, alle möglichen Unterschiede.

Es ist keine gute Situation, wenn man entweder seltsame Linker-Fehler oder ein seltsames Laufzeitverhalten hat. Deshalb haben wir eine Warnung hinzugefügt, um diese Situation zu überprüfen.

Diagnose: eine neue Linker-Warnung

RAD Studio / C++Builder 10.3.3 und neuer warnt Sie davor, beim Verknüpfen Clang und Klassik zu vermischen. (Wenn Linker-Fehler wie die oben genannten auftreten, wird diese Warnung vor ihnen ausgegeben, so dass Sie die Warnung vor allen Fehlern sehen, die auf das Problem zurückzuführen sind).

Die Meldung lautet ‚Warnung: Compiler-Fehlanpassung.‘ und sagt Ihnen dann, was er erwartet und was er gefunden hat:

[crayon-67687b536ec4c125914024/]

Wie prüft der Linker also auf gemischte Objekte, und woher weiß er, was ihn erwartet?

Im obigen Fehler habe ich eine VCL-Anwendung in einer statischen Bibliothek verknüpfen. Die VCL-Anwendung wird mit Clang erstellt. Die Bibliothek wird mit Classic erstellt. Die Clang-Anwendung verkettet in der Bibliothek mit:

[crayon-67687b536ec50626667788/]

see documentation on linking with #pragma comment vs #link.

Es ist ziemlich leicht, den Fehler zu machen, dass die Compiler nicht übereinstimmen. Wie Sie auf dem Screenshot rechts sehen können, ist nicht leicht zu erkennen, welcher Win32-Compiler verwendet wird. Dies ist etwas, das wir verbessern könnten, aber im Moment wird die Zielplattform aufgelistet, nicht der Compiler.

Unser Compiler gibt jetzt in jedes Objekt einen Datensatz (ein kleines Stückchen Daten) aus, der angibt, mit welchem Compiler es gebaut wurde (z.B. Clang Win32.) Beim Linken erhält der Linker einen Satz von Objektdateien und Bibliotheken, in der Reihenfolge auf der Befehlszeile. Er schaut sich das erste Objekt an, mit dem er verknüpft, und merkt an, dass er erwartet, dass alle weiteren Objekte mit demselben Compiler wie das erste Objekt erstellt werden. Für jedes Objekt, in das er verlinkt (und für jedes Objekt in der Bibliothek eine Bibliothek erhält, bei der es sich nur um einen Satz von Objekten handelt), prüft er, ob es mit dem erwarteten Compiler gebaut wurde.

Wenn nicht, wird die obige Warnung ausgegeben, die Sie auch auf dem Bild rechts sehen können. Sie sehen, dass es das fehlerhafte Objekt auflistet und womit es gebaut wurde, und es erklärt auch, warum es nach einem anderen Compiler gesucht hat. Dies soll Ihnen bei der Diagnose Ihres Build-Setups helfen.

TLDR

Kurze Zusammenfassung: Das Mischen von Objektdateien, die mit zwei Compilern erstellt wurden, in eine Binärdatei ist eine schlechte Idee. Der Linker gibt Ihnen eine Warnung, wenn Sie dies tun, und sagt Ihnen, was mit was gebaut wird, damit Sie es korrigieren können. Dies behebt Linker-Probleme und behebt Probleme mit der Stabilität von Anwendungen!

Weiterführende Lektüre

Paketierungskomponenten oder Bibliotheken, die in klassischen und Clang C++ Win32-Compilern geschrieben wurden

Diese neue Docwiki-Seite befasst sich mit der Linker-Warnung, bietet aber auch etwas mehr Informationen. Sie befasst sich mit der Verwendung von Clang oder klassischen Binärdateien, wenn Sie Anwendungsentwickler sind und Anwendungen mit mehreren Teilen erstellen (vielleicht gegen eine Open-Source-C++-Bibliothek linken, die Sie ebenfalls erstellen), und hat auch einen weiteren Abschnitt für Bibliotheksentwickler (z.B. Komponenten oder Bibliotheken schreiben und sie an Ihre Kunden verteilen).

Die mobile Version verlassen