삽질의 현장/- .NET

#069_닷넷(.NET)_.Net Framework 기본 - 어셈블리(assembly)

shovelman 2015. 11. 7. 09:06


안녕하세요 삽잡이입니다.


이번 시간부터 본격적으로 닷넷에서 제공해주는 어셈블리에 대해서 알아보려고합니다.

글이 산으로 갈 수 있으니 주의하시고...

시작해보겠습니다.



닷넷 플렛폼의 특징 중 하나가 바로 바이너리를 재사용할 수 있다는 것입니다.

즉, 외부의 어셈블리에 포함된 타입을 재사용할 수 있다는 것을 의미합니다.


그렇다면 어셈블리란 무엇일까요?

어셈블리의 정의는

'버전 관리되고 배포 되는 프로그램의 단위'를 뜻합니다.


어셈블리는 두 가지의 종류로 배포될 수 있습니다.

즉, 응용 프로그램 하나 혹은 여러 프로그램에서 사용하는지에 따라 

두가지로 나뉠 수 있게 됩니다.

바로, '공유 어셈블리'와 '전용 어셈블리'로 나뉠 수 있게 되지요.


전용 어셈블리는 응용 프로그램 하나에,

공유 어셈블리는 여러 응용 프로그램에서 사용되는 어셈블리입니다.


각각 공유 어셈블리는 GAC라는 '전역 어셈블리 캐시'에 위치합니다.

대표적인 공유 어셈블리에는 BCL이 있지요.

mscorlib라는 물리적인 파일에 보관되어있는 해당 라이브러리는

닷넷 라이브러리 어셈블리입니다.

여기에 우리가 닷넷에서 사용하는 대다수의 많은 기능들이 들어가있습니다.



닷넷 플렛폼에서 만든 아무 파일이나 만들어 실행한 뒤 

해당 바이너리를 디스어셈블리 해보면 항상 공유 어셈블리를 가지고 있는 것을 확인할 수 있습니다.


이해가 가시지 않으신다면 우선은 넘어가셔도 됩니다.

아래에서 다시 언급하도록 하겠습니다.


전용 어셈블리는 응용프로그램의 디렉터리에 위치하게 됩니다.

즉, 실행 프로그램과 같은 디렉터리에 위치하게 되면 실행이 가능하다 이겁니다.

만약, 같은 디렉터리에 없다면 당연히 실행이 되지 않습니다.

왜냐, 해당 디렉터리에 있는 어셈블리 형식만을 참조하기 때문입니다.


닷넷 플렛폼에서는 한 덩어리의 실행 파일을 

여러개의 닷넷 어셈블리 파일로 나눌 수 있습니다.

이렇게 되면, 언어 중립적인 코드 재사용을 할 수 있다는 

어마어마한 장점을 가지게 됩니다.





어셈블리는 단일 파일 어셈블리와 다중 파일 어셈블리로 나뉘게됩니다.


*.dll 혹은 *.exe 확장자라는 물리적 바이너리가 단 하나인 어셈블리가 있다면,

*.exe * n *.dll * n  즉, 여러개의 물리적 바이너리가 합쳐진 어셈블리가 있습니다.

그래서 어셈블리는 논리적인 단위라고도 합니다.


바이너리는 닷넷의 컴파일러에 의해 컴파일이 된 물리적인 파일을 의미합니다.

이 바이너리 하나가 단일 파일 어셈블리가 될 수도,

여러 바이너리들이 모여 다중 파일 어셈블리가 될 수도 있게 된다는 것입니다.



단일 파일 어셈블리는 물리적 파일 하나로 이루어진 어셈블리입니다.


간단하지요...

이 어셈블리 내부에 들어가는 정보들은 모~두 이전에 다 배웠습니다.

혹시, 잘 모르시겠다면 이~전 글들을 참고해주시길 바랍니다.


자... 그리고 다중 파일 어셈블리를 알아보기 이전에 

잠깐 알아보고자하는 용어가 있습니다.


여러분은 혹시 '모듈'이라는 용어를 들어보셨습니까?

