서론

image

개발하다 보면 라이브러리를 사용할 일이 많다. 라이브러리를 사용해보면 정확한 개념은 몰라도 프로그램을 개발할 때 필요한 기능을 가져다 쓰는 도구라는 것은 어렴풋이 이해할 수 있다.

사실 이 정도만 이해해도 사용하는 데 전혀 문제가 없겠지만, 라이브러리 확장자 종류(*.dll, *.lib, *.so, *.a)가 왜 다양한지 프로그램을 컴파일, 실행하는 과정에서 라이브러리가 없어서 왜 오류가 나는지와 같은 궁금증을 해소하기 위해 좀 더 자세히 알아볼 필요가 있다.

라이브러리에 대해 제대로 이해하려면 컴파일 과정, 특히 링킹 과정에 대한 이해가 필요하다.


라이브러리(Library) 정의

라이브러리는 프로그래밍에 사용할 수 있게 미리 만들어져 있는 함수나 변수들의 묶음이다. 미리 컴파일된 오프젝트 파일 형태로 존재하며 컴파일 과정(링킹 과정)에서 링킹되어 실행 가능한 프로그램을 이룬다.

라이브러리 장점

라이브러리가 가지는 장점은 다음과 같다.

  1. 코드를 재사용하기 쉽다.
  2. 코드의 내용을 숨겨 기술 유출을 방지할 수 있다.
  3. 이미 구현되어 있는 기능들을 가져다 쓸 수 있어 개발 시간을 단축할 수 있다.
  4. 컴파일 시간을 단축할 수 있다. (라이브러리는 미리 컴파일되어 있어 링킹만 하면 바로 사용 가능하다)


라이브러리를 사용하는데 헤더 파일(.h)이 필요한 이유

라이브러리를 사용하기 위해서는 #include 지시문을 통해 라이브러리 헤더 파일을 삽입하는 과정이 필요하다.

헤더 파일이 필요한 이유는 링커가 최종 실행 파일을 생성하기 위해 모든 함수의 심볼을 필요로 하는데 헤더 파일이 심볼을 생성하는 역할을 하기 때문이다.

즉, 라이브러리를 사용해 실행 파일을 만들기 위해서는 헤더 파일이 꼭 필요하다.


라이브러리 종류

라이브러리는 정적 링킹 방식과 동적 링킹 방식에 따라 정적 라이브러리동적 라이브러리(=공유 라이브러리)로 나눌 수 있다.

결국, 각 라이브러리의 정의 및 장단점은 각 링킹 방식의 정의 및 장단점과 같다고 보면 된다.

image

정적 라이브러리는 정적 링킹(Static Linking) 과정에서 링커가 프로그램에 필요로 하는 부분을 라이브러리에서 찾아 실행 파일에 복사하는 방식의 라이브러리를 의미한다.

정적 라이브러리 확장자는 윈도우 환경에서는 *.lib, 리눅스 환경에서는 *.a 이다,

*.lib라고 무조건 정적 라이브러리는 아니다. (아래 암시적 링킹 참고)

정적 라이브러리 장점

실행 파일이 정적 라이브러리를 복사해서 가지고 있으므로 실행할 때 라이브러리가 필요 없다. 즉, 실행 파일만 있으면 프로그램이 동작하는 만큼 이식성이 좋고 안정적이다.

정적 라이브러리 단점

하지만 정적 라이브러리는 몇 가지 단점이 존재한다.

  1. 실행 파일이 라이브러리 내용을 복사해서 가지고 있으므로 라이브러리에서 수정할 부분이 있으면 파일 전체를 다시 컴파일하여 재배포해야 한다.
  2. 실행 파일이 라이브러리를 가지고 있는 만큼 실행 파일 크기가 커진다.
  3. 같은 라이브러리를 가진 여러 프로그램이 동시에 실행될 경우 코드가 중복되어 메모리 자원을 낭비한다.
  4. 정적 라이브러리 전체를 링킹하면서 사용하지 않는 함수들까지 전부 다 프로그램에 포함한다.

이러한 단점을 해결하기 위해 동적 라이브러리가 존재한다.


image

