16 Stimmen

zirkuläre abhängigkeiten zwischen dlls mit visual studio

Ich habe eine zirkuläre Abhängigkeit zwischen zwei Funktionen. Ich möchte, dass jede dieser Funktionen in einer eigenen DLL untergebracht ist. Ist es möglich, dies mit Visual Studio zu bauen?

foo(int i)
{
   if (i > 0)
      bar(i -i);
}

-> sollte zu foo.dll kompiliert werden

bar(int i)
{
   if (i > 0)
      foo(i - i);
}

-> sollte in bar.dll kompiliert werden

Ich habe zwei Projekte in Visual Studio erstellt, eines für foo und eines für bar. Indem ich mit den "Referenzen" spielte und ein paar Mal kompilierte, gelang es mir, die gewünschten DLLs zu erhalten. Ich würde jedoch gerne wissen, ob Visual Studio eine Möglichkeit bietet, dies auf saubere Weise zu tun.

Wenn sich foo ändert, muss bar nicht neu kompiliert werden, weil ich nur von der Signatur von bar abhänge, nicht von der Implementierung von bar. Wenn die Lib in beiden DLLs vorhanden ist, kann ich neue Funktionen in eine der beiden neu kompilieren, und das ganze System funktioniert weiterhin.

Der Grund, warum ich dies versuche, ist, dass ich ein Legacy-System mit zirkulären Abhängigkeiten habe, das derzeit statisch verknüpft ist. Wir wollen aus verschiedenen Gründen auf DLLs umsteigen. Wir wollen nicht warten, bis wir alle zirkulären Abhängigkeiten bereinigt haben. Ich habe über Lösungen nachgedacht und einige Dinge mit gcc unter Linux ausprobiert, und dort ist es möglich, das zu tun, was ich vorschlage. Man kann also zwei gemeinsam genutzte Bibliotheken haben, die voneinander abhängen und unabhängig voneinander gebaut werden können.

Ich weiß, dass zirkuläre Abhängigkeiten keine gute Sache sind, aber das ist nicht die Diskussion, die ich führen möchte.

0 Stimmen

Eine sehr interessante Frage. Ich weiß, etwas kann wie dies möglich ist, aber ich weiß nicht wirklich, wie - ich denke, es beinhaltet einige spezielle Befehlszeilen-Parameter an den Linker von EINER der dll's und die andere dll sollte eine einfache Abhängigkeit haben.

0 Stimmen

@PM: Wenn das der Fall ist, dann ist es die Art von Sache, die ein ständiges Problem sein wird, das vergessen wird, falsch konfiguriert wird, etc.

15voto

Daniel Earwicker Punkte 111630

Auf Unix-ähnlichen Systemen funktioniert das, weil sie die tatsächliche Auflösung von Verknüpfungen zur Ladezeit durchführen. Eine Shared Library weiß nicht, woher ihre Funktionsdefinition kommt, bis sie in einen Prozess geladen wird. Der Nachteil dabei ist, dass Sie es auch nicht wissen. Eine Bibliothek kann Funktionen in jeder anderen Bibliothek finden und aufrufen (oder sogar in der Hauptbinärdatei, die den Prozess überhaupt erst gestartet hat). Außerdem wird standardmäßig alles in einer gemeinsam genutzten Bibliothek exportiert.

Bei Windows funktioniert das überhaupt nicht. Nur explizit exportierte Dinge werden exportiert, und alle Importe müssen zum Zeitpunkt der Bibliotheksverknüpfung aufgelöst werden, da zu diesem Zeitpunkt die Identität der DLL, die jede importierte Funktion bereitstellt, bestimmt wurde. Dies erfordert eine Importbibliothek, gegen die gelinkt wird.

Sie können dieses Problem jedoch (mit etwas mehr Aufwand) umgehen. Verwenden Sie LoadLibrary um jede beliebige DLL zu öffnen, und verwenden Sie dann GetProcAddress um die Funktionen zu finden, die Sie aufrufen möchten. Auf diese Weise gibt es keine Einschränkungen. Aber die Einschränkungen bei der normalen Methode haben einen Grund.

Da Sie von statischen Bibliotheken zu DLLs übergehen wollen, klingt es, als würden Sie davon ausgehen, dass Sie jede statische Bibliothek in eine DLL umwandeln sollten. Das ist aber nicht die einzige Möglichkeit. Warum beginnen Sie nicht damit, den Code erst dann in DLLs umzuwandeln, wenn Sie ihn als ein in sich geschlossenes Modul identifizieren, das in ein mehrschichtiges Design ohne Zirkularität passt? Auf diese Weise können Sie schon jetzt mit dem Prozess beginnen, ihn aber trotzdem Stück für Stück angehen.

0 Stimmen

Ich denke, dass die "Delay-Loaded"-Option in Visual Studio auch die Frage des Autors löst, so wie Daniel es hier geschrieben hat.