모듈은 '무엇인가의 일부'를 말합니다. 

즉, 부속품이라고도 부릅니다.



어떠한 완전체(All)가 있다고 해봅시다.

이 완전체 안에는 A, B, C, D라는 '모듈'들이 있는 것입니다.

이 넷이 합쳐졌을 때 All 즉, 완전체가 되는 것이지요.


컴퓨터 프로그램에서 모듈이란,

'컴파일이 완료된 바이너리'를 의미합니다.

또한, 이 모듈은 '일부'이기 때문에 코드의 일부라고도 할 수 있습니다.


코드의 일부는 일반적으로 라이브러리를 의미합니다.

클래스들이 컴파일되면 클래스 라이브러리가 됩니다.

그렇게 되면 이 클래스 라이브러리도 모듈이라고 부를 수 있게 됩니다.


그러면 라이브러리와 모듈은 같은 것인가요?

모듈이란 '이 라이브러리가 무엇인가의 일부로써 사용되구나!', 

'전체를 이루고 있는 하나이구나!'

라고 하는 의미를 심어주는 역할을 하게 되는 것입니다.


그런데 닷넷의 모듈은 어셈블리에서만 나타나게 됩니다.

어셈블리에서도 다중 파일 어셈블리에서만 나타나게 되지요.

왜냐하면, 단일 파일 어셈블리에서는 사용이 되지 않기 때문입니다.

단일 파일이기 때문이지요.


이전에 배운 비동기, 병렬처리에 대한 용어를 언급하기 위해서는

항상 '두개 이상'이라는 전제가 깔려있어야했듯이,

모듈에도 '일부'라는 의미가 포함되어야합니다.

그런데 단일 파일은 이 '일부'라는 내용이 포함될 수 없지요.


아무튼... 결론적으로 닷넷에서 모듈이라는 용어는

다중 파일 어셈블리에서만 불릴 수 있다는 것입니다.



컴파일 된 바이너리 어셈블리들을 모두 모듈이라고 부릅니다.

이 모듈들이 결합되어 하나의 어셈블리가 되는 것입니다.

이 어셈블리를 바로 '다중 파일 어셈블리'라고 부르는 것입니다.


참고로 리소스는 선택적으로 사용할 수 있습니다. 

있어도 그만, 없어도 그만이기에 모듈이라고 할 수 없습니다.


아무튼..

이 모듈들이 없다면 다중 파일 어셈블리라고 부를 수 없게됩니다.


모듈도 '주모듈'(Primary Moudule)과 '부모듈'(Secondary Module)로 나뉩니다.

매니페스트에는 어셈블리에 관한 정보들을 가지고 있는데,

이 어셈블리의 매니페스트를 가지고 있는 모듈을 

우리는 주된 모듈로써 Main 모듈이라고 부를 수 있습니다.

나머지는 부수적인 모듈로 Sub 모듈이라고 부를 수 있지요.


즉, Main 모듈, Sub 모듈 모두 CIL,형식 메타데이터, 리소스 다 가질 수 있지만,

Sub 모듈에는 매니 페스트가 없다는 사실을 기억하시길 바랍니다.


다중 파일 어셈블리는 왜 사용될까요?

당연히 장점이 있기 때문에 사용하겠지요...


부모듈들을 '갈아 끼운다'는 컴포넌트의 개념에 입각하여

어떤 동작을 수행하는데 있어서 확장과 수정이 용이해진다 이겁니다.

모듈 하나를 다른 어셈블리에서도 사용할 수도 있지요.


즉, 하나로 Packing 해버리게 되면 사용하고자 하는 응용 프로그램에서 

사용할 수 있다 이겁니다.

어떠한 동작을 수행하더라고 하나의 모듈로써 관리하게 되면 

어느 곳이던지 사용할 수 있게 된다 이거죠.


다중 어셈블리라고 해서 모든 모듈이 하나로 묶인다고 이해하면 

약간 뭔가.. 부족하게 이해를 한 꼴이 됩니다.

