zirkuläre Abhängigkeiten zwischen DLLs mit Visual Studio

8

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

%Vor%

- & gt; sollte in foo.dll

kompilieren %Vor%

- & gt; sollte in bar.dll

kompilieren

Ich habe zwei Projekte im Visual Studio erstellt, eins für foo und eins für bar. Indem ich mit den 'Referenzen' gespielt und einige Male kompiliert habe, habe ich es geschafft, die DLLs zu bekommen, die ich möchte. Ich würde jedoch gerne wissen, ob Visual Studio eine Möglichkeit bietet, dies auf eine saubere Art und Weise zu tun.

Wenn foo sich ändert, muss bar nicht neu kompiliert werden, weil ich nur von der Signatur von bar abhängig bin, nicht von der Implementierung von bar. Wenn beide DLLs die lib vorhanden haben, kann ich neue Funktionen in beide kompilieren und das ganze System funktioniert immer noch.

Der Grund, warum ich das versuche, ist, dass ich ein Altsystem mit zirkulären Abhängigkeiten habe, das derzeit statisch verknüpft ist. Wir wollen aus verschiedenen Gründen auf dlls zugehen. Wir wollen nicht warten, bis wir alle zirkulären Abhängigkeiten aufgeräumt haben. Ich habe über Lösungen nachgedacht und einige Sachen mit gcc auf Linux ausprobiert und dort ist es möglich zu tun, was ich vorschlage. So können Sie zwei gemeinsam genutzte Bibliotheken haben, die voneinander abhängig sind und unabhängig voneinander erstellt werden können.

Ich weiß, dass zirkuläre Abhängigkeiten nicht gut sind, aber das ist nicht die Diskussion, die ich haben möchte.

    
Kris Steegmans 12.12.2008, 13:59
quelle

8 Antworten

11

Der Grund, warum es auf Unix-ähnlichen Systemen funktioniert, ist, dass sie die tatsächliche Verbindungsauflösung zur Ladezeit durchführen. Eine gemeinsam genutzte Bibliothek weiß nicht, woher ihre Funktionsdefinition kommt, bis sie in einen Prozess geladen wird. Der Nachteil davon 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 gestartet hat). Außerdem wird standardmäßig alles in einer gemeinsam genutzten Bibliothek exportiert.

Windows funktioniert überhaupt nicht so. Nur explizit exportierte Objekte werden exportiert, und alle Importe müssen zur Bibliotheksverbindungszeit aufgelöst werden. Zu diesem Zeitpunkt wurde die Identität der DLL ermittelt, die jede importierte Funktion bereitstellt. Dies erfordert eine Importbibliothek, mit der verlinkt werden kann.

Allerdings kann man dies (mit etwas Zusatzarbeit) umgehen. Verwenden Sie LoadLibrary , um eine 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 in der normalen Methode gibt es aus einem bestimmten Grund.

Wenn Sie von statischen Bibliotheken zu DLLs wechseln wollen, klingt es so, als würden Sie davon ausgehen, dass Sie jede statische Bibliothek zu einer DLL machen sollten. Das ist nicht deine einzige Option. Warum fangen Sie nicht an, Code nur dann in DLLs zu verschieben, wenn Sie ihn als eigenständiges Modul identifizieren, das in ein mehrschichtiges Design ohne Zirkularität passt? Auf diese Weise können Sie den Prozess jetzt beginnen, aber immer noch Stück für Stück angreifen.

    
Daniel Earwicker 22.12.2008 21:16
quelle
7

Ich habe tiefe Sympathie mit Ihrer Situation (wie durch Ihre Bearbeitung klargestellt wurde), aber als ein überzeugter Anhänger davon, das Richtige zu tun, nicht das, was jetzt funktioniert , wenn es überhaupt eine Möglichkeit gibt Ich denke, Sie müssen diese Projekte refaktorieren .

Beheben Sie das Problem nicht das Symptom.

    
annakata 12.12.2008 15:18
quelle
3

