Wie löse ich eine nicht aufgelöste externe Komponente, wenn ich C ++ Builder-Pakete verwende?

8

Ich experimentiere mit der Neukonfiguration meiner Anwendung, um die Verwendung von Paketen zu verbessern. Sowohl ich als auch ein anderer Entwickler, der ein ähnliches Experiment ausführt, stößt bei der Verknüpfung mit mehreren verschiedenen Paketen auf einige Probleme. Wir machen wahrscheinlich beide etwas falsch, aber Gott weiß was:)

Die Situation ist dies:

  • Das erste Paket, PackageA.bpl , enthält die C ++ Klasse FooA . Die Klasse wird mit der Direktive PACKAGE deklariert.
  • Das zweite Paket, PackageB.bpl , enthält eine Klasse, die von FooA , genannt FooB , erbt. Es enthält FooB.h , und das Paket wird mithilfe von Laufzeitpaketen erstellt und verweist auf PackageA , indem ein Verweis auf PackageA.bpi hinzugefügt wird.

  • Beim Erstellen von PackageB wird eine Feinkompilierung durchgeführt, aber die Verknüpfung schlägt mit einer Anzahl von nicht aufgelösten externen Elementen fehl, von denen die ersten sind:

    • [ILINK32 Error] Error: Unresolved external '__tpdsc__ FooA' referenced from C:\blah\FooB.OBJ
    • [ILINK32 Error] Error: Unresolved external 'FooA::' referenced from C:\blah\FooB.OBJ
    • [ILINK32 Error] Error: Unresolved external '__fastcall FooA::~FooA()' referenced from blah\FooB.OBJ

    usw.

Das Ausführen von TDump in PackageA.bpl zeigt:

%Vor%

Somit scheint die Klasse definitiv exportiert zu werden und verfügbar zu sein. Ich kann Einträge für die spezifischen Dinge sehen, nach denen ILink32 sucht und nicht findet. Das Ausführen von TDump in der BPI-Datei zeigt ähnliche Einträge.

Weitere Informationen

Die Klasse stammt von TObject ab, obwohl sie ursprünglich vor dem Refactoring in Pakete eine normale C ++ - Klasse war. (Mehr Details unten. Es scheint "sicherer" VCL-Klassen zu verwenden, wenn versucht wird, Probleme mit einem Delphi-ähnlichen Objekt zu lösen. Das ändert nur die Reihenfolge der nicht gelösten externen Elemente, um Method1 und% co_de nicht zu finden %, dann andere.)

Deklaration für Method2 :

%Vor%

und FooA :

%Vor%

Alle Methoden sind definitiv in den .cpp-Dateien implementiert, so dass sie nicht gefunden werden, weil sie nicht existieren! Die .cpp-Dateien enthalten auch FooB in der Nähe der Spitze, unter den Includes.

Fragen, die helfen könnten ...

  • Sind Pakete zuverlässig mit C ++ oder nur mit Delphi-Code verwendbar?
  • Verknüpft mit dem ersten Paket, indem ein Verweis auf seinen BPI korrekt hinzugefügt wird - soll das so sein? Ich könnte ein LIB verwenden, aber es scheint, das zweite Paket viel größer zu machen, und ich vermute, dass es statisch in den Inhalt des ersten verbindet.
  • Können wir die #pragma package(smart_init) -Direktive nur für PACKAGE -abgeleitete Klassen verwenden? Es gibt keine Compiler-Warnung, die es für Standard-C ++ - Klassen verwendet.
  • Ist das Teilen von Code in Pakete der beste Weg, das Ziel zu erreichen, Code zu isolieren und über definierte Layer / Interfaces zu kommunizieren? Ich habe diesen Pfad untersucht, weil es scheint, der C ++ Builder / Delphi Way zu sein, und wenn es funktionierte, sieht es attraktiv aus. Aber gibt es bessere Alternativen?
  • Ich bin sehr neu in der Verwendung von Paketen und kenne sie nur durch die Verwendung von Komponenten. Irgendwelche allgemeinen Ratschläge wären großartig!

Wir verwenden C ++ Builder 2010. Ich habe die Klassen- und Methodennamen in den obigen Codebeispielen erstellt, ansonsten sind die Details genau das, was wir sehen.

    
David M 28.04.2010, 05:19
quelle

3 Antworten

9

Nicht aufgelöstes externes

Das in Ihrem Fall nicht aufgelöste externe Objekt scheint darauf zurückzuführen zu sein, dass der Compiler den Pfad zu den Paketdaten nicht finden kann. Sie sollten herausfinden, ob:

  • Der Pfad existiert in der Compiler-Suchpfadliste.
  • Das Paket existiert im Standard-Paketverzeichnis.