사실, 매니페스트에 기술되어있는 정보로 인해 논리적으로 묶여있는 것이기 때문입니다.


그런데, 이 부모듈들을 갈아끼우기 위해서는 '참조'가 필요합니다.

어셈블리에는 '참조'라는 용어가 있습니다.

기본적으로 우리가 개발하는 어셈블리는

다른 어셈블리를 참조해서 사용하게 되는 것이지요.


어셈블리 참조라는 의미는 

해당 어셈블리르 가져다 쓰겠다는 의미이고 Load하는 것입니다.

닷넷에서는 load라는 의미를 어셈블리 참조라고 부르는 것입니다.

즉, 참조는 가져다 쓰는 것입니다.


위에서도 언급드렸지만,



BCL 어셈블리가 들어있는 물리적인 닷넷 라이브러리인 mscorlib는 

외부 어셈블리라고 부릅니다.

우리가 닷넷 기반으로 프로그램을 만들게 되면 참조를 하지 않았어도 

기본적으로 참조를 하고 있게 됩니다.


여기서 extern은 '외부 어셈블리 참조'를 의미합니다.

그리고 해당 어셈블리는 공유 어셈블리이지요.

만약, 내가 만든 어셈블리를 사용하고싶다면 외부 어셈블리로 참조하면 됩니다.


단 하나의 형식만을 사용하더라도 참조를 사용해야하기 때문에

extern 키워드가 붙는 것입니다.




지금 보여드린 이 매니페스트의 내용은 내 어셈블리에 대한 정보의 일부입니다.

extren이 붙어있지 않지요.

즉, 해당 어셈블리의 이름이 바로 나옵니다.

해당 예제의 어셈블리명은 'AddApp'이군요.


단지 어셈블리의 이름만 명시해줍니다.

'.assembly 이름' 이렇게 말입니다.


.dll, .exe 같은 것은 없습니다. 

왜냐, dll이던 exe던 중요하지 않기 때문입니다.

단지 어셈블리라는 것이 중요한 것이지요.


어셈블리는 이름까지가 중요하지, 확장자가 중요하지 않습니다.

나중에 probing에 대하여 알아볼 기회가 있을 것인데 그 때 자세하게 알아보도록 하겠습니다.


간략하게 말씀드리자면, probing은 어셈블리를 찾는 과정을 말합니다.

먼저 .dll 어셈블리를 보고 .exe 어셈블리도 보게 됩니다.

만약, 어셈블리가 있다면 읽어들이는데 dll을 우선적으로 봅니다.

아무튼... 어셈블리를 만들어낼 때에 .dll, .exe 확장자 상관없이 가져다 쓰려고 만든 개념입니다.

자세한 것은 추후 알아보도록 하지요!




그런데 공유이냐 전용이냐는 어떻게 구분할 수 있을까요?

공유 어셈블리는 같은 디렉터리에 있어야 동작이 가능합니다.

그리고 공유 업셈블리는 약속되어있는 GAC에 위치해있기 때문에 

같은 디렉터리에 없어도 상관 없습니다.


또한, 공유 어셈블리에는 'publickeytoken'과 같은 정보가 있습니다.

사실 모든 공유 어셈블리는 publickeytoken을 갖습니다.

공유 어셈블리를 구분하는데 사용되는 강력한 이름과도 같은 것입니다.

이 이름에는 비밀키, 공개키등의 기반으로 만들어진 키가 포함됩니다.


이는 보안 때문이 아닌, 어셈블리를 구분하기 위해서

유니크하게 만들고자 포함시키는 것입니다.


해당 정보로는 어셈블리의 이름, 버전, 컬쳐 정보등이 포함됩니다.

그리고 방금 언급한 비밀키, 공개키등의 키 코드가 내부적으로 서명을 거쳐 포함되지요.

이렇게 어셈블리가 결정됩니다.


만약, 이 정보들중 하나라도 다르게 되면 이는 다른 어셈블리입니다.


이번 시간은 여기까지 알아보도록 하겠습니다.


이상 삽잡이였습니다!