Es ist möglich, das LIB-Dienstprogramm mit .EXP-Dateien zu verwenden, um eine Reihe von DLLs mit einem Zirkelverweis wie diesem zu "bootstrappen" (Build ohne vorherige .LIB-Dateien). Weitere Informationen finden Sie im MSDN-Artikel .

Ich stimme mit anderen darüber überein, dass diese Art von Situation vermieden werden sollte, indem das Design überarbeitet wird.

    
stephane.leclair 28.05.2011 20:39
quelle
1

Wie wäre es damit:

Projekt A

Öffentliche Klasse A     Implementiert C.IA

%Vor%

Ende Klasse

Projekt B

Öffentliche Klasse B     Implementiert C.IB

%Vor%

Ende Klasse

Projekt C

%Vor%

Projekt D

%Vor%     
Keith 12.12.2008 15:23
quelle
0

Es ist nicht möglich, sauber zu machen. Weil beide voneinander abhängen, wenn A sich ändert, muss B neu kompiliert werden. Weil B neu kompiliert wurde, hat es sich geändert und A muss neu kompiliert werden und so weiter.

Das ist Teil des Grundes, warum zirkuläre Abhängigkeiten schlecht sind und ob Sie wollen oder nicht, Sie können das nicht aus der Diskussion herauslassen.

    
Rob Prouse 12.12.2008 14:31
quelle
0

Visual Studio erzwingt im Allgemeinen Abhängigkeiten, da sich die Funktionsadressen innerhalb der neu kompilierten DLL ändern können. Auch wenn die Signatur identisch sein kann, kann sich die exponierte Adresse ändern.

Wenn Sie jedoch feststellen, dass Visual Studio in der Regel die gleichen Funktionsadressen zwischen den Builds verwaltet, können Sie eine der Buildeinstellungen für "Nur Projekt" verwenden (ignoriert Abhängigkeiten). Wenn Sie dies tun und eine Fehlermeldung erhalten, dass die Abhängigkeits-DLL nicht geladen werden kann, erstellen Sie beide einfach neu.

    
Brian 22.12.2008 20:55
quelle
0

Sie müssen die zwei DLLs entkoppeln, die Schnittstellen und die Implementierung in zwei verschiedene DLLs platzieren und dann die späte Bindung verwenden, um die Klasse zu instanziieren.

%Vor% %Vor% %Vor% %Vor%

Die "Factory" -Klassen sind technisch nicht notwendig, aber es ist viel schöner zu sagen:

%Vor%

im Anwendungscode als:

%Vor%

aus folgenden Gründen:

  1. Sie können einen "Cast" im Anwendungscode vermeiden, was eine gute Sache ist
  2. Wenn sich die DLL, die die Klasse hostet, ändert, müssen Sie nicht alle Clients ändern, nur die Factory.
  3. Die Code-Vervollständigung funktioniert immer noch.
  4. Abhängig von Ihren Anforderungen müssen Sie Culture-Aware- oder Key-Signed-DLLs aufrufen. In diesem Fall können Sie dem CreateInstance-Aufruf in der Factory an einem Ort weitere Parameter hinzufügen.

- Kenneth Kasajian

    
zumalifeguard 04.09.2009 00:49
quelle
0

Der einzige Weg, wie Sie das "sauber" umgehen (und ich verwende den Begriff lose), besteht darin, eine der statischen / Verbindungszeitabhängigkeiten zu eliminieren und sie in eine Laufzeitabhängigkeit umzuwandeln.

Vielleicht in etwa so:

%Vor%

Foo.dll wird die Funktion exportieren. Bar.dll versucht nicht länger, die Funktion zu importieren; Stattdessen löst es die Funktionsadresse zur Laufzeit auf.

Rollen Sie Ihre eigenen Fehlerbehandlung und Leistungsverbesserungen.

    
ijprest 04.09.2009 01:04
quelle

Tags und Links