program story

Microsoft는 순환 참조가있는 어셈블리를 어떻게 만들었습니까?

inputbox 2020. 8. 12. 08:16
반응형

Microsoft는 순환 참조가있는 어셈블리를 어떻게 만들었습니까?


.NET BCL에는 다음 사이에 순환 참조가 있습니다.

  • System.dllSystem.Xml.dll
  • System.dllSystem.Configuration.dll
  • System.Xml.dllSystem.Configuration.dll

다음은 내가 의미하는 바를 보여주는 .NET Reflector의 스크린 샷입니다.

여기에 이미지 설명 입력

Microsoft가 이러한 어셈블리를 만든 방법은 나에게 미스테리입니다. 이를 허용하려면 특별한 컴파일 프로세스가 필요합니까? 여기서 흥미로운 일이 벌어지고 있다고 생각합니다.


Mono Project가 어떻게이 작업을 수행하는지 알 수 있습니다. 정리는 코드가 엉망이긴하지만 아주 간단합니다.

먼저 System.Xml.dll에 대한 참조가 필요한 부분없이 System.Configuration.dll을 컴파일합니다. 그런 다음 System.Xml.dll을 일반적인 방식으로 컴파일합니다. 이제 마법이 온다. System.Xml.dll에 대한 참조가 필요한 부분으로 System.configuration.dll을 다시 컴파일합니다. 이제 순환 참조를 사용한 성공적인 컴파일이 있습니다.

요컨대 :

  • A는 B가 필요한 코드와 B에 대한 참조없이 컴파일됩니다.
  • B가 컴파일됩니다.
  • A가 다시 컴파일됩니다.

RBarryYoung과 Dykam이 뭔가에 있습니다. Microsoft는 ILDASM을 사용하여 어셈블리를 분해하고 모든 내부 / 개인 항목 및 메서드 본문을 제거하고 IL을 다시 컴파일 (ILSM 사용)하여 '탈수 어셈블리'또는 메타 데이터 어셈블리로 다시 컴파일하는 내부 도구를 사용합니다. 이는 어셈블리의 공용 인터페이스가 변경 될 때마다 수행됩니다.

빌드하는 동안 실제 어셈블리 대신 메타 데이터 어셈블리가 사용됩니다. 그렇게하면주기가 깨집니다.


Dykam이 설명하는 방식으로 수행 할 수 있지만 Visual Studio는이를 수행하지 못하도록 차단합니다.

명령 줄 컴파일러 csc.exe를 직접 사용해야합니다.

  1. csc / target : library ClassA.cs

  2. csc / target : library ClassB.cs /reference:ClassA.dll

  3. csc / target : library ClassA.cs ClassC.cs /reference:ClassB.dll


//ClassA.cs
namespace CircularA {
    public class ClassA {
    }
}


//ClassB.cs
using CircularA;
namespace CircularB {
    public class ClassB : ClassA  {
    }
}


//ClassC.cs
namespace CircularA {
    class ClassC : ClassB {
    }
}

Its pretty easy to do in Visual Studio as long as you don't use project references... Try this:

  1. Open visual studio
  2. Create 2 Class Library projects "ClassLibrary1" & "ClassLibrary2".
  3. Build
  4. From ClassLibrary1 add a reference to ClassLibrary2 by browsing to the dll created in step 3.
  5. From ClassLibrary2 add a reference to ClassLibrary1 by browsing to the dll created in step 3.
  6. Build again (Note: if you make changes in both projects you would need to build twice to make both references "fresh")

So this is how you do it. But seriously... Don't you EVER do it in a real project! If you do, Santa wont bring you any presents this year.


I guess it could be done by starting with an acyclic set of assemblies and using ILMerge to then coalesce the smaller assemblies into logically related groups.


Well, I've never done it on Windows, but I have done it on a lot of the compile-link-rtl environments that served as the practical progenitors for it. What you do is first make stub "targets" without the cross-references then link, then add the circular references, then re-link. The linkers generally do not care about circular refs or following ref chains, they only care about being able to resolve each reference on it's own.

So if you have two libraries, A and B that need to reference each other, try something like this:

  1. Link A without any refs to B.
  2. Link B with refs to A.
  3. Link A, adding in the refs to B.

Dykam makes a good point, It's compile, not link in .Net, but the principle remains the same: Make your cross-referenced sources, with their exported entry points, but with all but one of them having their own references to the others stubbed out. Build them like that. Then, unstub the external references and rebuild them. This should work even without any special tools, in fact, this approach has worked on every operating system that I have ever tried it on (about 6 of them). Though obviously something that automates it would be a big help.


One possible approach is to use conditional compilation (#if) to first compile a System.dll that doesn't depend on those other assemblies, then compile the other assemblies, and at last recompile System.dll to include the parts depending on Xml and Configuration.


기술적으로는 이것들이 전혀 컴파일되지 않고 수작업으로 조립되지 않았을 가능성이 있습니다. 결국 이것들은 저수준 라이브러리입니다.

참고 URL : https://stackoverflow.com/questions/1316518/how-did-microsoft-create-assemblies-that-have-circular-references

반응형