본문 바로가기
SWE/C++ OOP

[C++] 동적 라이브러리에서 클래스 객체 생성하는 방법 | 런타임 링킹 | 팩토리함수 | 예제 코드

by S나라라2 2023. 11. 2.
반응형

 

먼저 라이브러리 기초 개념에 대해 정리해보자

 

라이브러리 종류

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 명시적으로 연결하는 방법

https://learn.microsoft.com/ko-kr/cpp/build/linking-an-executable-to-a-dll?view=msvc-170#linking-explicitly

 

dll생성, 묵시적 링킹 -  연습: 동적연결라이브러리 만들기 사용 (C++)

https://learn.microsoft.com/ko-kr/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170

 

dll 파일 명시적 링크하기

https://blog.naver.com/sorkelf/40133647878

 

C++ 클래스를 DLL 만들고 사용하기

https://luckygg.tistory.com/281

반응형