Wenn einer von ihnen wahr ist, dann ist der Pfad nicht das Problem. Jedoch als Riho erwähnt auch, dass dies der wahrscheinlichste Grund für das Problem ist. Das Embarcadero-Dokumentations-Wiki gibt Folgendes über den nicht aufgelösten externen Fehler aus:

  

Das benannte Symbol wird in dem angegebenen Modul referenziert, ist aber nirgendwo in der Gruppe von Objektdateien und Bibliotheken, die in dem Link enthalten sind, definiert. Überprüfen Sie, ob das Symbol richtig geschrieben ist.

     

Sie werden diesen Fehler normalerweise von dem Linker für C- oder C ++ - Symbole sehen, wenn einer der folgenden Fälle auftritt:

     
  • Sie haben die Deklarationen eines Symbols von __pascal und __cdecl Typen in verschiedenen Quelldateien nicht richtig abgeglichen.
  •   
  • Sie haben den Namen einer Objektdatei, die Ihr Programm benötigt, weggelassen. Sie müssen alle erforderlichen Pakete manuell zur Liste "Benötigt" hinzufügen.
  •   
  • Sie haben die Emulationsbibliothek nicht verknüpft.
  •   

Wenn Sie C ++ - Code mit C-Modulen verknüpfen, haben Sie möglicherweise vergessen, externe C-Deklarationen in extern "C" einzubinden.

     

Sie könnten auch eine Falschbeziehung zwischen zwei Symbolen haben.

Quelle: Nicht aufgelöstes externes 'Symbol', auf das von 'Modul' verwiesen wird .

Da es von den - obwohl geänderten Klassennamen - scheint, ist es nicht der Fall eines Rechtschreibfehlers. Sie geben auch an, dass Sie das Paket zur Liste der Anforderungen hinzugefügt haben, sodass wir dies ebenfalls ausschließen. Da Sie keine Verbindung zu C-Modulen herstellen, können wir diesen Teil ebenfalls auslassen. Es weist also auf Probleme mit dem Verzeichnis hin.

Über die anderen Fragen

Ihre Fragen sind alle sehr interessant und viele der Fragen sind Fragen, die ich selbst gesucht habe, als ich anfing, Pakete und Komponenten für C ++ Builder zu entwickeln.

Sind Pakete zuverlässig mit C ++?

Pakete sind eine gute Lösung für C ++ Builder. Sowohl C ++ Builder als auch das Pascal-geschriebene VCL-Framework sind dafür ausgelegt, Pakete zu unterstützen. Dies bedeutet, dass sich bestimmte Implementierungen in C ++ Builder von anderen Compilern unterscheiden. Dies ist notwendig, um die Sprache kompatibel zu Delphi zu halten. Aus diesem Grund können Sie Pakete in C ++ Builder fast genauso einfach verwenden wie mit Delphi.

Wird eine Verknüpfung zum ersten Paket hergestellt, indem eine Referenz zu seinem BPI-Code hinzugefügt wird?

Um mit dem zweiten Teil Ihrer Frage hier zu beginnen, macht die Verwendung einer lib-Datei Ihr Paket größer, weil es eine statische Verknüpfung verwendet - damit Ihre Vermutung richtig ist. Jetzt zurück zum ersten Teil der Frage, die Verknüpfung zu einem Paket ist in Ordnung, indem Sie einen Verweis auf seine BPI hinzufügen. Sie müssen jedoch sicherstellen, dass die Pfadvariable korrekt als schlägt Riho in seiner Antwort vor.

Persönlich stelle ich immer sicher, dass meine Pakete den richtigen Verzeichnissen in Ihrem Benutzerordner entsprechen. Der Speicherort hängt von Ihrer Delphi-Version und Betriebssystemversion ab. Soweit ich mich erinnere, ist es unter den Dokumenten und Einstellungen \ all users \ shared documents \ Rad studio (Versionsnummer) \ Packages, aber ich könnte mich irren.

Können wir die PACKAGE -Direktive nur für TObject -abgeleitete Klassen verwenden?

Das Makro PACKAGE wird in __declspec(package) aufgelöst, Sie können es mit __declspec(dllexport) vergleichen. Der Unterschied zwischen diesen ist, dass das Paket verwendet wird, wenn es in einem Paket deklariert ist, und dllexport wird verwendet, wenn es in einer DLL deklariert wird. Es gibt ein Thema darüber in den offiziellen embarcadero Foren mit dem Titel __declspec (Paket) vs __declspec (dllexport) . Der Autor des ursprünglichen Posts stellt auch Ihre genaue Frage dazu, aber leider ist dieser Teil der Frage unbeantwortet.

Ich habe jedoch eine Theorie, und ich muss betonen, dass es nichts weiter als eine Theorie ist. Remy Lebeau schreibt als Antwort auf die Frage im Forumsbeitrag:

  

