Library

DV·2023년 12월 12일

C/C++

목록 보기
1/1
post-thumbnail

Concept of Library

Library란?
c언어에서 library는 모듈화를 지원하는 개념이다.

  • 목적: 특정한 기능을, 반복적인 코드 작성을 하지 않고 필요한 곳에서 재사용하기 위함
  • 형태: 프로그램이 연결할 수 있는 패키징된 object 파일들의 모음
  • 컴파일된 형태인 object code로 존재하므로(미리 컴파일 되어있으므로) 컴파일 시간 단축됨


    기본적으로 C Programming은 소스 파일을 컴파일하고 그 결과물을 실행한다.
    코드가 많아지면 소스파일을 여러 파일로 나누어 격리하고, 목적에 맞는 코드들을 모아 Library를 만든다.
    Library는 각각 컴파일되며 링크 단계에서 execute file에 라이브러리(object code)가 연결된다.

특징
header와 구현부가 분리된다.

  • 배포하기 쉬움
  • 구현부를 binary code로(.lib 등) 감출 수 있음

예시
게임엔진에서 sound를 처리하기 위해 FMOD를 사용함

  • sound 기능을 이미 잘 구현된 library 활용해 처리
  • library만 참고해도 내부 함수 사용 가능

Types of Library

Library Type
object code가 Linking되는 방법에 따라 나뉜다.

  • Static Library
  • Dynamic Linking Library (DLL)

    기능이 추가되면 library의 코드도 많아지고, 각 역할에 맞는 library도 많아져 실행 바이너리의 크기는 점점 증가한다.
    한 번만 실행하면 괜찮을 수 있겠지만, 여러번 실행되면 많은 메모리 영역을 차지하고, 그러면 더 많은 메모리가 필요하다.

    따라서 메모리 관리 측면에서, 단일 실행에 적합한 Static Library와 다중 실행에 적합한 Dynamic (Linking) Library 로 library 형태를 구분지을 수 있다.

Library Type과 메모리 영역

  • Static Library: Text Segment (execute file에 포함됨)
  • Dynamic Linking Library: Memory Mapping Segment (library process 공유)

Static Library

concept
compile time에 library가 link된다.

  • object code(*.lib)가 실행 바이너리에 포함됨
  • 각 프로세스는 자체 코드 및 데이터 복사본을 얻음

장점

  • runtime 추가 loading 비용 없음: library code는 compile time에 연결되므로 최종 execute file은 runtime 시 library에 종속되지 않음
  • 빠른 속도: 동적 쿼리 등 추가작업 없이 독립적으로(실행 바이너리만으로) library functions 사용 가능
  • 실행 안정성: 한번 execute file을 생성하면, 추후 static library가 제거되더라도 이미 생성된 실행파일을 실행하는 데는 문제 없음

단점

  • 바이너리 파일 크기 & 메모리 공간: binary file의 크기가 커지므로 더 많은 공간 필요
  • update: library를 update할 경우 메인 프로그램을 다시 컴파일해야 함

사용

#include <*.h>
#pragma comment(lib, "*.lib")

Dynamic Linking Library (DLL)

Concept
runtime에 library가 link된다

  • object code(*.lib)가 실행 바이너리에 포함되지 않음
  • 라이브러리 프로세스(DLL)는 별도로 존재하며, 각 (실행파일)프로세스는 이를 공유해 사용
  • 특정 시점에 연결하거나, 연결을 끊을 수도 있음

Output File

*.Lib: DLL의 "Implict Linking" 위한 링크 정보

  • DLL이 제공하고자 하는 함수 정보(함수명)을 가지는 object file
  • 프로그램 실행될 때 어떤 DLL을 쓰겠다는 정보 저장

*.DLL: 구현부(binary부)

  • lib의 모든 코드 구현
  • DLL은 OS에서 두 개 이상 실행되지 않음
  • execute file 위치에 함께 존재해야 함

장점

  • 바이너리 파일 크기 & 메모리 공간: 더 작게 사용
  • update: library를 update하더라도, 이전 버전과 바이너리가 호환되면 다시 컴파일하지 않아도 됨

단점

  • 실행 시간: 매번 library 주소에 접근해야 하므로 static library보다 느림
  • 호환성 문제: library가 이미 메모리에 올라가 있지만 변경된 경우, 두 버전의 바이너리가 호환되지 않으면 호환성 문제가 생길 수도 있음(다시 링크해야 함)

Types of Linking (DLL)

  • Implicit Linking 암시적 링킹
  • Explicit Linking 명시적 링킹

Implicit Linking
execute file 자체에 어떤 DLL의 어떤 함수를 사용하겠다는 정보를 포함시킨 링크 방식.

  • DLL의 *.lib 파일 사용
  • 링크 단계: 실행 바이너리의 *.obj 파일들과 DLL의 *.lib 파일을 함께 링크
  • 실행 단계: OS가 프로그램 실행 시(runtime) DLL의 함수 코드를 참조

Explicit linking
프로그램이 실행 중일 때 API를 이용하여 DLL 파일이 있는지 검사하고 동적으로 원하는 함수만 불러와서 사용하는 링크 방식.

  • *.lib 파일 필요 없음
  • 실행 단계: DLL이 필요한 시점에서 로딩하고, 불필요해지면 반환

특징

  • 메모리 절약
  • 프로그램 실행 중 DLL 교체 및 선택 가능
  • 필요한 순간에 하나씩 DLL을 로딩할 수 있으므로 DLL 로딩에 걸리는 시간 분산 가능

예시: Unreal Engine

  • 사용자 코드를 DLL로 만듦
  • 코드가 Update되는 경우 이전 버전과 메모리 연결 끊고 다시 빌드, 연결

예시: 언어 설정 등의 분기 경우

  • DLL을 사용해서 코드 분기하는 케이스
  • 같은 함수를 찾아 호출하지만, ~한 경우에는 A, ~한 경우에는 B

Usage

<library header>

  • export & import
#define DLL_EXPORT extern "C" __declspec(dllexport)
#define DLL_IMPORT extern "C" __declspec(dllimport)
  • 하나의 헤더로 묶어 처리
#ifdef DYNAMICLIB_EXPORTS
#define MY_DLL extern "C" __declspec(dllexport)
#else
#define MY_DLL extern "C" __declspec(dllimport)
#endif
  • library 내에서 사용할 함수, 외부로 공개할 함수 구분 가능
    - export 선언이 있어야 외부로 나감
    - import 선언이 있어야 참조함

<Source.cpp>

# include <*.h>
  • Implict Linking
# pragma comment(lib, *.Lib)
  • Explict Linking
// Load DLL
HMODULE hDllHandle = LoadLibrary(L"LibName.dll");
if (!hDllHandle)
	return 0;

// Call DLL Function
// - Funtion Pointer
typedef int(*FUNC_TYPE)(int);
FUNC_TYPE pFunc = nullptr;
pFunc = (FUNC_TYPE)GetProcAddress(hDllHandle, "FuncName");
if (pFunc)
	int data = pFunc(87);
  • LoadLibrary : 필요한 DLL을 프로세스 가상 메모리에 맵핑
  • GetProcAddress : DLL 함수의 포인터 획득
  • FreeLibrary : 프로세스 가상 메모리에서 DLL 반환

0개의 댓글