2008-12-12 9 views
8

У меня есть круговая зависимость между двумя функциями. Я хотел бы, чтобы каждая из этих функций находилась в собственной DLL. Можно ли построить это с помощью визуальной студии?Круговые зависимости между dll с визуальной студией

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

-> компилируется в foo.dll

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

-> компилируется в bar.dll

я создал два проекта в Visual Studio, один для обув и один для бара , Играя с «Литературами» и компилируя несколько раз, мне удалось получить DLL, которую я хочу. Однако я хотел бы знать, предлагает ли визуальная студия способ сделать это чистым способом.

Если foo изменяет, панель не нужно перекомпилировать, потому что я полагаюсь только на подпись бара, а не на реализацию бара. Если у обеих dll есть lib, я могу перекомпилировать новую функциональность в одну из двух, и вся система все еще работает.

Причина, по которой я пытаюсь это сделать, заключается в том, что у меня есть унаследованная система с круговыми зависимостями, которая в настоящее время статически связана. Мы хотим двигаться по направлению к dll по разным причинам. Мы не хотим ждать, пока мы очистим все круговые зависимости. Я думал о решениях и пробовал некоторые вещи с помощью gcc on linux, и там можно сделать то, что я предлагаю. Таким образом, вы можете иметь две разделяемые библиотеки, которые зависят друг от друга и могут быть построены независимо друг от друга.

Я знаю, что круговые зависимости не очень хорошие, но это не та дискуссия, которую я хочу иметь.

+0

Очень интересный вопрос. Я знаю, что возможно, что это возможно, но я не знаю, как это сделать - я думаю, что это связано с некоторыми специальными параметрами командной строки для компоновщика ONE из dll, а другая dll должна иметь простую зависимость. – Paulius 2008-12-12 15:04:42

+0

@PM: Если это так, то это то, что будет постоянной проблемой, забытой, неправильно сконфигурированной и т. Д. – annakata 2008-12-12 15:19:56

ответ

0

Непонятно. Поскольку они оба зависят друг от друга, если A изменяется, то B необходимо перекомпилировать. Поскольку B был перекомпилирован, он изменился, и A необходимо перекомпилировать и так далее.

Это часть причин, по которым круговые зависимости плохи и хотите вы этого или нет, вы не можете оставить это вне обсуждения.

+0

Если A изменяется, B не нужно перекомпилировать, потому что я полагаюсь только на подпись от A, а не от реализации A. Если обе библиотеки dll имеют lib, я могу перекомпилировать новую функциональность в одну из двух, и вся система все еще работает. – 2008-12-12 14:46:25

+0

Вы упомянули о работе со ссылками, поэтому я предположил, что вы работаете с управляемым кодом. Управляемый код не использует заголовки из других проектов и работает таким образом. – 2008-12-12 16:28:32

7

Я глубоко сочувствую вашей ситуации (как уточняется вашими изменениями), но как твердый верующий в правильном ведении, а не в том, что работает на данный момент, если есть какая-то возможность вообще, я думаю, вам нужно refactor Эти проекты.

Устранить проблему не симптом.

1

Как об этом:

Проект A

Открытый класс A Реализует C.IA

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

End Class

Проект B

Публичный класс B Реализует C.IB

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

End Class

Проект 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 

Проект D

Sub Main() 

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

    a.foo(b) 

End Sub 
+0

Спасибо за быстрые ответы. Это будет работать, но я не хочу этого делать. Я ищу трюк компилятора, который позволяет мне делать чистым способом, что я сделал, компилируя несколько раз и играя с зависимостями. – 2008-12-12 15:33:38

0

Visual Studio будет следить за соблюдением зависимостей, вообще говоря, так как функция адресов может изменяться внутри только что скомпилированной библиотеки DLL. Несмотря на то, что подпись может быть одинаковой, отображаемый адрес может измениться.

Однако, если вы заметили, что Visual Studio обычно поддерживает одни и те же функциональные адреса между сборками, вы можете использовать один из параметров сборки «Только для проекта» (игнорирует зависимости). Если вы это сделаете и получите сообщение об ошибке, чтобы не загружать DLL зависимостей, просто перестройте их.

11

Причина, по которой он работает в Unix-подобных системах, заключается в том, что они выполняют фактическое разрешение соединения во время загрузки. Общая библиотека не знает, где будет определяться ее определение функции до тех пор, пока она не будет загружена в процесс. Недостатком этого является то, что вы тоже не знаете. Библиотека может находить и вызывать функции в любой другой библиотеке (или даже в главном двоичном файле, который запустил этот процесс в первую очередь). Также по умолчанию все в общей библиотеке экспортируется.

