Development/C#

[제프리 리처의 CLR via C#] 여러 모듈을 하나의 어셈블리로 통합하기

오늘도 진이 2021. 2. 22. 14:01

1부. CLR의 기본

2장. 빌드, 패키징, 배포, 응용프로그램과 타입의 관리

여러 모듈을 하나의 어셈블리로 통합하기

  • 어셈블리 - 타입에 대한 정의가 담겨있는 파일과 리소스 파일들을 묶은 컬렉션
  • 매니페스트 - 어셈블리의 일부로 포함되는 여러 다양한 파일들의 이름을 저장하는 메타데이터 테이블들의 또 다른 집합
  • 어셈블리의 버전, 문화권, 게시자, 외부에서 사용할 수 있도록 공개된 타입들, 어셈블리를 이루고 있는 파일들에 대해서도 설명
  • 어셈블리의 주요한 특징
    • 어셈블리 안에는 재사용 가능한 타입들을 정의
    • 어셈블리에는 버전 번호가 기록
    • 어셈블리는 어셈블리에 관련된 보안 정보들을 가지고 있을 수 있다.
  • 패키지로 만들고, 버전 번호를 부여하고, 보안을 유지하며, 타입을 재사용할 수 있도록 하기 위해서는 어셈블리의 일부가 될 수 있도록 모듈들을 구성
  • 왜 마이크로소프트가 어셈블리라는 개념을 소개했는지 그이유
    • 어셈블리는 논리적인 개념과 물리적인 개념의 재사용 가능한 타입을 분리해서 생각할 수 있도록 도와주기 때문
  • codeBase 요소 - 어셈블리 파일을 어느 위치에서 가져올 수 있는지에 대한 URL을 파악
  • 어셈블리 로드
    • CLR은 주소에 개재된 파일을 다운로드하여 캐시에 저장하고 그 파일을 로드
    • 파일을 사용할 수 없는 경우에는 FileNotFoundException 예외를 실행 중에 발생
  • 다중 파일 어셈블리를 사용하려는 이유
    • 배포하려는 타입들을 몇 개의 파일로 쪼개어 분할 배포할 수 있고, 앞에서 언급한 것과 같이 인터넷상에서 다운로드할 경우 필요한 파일만을 다운로드하여 효율성을 개선할 수 있다. 뿐만 아니라 사용자가 결제한 기능에 해당되는 부분만을 다운로드하고 설치하도록 만들 때에도 활용할 수 있다.
    • 리소스나 데이터 파일들을 어셈블리에 포함시킬 수도 있다. 보헙료에 관련된 계산을 수행하는 타입을 예로 들어보자. 이 타입이 제공하는 계산 기능이 동작하도록 만들기 위해서 갱신된 데이터를 필요로 할 수 있다. 소스 코드에 이러한 데이터를 포함시키지 않는 대신, 이후에 살펴볼 AL.EXE(어셈블리링커)와 같은 도구를 사용해서 포함하려는 파일이 텍스트 파일이든, Microsoft Excel에서 만든 스프레드시트 파일이든 종류에 관계없이 응용프로그램이 해당 파일을 다룰 수 있는 코드만 정확히 구현하고 있다면, 필요한 데이터를 어셉블리의 일부로 포함시켜 배포할 수 있다.
    • 하나의 어셈블리를 만들면서 여러 다른 프로그래밍 언어로 만든 타입을 하나로 통합할 수 있다. 예를 들어 어떤 타입은 C#으로 만들고, 또 어떤 타입은 Microsoft Visual Basic .NET 혹은 그 외 기타 CLR을 지원하는 프로그래밍 언어로 만들어 포함시킬 수 있다. 각 소스 코드를 처리할 수 있는 해당 언어의 컴파일로 컴파일할 때 분리된 모듈로 만들도록 할 수 있다. 그 후 만들어진 모듈들을 하나의 어셈블리로 통합할 수 있는 도구를 사용할 수 있다. 이 어셈블리를 사용하는 개발자들이 보기에는 이 안에 단지 여러 개의 타입들이 포함되어 있으며, 어떤 언어를 사용해서 개발한 것인지는 정확히 알 수 없다. 하지만 만약 필요하다면 ILDASM.EXE 도구를 실행하여 각 모듈들이 가지고 있는 IL 소스 코드를 역어셈블리 과정을 통해 얻어낼 수 있다. 그 다음, ILASM.EXE를 실행하여 모든 IL 소스 코드 파일들을 전달하면, 모든 타입들을 포함하는 단일 결과 파일로 만들어질 것이다. 이러한 기법을 사용할 수 있으려면 사용하려는 컴파일러가 IL 전용 코드를 만들어낼 수 있는 기능을 구현해야 한다.
  • 어셈블리
    • 재사용 가능하고
    • 버전을 관리할 수 있으며
    • 보안을 준수하는 기본 단위가 된다는 것
    • 타입이나 리소스들을 몇 개의 파일로 분할해서 배포하는 방법도 제공하여 어떤 패키지를 선택하여 배포할 것인지를 사용자가 결정하게 할 수도 있다.
    • CLR이 매니페스트를 포함한 파일을 로드할 떄 현재 로드한 어셈블리가 참조하는 또 다른 타입이나 리소스가 들어있는 어셈블리를 어디에서 로드할 수 있는지에 대한 정보도 같이 파악하는 것도 가능
  • [표2-3] 매니페스트 메타데이터 테이블
  • 매니페스트를 사용함으로써 어셈블리를 사용하는 프로그램과 어셈블리의 분할 사이에 간접 계층을 제공하고, 어셈블리가 최대한 자신의 정보를 자기 설명적인 상태로 유지할 수 있도록 해줌
  • C# 컴파일러는 /t:exe, /t:winexe, /t:appcontainerexe, /t:library, /t:winmdobj 스위치를 지정하여 실행하면 어셈블리를 생성 → 컴파일러가 단일 PE 파일을 만들고 그 안에 매니페스트 메타데이터 테이블을 넣도록 한다.
  • C# 컴파일러는 /t:module 스위치를 지원 → 컴파일러에 PE 파일을 만들도록 하지만 매니페스트 메타데이터 테이블을 포함하지 않도록 지시
  • [그림 2-1] 한 쪽에 매니페스트를 포함하는 두 개의 관리 모듈로 구성된 다중 파일 어셈블리
  • 메타데이터 토큰은 4바이트 값
    • 상위 1바이트 - 토큰의 유형을 결정
    • 나머지 3바이트 - 메타데이터 테이블상의 행 번호를 가리킨다.
  • 클라이언트의 코드가 실행될 때 메서드를 호출
  • 메서드를 처음 호출할 때
    • CLR은 메서드가 매개변수의 타입, 반환되는 타입, 또는 지역 변수의 타입으로 어떤 타입을 참조하고 있는지 파악
    • 그 다음, CLR은 참조되는 어셈블리에서 매니페스트를 포함하는 파일을 로드
      • 만약 이 파일 내에서 해당되는 타입을 직접 가져올 수 있다면, 해당되는 파일을 다시 로드하여 같은 절차를 거쳐 필요할 때 사용할 수 있도록 타입에 대한 정보를 기록
  • CLR은 실제 어셈블리를 메서드가 참조하는 타입이 들어있는 어셈블리가 로드되지 않았을 때에만 로드
  • 즉 프로그램을 실행할 때, 컴파일 할 때와는 다르게 어셈블리에 연관된 모든 파일들이 존재하지 않아도 된다.
  • Visual Studio에서 어셈블리를 프로젝트에 추가하기
    • [그림2-2] Visual Studio의 참조 관리자 대화 상자
  • 어셈블리 링커 사용하기
    • C# 컴파일러의 /addmodule 같은 스위치를 제공하지 않을 수도 있는 컴파일러 또는 여러 다른 종류의 컴파일러들이 만들어낸 모듈을 어셈블리로 연결하기 위한 목적으로 요긴하게 사용
    • 또는 어셈블리 패키징을 할 떄 필요한 종속성이 무엇인지 알기 어려운 떄에도 활용할 수 있다.
    • 그 외에 리소스 전용 어셈블리를 만들기 위해서 AL.EXE 를 사용할 수 있는데, 이런 유형의 어셈블리를 위성 어셈블리라고 부르며, 보통 지역화를 위하여 쓰인다.
    • [그림 2-3] 세 개의 관리 모듈과 한 개의 매니페스트로 구성된 다중 파일 어셈블리
  • 어셈블리에 리소스 파일 추가하기
    • ManifrestResourceDef 테이블
    • FileDef 테이블