6voto

annakata Punkte 72408

Ich habe tiefes Verständnis für Ihre Situation (wie durch Ihre Bearbeitung klargestellt), aber ich glaube fest daran, das Richtige zu tun, nicht das, was funktioniert vorläufig Wenn es irgendeine Möglichkeit gibt, müssen Sie meiner Meinung nach Refactor diese Projekte.

Beheben Sie das Problem, nicht das Symptom.

6voto

Nimloth Punkte 189

Es ist möglich, das LIB-Dienstprogramm mit .EXP-Dateien zu verwenden, um eine Reihe von DLLs mit einer zirkulären Referenz wie dieser zu "booten" (ohne vorherige .LIB-Dateien zu erstellen). Siehe MSDN-Artikel für Details.

Ich stimme mit den Vorrednern überein, dass diese Art von Situation durch eine Überarbeitung des Entwurfs vermieden werden sollte.

3voto

MetNP Punkte 541

Diese Frage stand bei meiner Suche nach "dll cyclic dependency" an erster Stelle, und auch wenn sie 10 Jahre alt ist, ist es eine Schande, dass die meisten Antworten auf "Refactoring" hinweisen, was ein sehr sehr dummer Ratschlag für ein großes Projekt ist und ohnehin keine Frage war.

Ich muss also darauf hinweisen, dass zyklische Abhängigkeiten nicht so gefährlich sind. Sie sind unter Unix/Linux völlig in Ordnung. Sie werden in vielen msdn-Artikeln als mögliche Situationen mit Möglichkeiten, sie zu umgehen . Sie kommen in JAVA vor (der Compiler löst das Problem durch Muilti-Pass-Compilierung). Zu sagen, dass Refactoring der einzige Weg ist, ist wie das Verbot von "Freunden" in Klassen.

  • dieser Absatz in einem Einsteigerhandbuch für Linker (David Drysdale) erklärt es gut für VS-Linker.

Der Trick besteht also darin, eine Kompilierung mit zwei Durchgängen zu verwenden: der erste, der nur "import-libs" erzeugt, und der zweite, der die dlls selbst erzeugt.

Für Visual Studio und jede grafische Seite kompilieren, ist es wahrscheinlich noch etwas seltsam. Aber wenn man seine eigenen Makefiles macht und den Linker-Prozess und die Flags besser beherrscht, ist es nicht so schwer zu machen.

Anhand der OP-Beispieldateien und der mingw-gcc-Syntax als Konzept zu zeigen (weil ich es getestet habe und sicher weiß, dass es unter Windows gut funktioniert), muss man: - Kompilieren/Verknüpfen von a.lib und b.lib ohne Angabe von zyklischen Bibliotheken:

g++ -shared -Wl,--out-implib=a.lib -o a.dll a.obj //without specifying b.lib  
g++ -shared -Wl,--out-implib=b.lib -o b.dll b.obj //without specifying a.lib

... zeigt 'undefined refernce errors' an und kann keine dll-s bereitstellen, aber es erstellt a.lib y b.lib die wir für die Verknüpfung im zweiten Durchgang benötigen:

g++ -shared -Wl,--out-implib=a.lib -o a.dll a.obj b.lib  
g++ -shared -Wl,--out-implib=b.lib -o b.dll b.obj a.lib

und das Ergebnis ist a.dll y b.dll mit einer ziemlich sauberen Methode. Die Verwendung von Microsoft-Compilern sollte ähnlich sein, mit ihrem Rat, link.exe zu lib.exe zu wechseln (habe es nicht getestet, scheint sogar sauberer, aber wahrscheinlich schwieriger, etwas Produktives daraus zu machen, im Vergleich zu mingw + Make-Tools).

1voto

Keith Punkte 2373

Wie wäre es damit:

Projekt A

Öffentliche Klasse A Implementiert C.IA

Public Function foo(ByVal value As C.IB) As Integer Implements C.IA.foo
    Return value.bar(Me)
End Function

Klasse beenden

Projekt B

Öffentliche Klasse B Implementiert C.IB

Public Function bar(ByVal value As C.IA) As Integer Implements C.IB.bar
    Return value.foo(Me)
End Function

Klasse beenden

Projekt C

Public Interface IA
    Function foo(ByVal value As IB) As Integer
End Interface

Public Interface IB
    Function bar(ByVal value As IA) As Integer
End Interface

Projekt D

Sub Main()

    Dim a As New A.A
    Dim b As New B.B

    a.foo(b)

End Sub

0 Stimmen

Vielen Dank für die schnellen Antworten. Dies würde funktionieren, aber ist nicht das, was ich tun möchte. Ich bin auf der Suche nach dem Compiler-Trick, der es mir ermöglicht, auf saubere Weise zu tun, was ich durch Kompilieren ein paar Mal und spielen mit den Abhängigkeiten getan habe.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X