Windows не работает, как будто. Экспортируются только экспортированные вещи, и все импорт должен быть разрешен во время ссылки на библиотеку, после чего определяется идентификатор DLL, который будет предоставлять каждую импортированную функцию. Для этого требуется связать библиотеку импорта.

Однако вы можете (с некоторой дополнительной работой) обойти это. Используйте LoadLibrary, чтобы открыть любую понравившуюся вам DLL, а затем используйте GetProcAddress, чтобы найти функции, которые вы хотите позвонить. Таким образом, ограничений нет. Но ограничения в обычном методе существуют по какой-то причине.

Как вы хотите перейти от статических библиотек к DLL, это звучит так, будто вы предполагаете, что вы должны сделать каждую статическую библиотеку в DLL. Это не единственный вариант. Почему бы не начать перемещать код в библиотеки DLL только тогда, когда вы идентифицируете его как автономный модуль, который вписывается в многоуровневый дизайн без округления? Таким образом, вы можете начать процесс сейчас, но все равно нападать на него за штуку одновременно.

0

Вам необходимо отделить две библиотеки DLL, помещая интерфейсы и реализацию в две разные библиотеки, а затем используя последнее связывание для создания экземпляра класса.


// IFoo.cs: (build IFoo.dll) 
    interface IFoo { 
     void foo(int i); 
    } 

    public class FooFactory { 
     public static IFoo CreateInstance() 
     { 
     return (IFoo)Activator.CreateInstance("Foo", "foo").Unwrap(); 
     } 
    } 

// IBar.cs: (build IBar.dll) 
    interface IBar { 
     void bar(int i); 
    } 

    public class BarFactory { 
     public static IBar CreateInstance() 
     { 
     return (IBar)Activator.CreateInstance("Bar", "bar").Unwrap(); 
     } 
    } 

// foo.cs: (build Foo.dll, references IFoo.dll and IBar.dll) 
    public class Foo : IFoo { 
     void foo(int i) { 
     IBar objBar = BarFactory.CreateInstance(); 
     if (i > 0) objBar.bar(i -i); 
     } 
    } 

// bar.cs: (build Bar.dll, references IBar.dll and IFoo.dll) 
    public class Bar : IBar { 
     void bar(int i) { 
     IFoo objFoo = FooFactory.CreateInstance(); 
     if (i > 0) objFoo.foo(i -i); 
     } 
    } 

Классы "Фабрика" технически не является необходимым, но это гораздо лучше сказать:

IFoo objFoo = FooFactory.CreateInstance(); 

в коде приложения, чем:

IFoo objFoo = (IFoo)Activator.CreateInstance("Foo", "foo").Unwrap(); 

из следующих причин:

  1. Вы можете избежать "слепок" в коде приложения, что это хорошая вещь
  2. Если DLL, в которой размещаются изменения класса, вам не нужно менять всех клиентов, просто фабрику.
  3. Код-завершение все еще wroks.
  4. В зависимости от ваших потребностей вам необходимо вызвать библиотеки, поддерживающие культуру или ключевые слова, и в этом случае вы можете добавить дополнительные параметры для вызова CreateInstance на заводе в одном месте.

- Кеннет Kasajian

0

Единственный способ вы получите вокруг этого «чисто» (и я использую термин свободно) будет устранить один из статических/зависимостей связь времени и изменения он зависит от времени выполнения.

Может быть что-то вроде этого:

// foo.h 
#if defined(COMPILING_BAR_DLL) 
inline void foo(int x) 
{ 
    HMODULE hm = LoadLibrary(_T("foo.dll"); 
    typedef void (*PFOO)(int); 
    PFOO pfoo = (PFOO)GetProcAddress(hm, "foo"); 
    pfoo(x); // call the function! 
    FreeLibrary(hm); 
} 
#else 
extern "C" { 
__declspec(dllexport) void foo(int); 
} 
#endif 

foo.dll будет экспортировать функцию. Bar.dll больше не пытается импортировать функцию; вместо этого он решает адрес функции во время выполнения.

Внесите ваши собственные ошибки обработки и улучшения производительности.

3

Возможно использование утилиты LIB с файлами .EXP в "bootstrap" (сборка без предшествующих файлов .LIB) набора DLL с круговой ссылкой, такой как эта. См. MSDN article.

Я согласен с другими людьми выше, что такого рода ситуации следует избегать, пересмотрев дизайн.