먼저 라이브러리 기초 개념에 대해 정리해보자
라이브러리 종류
1. 정적 라이브러리 (static library)
.lib, .a 파일
2. 동적 라이브러리 (dynamic-link library)
.dll, .so 파일
동적 라이브러리 사용 방법
1. 묵시적 링킹, 암시적 링킹(Implicit linking)
실행 파일 자체에 어떤 dll의 어떤 함수를 사용하겠다는 정보를 포함시키고, 운영체제가 프로그램 실행 시 해당 함수들을 초기화한 후 그것을 이용하는 방법
- 정적 라이브러의 함수 호출과 유사한 방법
- Include header file 필요, 라이브러리 링킹 필요
- #pragma comment(lib, "library명")
2. 명시적 링킹(Explicit linking)
프로그램이 실행 중일 때 API를 이용하여 DLL파일이 있는지 검사하고 동적으로 원하는 함수만 불러와서 쓰는 방법
- 런타임 때 필요한 라이브러리만 동적으로 호출하여 사용
- Windows 제공 api : LoadLibrary(), GetProcAddress(), FreeLibrary()
- Linux 제공 api : dlopen(),
본격적으로 '동적 라이브러리 명시적 링킹 방법'을 살펴보자
Windows API를 살펴보자
(함수명만 다를뿐 linux도 동일한 원리이다.)
1. LoadLibrary()
// ansi, no L is required
HMODULE LoadLibraryA(
[in] LPCSTR lpLibFileName
);
// unicode, L is needed as a prefix
HMODULE LoadLibraryW(
[in] LPCWSTR lpLibFileName
);
DLL을 로드하고 모듈 핸들을 가져온다.
즉, DLL을 현재 프로세스의 주소공간으로 mapping시켜서 사용할 수 있도록 해준다.
2.GetProcAddress()
FARPROC GetProcAddress(
[in] HMODULE hModule,
[in] LPCSTR lpProcName
);
호출하는 내보낸 각 함수에 대한 함수포인터를 가져온다.
즉, DLL에서 Export한 함수의 번지를 찾아서 그 함수를 사용할 수 있도록 그 함수의 포인터를 리턴해준다.
3. FreeLibrary()
BOOL FreeLibrary(
[in] HMODULE hLibModule
);
DLL 사용 작업이 완료되면 호출한다.
즉, 해당 DLL의 사용 카운트를 1 감소시키고 사용 카운트가 0이 되었을 때 메모리에서 해당 DLL을 삭제해준다. 삭제에 성공하면 TRUE, 실패하면 FALSE를 리턴한다.
예제 코드
동적 라이브러리 MyLib을 만든다.
Client 프로그램에서 런타임 중에 MyLib을 명시적 링킹하여 사용한다.
MyLib코드
// my_lib.h
#pragma once
class MyLib
{
public:
explicit MyLib();
virtual ~MyLib();
public:
int GetTestNumber();
};
// my_lib.cc
#include "my_lib.h"
extern "C" {
__declspec(dllexport) MyLib* create_component() {
return new MyLib();
}
__declspec(dllexport) void destroy_component(MyLib* obj) { delete obj; }
__declspec(dllexport) int get_test_number(MyLib* obj) {
return obj->GetTestNumber();
}
}
MyLib::MyLib() {
}
MyLib::~MyLib() {
}
int MyLib::GetTestNumber() {
return 100;
}
extern "C" 중괄호로 묶여있는 코드를 주목하자
명시적링킹은 이와 같이 함수 주소를 export하고, client 프로그램에서 사용할 때 해당 함수 주소를 import해서 사용한다.
동적라이브러리를 사용할 땐 보통 함수를 호출하여 사용한다.
그러나 구조상 라이브러리 파일에서 클래스 object를 생성할 필요가 있는 경우, 위와 같이 팩토리 함수를 만들어서 객체 포인터를 리턴해준다. (create_component)
Client 프로그램 코드
// main.cc
#include <iostream>
#include <windows.h> //LoadLibrary
typedef void* (*CreateFunc)();
typedef void (*DestroyFunc)(void*);
typedef int (*TestFunc)(void*);
int main(int argc, char *argv[]) {
// 1. load dll
void* handle;
handle = LoadLibrary(L"my_lib.dll");
if (handle == nullptr) {
printf("load library failed. %s", std::to_string(GetLastError()).c_str());
return 0;
}
std::cout << "load succeed "<< std::endl;
// 2. get external function pointer
CreateFunc creation_func = reinterpret_cast<CreateFunc>(GetProcAddress((HMODULE)handle, "create_component"));
TestFunc test_func = reinterpret_cast<TestFunc>(GetProcAddress((HMODULE)handle, "get_test_number"));
DestroyFunc destruction_func = reinterpret_cast<DestroyFunc>(GetProcAddress((HMODULE)handle, "destroy_component"));
void* lib = creation_func();
std::cout << "get_test_number(): "<< test_func(lib) << std::endl;
destruction_func(lib);
// 3. free dll library file
FreeLibrary((HMODULE)handle);
}
1) 동적라이브러리를 로딩하고 LoadLibrary()
2) dll에서 export해놓은 함수 주소를 얻어온다. GetProcAddress().
3) 팩토리함수를 통해 dll파일의 클래스 객체를 생성하여 리턴받는다. void *lib = creation_func()
4) 사용 완료 후에는 생성된 객체를 소멸해준다. destruction_func()
5) 라이브러리 해제해준다. FreeLibrary()
참고 :
Dll 명시적 링킹 - DLL에 명시적으로 연결하는 방법
dll생성, 묵시적 링킹 - 연습: 동적연결라이브러리 만들기 및 사용 (C++)
dll 파일 명시적 링크하기
https://blog.naver.com/sorkelf/40133647878
C++ 클래스를 DLL로 만들고 사용하기