__ declspec (dllexport) kann für einfache Funktionen, Datenvariablen und verwendet werden   Nicht-VCL-Klassen und können in einfachen DLLs verwendet werden. __declspec (Paket) ist   Wird für VCL-Komponenten verwendet und kann nur mit Paketen verwendet werden.

Nach dem Lesen seiner Antwort scheint mir, dass das Paket einfach die Klasse exportiert, genau wie dllexport. Und da dllexport, so weit ich aus seiner Antwort lesen kann, nur in einfachen DLLs verwendet werden soll, müssen Sie das Paket verwenden, um (auch) Nicht-VCL-Klassen aus einem Paket zu exportieren.

Was an all dem interessant ist, ist, dass ein Paket im Grunde genommen eine DLL ist, soweit ich mich erinnere, aber ich muss zugeben, dass ich die Quelle dieser Information weder finden noch merken kann. p>

Ist das Teilen von Code in Pakete der beste Weg, um das Ziel zu erreichen, Code zu isolieren?

Pakete haben einige sehr prominente Stärken beim Erstellen wiederverwendbarer Komponenten für die VCL. Natürlich beschränkt die Verwendung von Paketen den Benutzer auf die Verwendung von C ++ Builder oder Delphi, aber für Komponenten, die geschrieben wurden, um das VCL-Framework zu nutzen, ist es eine ausgezeichnete Wahl. Richtig geschriebene Pakete können die Wiederverwendbarkeit von Komponenten erleichtern, und ich glaube, es ist die bevorzugte Methode zur Verteilung von Komponenten für die VCL.

Wenn Ihr Code jedoch das VCL-Framework in keiner Weise ausnutzt, würde ich die Verwendung einer normalen Bibliothek, entweder statisch oder dynamisch, in Erwägung ziehen, um einfach einen Cross-Compiler-freundlichen Ansatz zu erstellen.

Ob es einen besseren Ansatz zur Isolierung Ihres Codes gibt, hängt wirklich von dem Projekt ab, an dem Sie arbeiten. Ich möchte Code behalten, der durch die Verwendung von VCL-Klassen in Paketen kommuniziert, aber Code, der keine Verwendung von VCL-Klassen in regulären Bibliotheken erfordert. Bedenken Sie jedoch, dass VCL-Klassen problemlos in einer DLL verwendet werden können, Sie jedoch Sonderfälle behandeln müssen, wenn Sie Funktionen mit VCL-String-Klassen als Parameter oder Rückgabewerte exportieren.

Irgendwelche allgemeinen Ratschläge?

Ich bin selbst nicht der erfahrenste Entwickler von Paketen, aber ich habe festgestellt, dass die Deaktivierung der Laufzeitverknüpfung oft viele meiner Probleme löst, während es manchmal trivial ist, Probleme für Ihren eigenen Code zu beheben Komponenten von Drittanbietern, die Probleme damit haben. Abgesehen davon bin ich kein Fan davon, meine Pakete mit meiner Bewerbung zu verteilen, wie es in diesem Fall erforderlich ist. Aber um ehrlich zu sein, ist das eine Frage des Geschmacks.

Ich persönlich fand es schwierig, einige meiner Fragen richtig zu beantworten, als ich begann, Komponenten und Pakete zu erstellen. Die offizielle Hilfedatei ist nicht besonders informativ, aber wenn Sie den VCL-Quellcode durchsehen, erhalten Sie oft die beste Antwort auf Ihre Frage. Außerdem gibt es ein paar andere Websites, die Hilfe anbieten können, viele der Seiten zielen jedoch auf Delphi ab, aber daran müssen Sie sich allerdings gewöhnen.

Delphi Wikia hat einige gute Artikel über das Erstellen von Komponenten, insbesondere Komponenten erstellen und Pakete erstellen Es gibt auch ein BCB-Journal , das einer der wenigen C ++ Builder ist bestimmte Websites, es hat einige gute Artikel und ein akzeptables Forum. Die Delphi-Seiten bei About.com sind auch eine gute Quelle für Informationen, ich habe viele gute Hinweise gefunden und es ist schön dort zu wissen, insbesondere: Erstellen von benutzerdefinierten Delphi-Komponenten - Inside and Out .

    
Tommy Andersen 28.04.2010, 14:31
quelle
2

Vielleicht blöde Frage, aber sind deine BPI / BPL-Dateien im richtigen Pfad vom Linker zu finden? Ich habe einmal eine App in BCB5 erstellt, die mehrere verknüpfte Pakete verwendet, aber ich kann mich nicht erinnern, ob es etwas Besonderes daran gab, sie zu erstellen.

    
Riho 28.04.2010 05:51
quelle
1

Bei mir hat #pragma package (smart_init, weak) in der cpp-Datei das Problem gelöst. Siehe auch Ссылка Die Datei cpp- & gt; obj wird statisch verknüpft, ohne etwas anderes zu beeinflussen.

    
Peter 30.01.2013 12:42
quelle

Tags und Links