동적 라이브러리는 동적 링킹(Dynamic Linking) 과정에서 링커가 라이브러리 내용을 복사하지 않고 해당 내용의 주소만 가지고 있다가 런타임에 실행 파일과 라이브러리가 메모리에 위치할 때 해당 주소로 가서 필요한 내용을 가져오는 방식의 라이브러리를 의미한다.

동적 라이브러리 확장자는 윈도우 환경에서는 *.dll, 리눅스 환경에서는 *.so 이다.

동적 라이브러리 장점

정적 라이브러리를 사용하는 것보다 실행 파일 크기가 작아지고 여러 프로그램이 동적 라이브러리를 메모리에 올려놓고 공유해서 사용하기 때문에 메모리 자원을 효율적으로 사용할 수 있다.

또한, 라이브러리에서 수정할 부분이 있으면 실행 파일을 새로 컴파일할 필요 없이 동적 라이브러리만 다시 컴파일하여 재배포할 수 있다.

동적 라이브러리 단점

동적 라이브러리라고 장점만 있는 것은 아니다.

동적 라이브러리를 사용하는 실행 파일은 실행할 때 동적 라이브러리가 필요하다. 만약 동적 라이브러리가 제대로 링크되어 있지 않거나 버전이 맞지 않는 등의 문제가 있으면 실행이 안 될 수 있다. 즉, 외부 의존도가 생기며 이식성이 낮은 단점이 있다.

또한, 동적 라이브러리를 사용할 경우 매번 프로그램 영역에서 라이브러리가 저장된 주소로 이동하는 과정이 필요하여 약간의 성능 감소가 있을 수 있다.


DLL의 분류

놀랍게도 동적 라이브러리에서 한번 더 종류를 나눌 수 있다.

윈도우에서 동적 라이브러리를 *.dll 파일이라 부르는데 실행 파일에서 *.dll 함수를 호출하는 방법에 따라 암시적 링킹명시적 링킹으로 나눌 수 있다.

암시적 링킹(Implicit Linking)

암시적 링킹은 실행 파일 자체에 어떤 *.dll의 어떤 함수를 호출하겠다는 정보를 포함 시키고 프로그램 실행 시 해당 함수들을 초기화한 후 이용하는 방식이다.

프로그램을 시작하면서 해당 *.dll을 로드하며 *.dll에 정의된 함수를 마치 자신의 함수처럼 호출할 수 있다.

실행 파일에 어떤 함수를 사용하겠다는 정보를 포함하기 위해서는 *.lib 파일이 필요하다. 이때, *.lib 파일은 정적 라이브러리가 아니라 암시적 링킹을 위해 필요한 심볼이 들어있는 *.lib 파일동적 링킹 과정에 꼭 필요하다.

코드가 간결하여 사용하기 쉽다는 장점이 있다.

프로그램이 실행될 때 *dll 파일이 로드되므로 실행 시 연결이라고 표현한다.

명시적 링킹(Explicit Linking)

명시적 링킹은 프로그램이 실행 중일 때 *.dll 파일이 있는지 검사하고 동적으로 원하는 함수만 호출하는 방법이다. 정확하게는 호출할 함수의 포인터를 얻어 함수를 호출하는 방법이라 할 수 있다.

링킹 과정에서 *.dll의 함수 정보가 필요하지 않기 때문에 *.lib 파일이 필요 없다.

직접 코드를 통해 원하는 함수만 불러와서 사용하는 방법으로 사용하지 않는 함수들까지 전부 다 프로그램에 포함할 필요가 없어 자원을 아낄 수 있다.

프로그램이 실행 중에 *.dll 파일이 메모리에 읽히므로 실행 중 연결이라고 표현한다.


결론

위 내용을 이해했다면 이제 라이브러리 확장자가 어떤 의미를 가지고 있는지 알 수 있다.

*.dll : 윈도우 환경의 동적 라이브러리
*.lib : 윈도우 환경의 정적 라이브러리
*.so : 리눅스 환경의 동적 라이브러리
*.a : 리눅스 환경의 정적 라이브러리

또한, *.lib라고 무조건 정적 라이브러리가 아니라 동적 라이브러리의 암시적 링킹에 필요한 심볼이 들어있는 라이브러리일 수도 있는 것을 명심하자.


카테고리:

업데이트: