Windows 및 Linux 동적 라이브러리 생성 및 사용


c 및 C++에서 동적 링크 라이브러리를 사용하는 주요 의미는 다음과 같습니다.

시스템 리소스 절약
응용 프로그램이 많은 수의 라이브러리 기능을 연결해야 하는 경우 정적 연결 라이브러리를 사용하면 응용 프로그램 크기가 커지고 각 응용 프로그램에는 완전한 코드 라이브러리가 필요하므로 시스템 리소스가 낭비됩니다. 반대로 동적 링크 라이브러리는 여러 응용 프로그램에서 공유할 수 있으므로 반복적으로 코드를 로드하는 상황을 피하고 시스템 리소스 낭비를 줄일 수 있습니다.

코드 유지 관리 단순화
동적 링크 라이브러리를 사용하면 라이브러리 기능과 응용 프로그램 코드를 분리할 수 있으므로 코드 유지 관리 및 업그레이드에 유리합니다. 라이브러리 기능을 업데이트해야 하는 경우 동적 연결 라이브러리만 교체하면 되며 응용 프로그램을 다시 컴파일하여 배포할 필요가 없습니다. 이것은 또한 응용 프로그램 개발 및 유지 관리를 보다 유연하고 효율적으로 만듭니다.

애플리케이션의 보안 향상
동적 링크 라이브러리를 사용하면 악의적인 공격자의 허점을 악용하여 애플리케이션에 악성 코드가 주입되는 것을 방지할 수 있습니다. 동적 링크 라이브러리는 독립적인 바이너리 파일이기 때문에 공격자가 콘텐츠를 직접 수정할 수 없으므로 애플리케이션의 보안이 보장됩니다.

요컨대 동적 링크 라이브러리를 사용하면 시스템 성능과 보안을 개선하고 코드 유지 관리를 간소화하며 애플리케이션 개발 및 배포를 보다 유연하고 효율적으로 만들 수 있습니다.

Windows 동적 라이브러리 생성 및 사용

동적 라이브러리 생성

다음은 CMake를 사용하여 동적 라이브러리를 빌드하고 Windows 시스템에서 호출하는 자세한 단계입니다.

CMake 설치: 공식 CMake 웹사이트에서 CMake를 다운로드하고 설치 마법사의 지시에 따라 설치합니다.

프로젝트 디렉터리 만들기: 로컬 디스크에 프로젝트 디렉터리를 만들고 이 디렉터리 아래에 소스 코드 파일을 저장하는 데 사용할 "src"라는 폴더를 만듭니다.

소스 코드 작성: "src" 폴더에 "library.cpp"라는 파일을 만들고 다음 코드를 작성합니다.

#include <iostream>
#include "library.h"

void Library::HelloWorld() {
    
    
    std::cout << "Hello, World!" << std::endl;
}

같은 폴더에 "library.h"라는 파일을 만들고 다음 코드를 작성합니다.

class Library {
    
    
public:
    void HelloWorld();
};

CMakeLists.txt 파일 만들기: 프로젝트 디렉터리에 "CMakeLists.txt"라는 파일을 만들고 다음 코드를 작성합니다.

cmake_minimum_required(VERSION 3.0)

project(MyLibrary)

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

add_library(MyLibrary SHARED library.cpp)

target_include_directories(MyLibrary PUBLIC ${
    
    CMAKE_CURRENT_SOURCE_DIR})

install(TARGETS MyLibrary DESTINATION lib)
install(FILES library.h DESTINATION include)

이 파일은 CMake에게 소스 코드 파일을 동적 라이브러리로 컴파일하고 지정된 디렉토리에 설치하도록 지시합니다. 여기서 "CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS" 옵션은 모든 기호를 내보낼 수 있도록 하는 데 사용됩니다.
"CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS"는 Windows의 동적 라이브러리에서 모든 기호를 공용 기호로 내보내는 CMake 옵션입니다. 이 옵션이 "켜짐"이면 CMake는 인라인이 아닌, 템플릿이 아닌, 인라인이 아닌 모든 명령(__inline, __forceinline, __inline__ 등) 기호를 내보낼 수 있는 것으로 표시하고 생성된 동적 라이브러리에 포함합니다. 이는 일반적으로 모든 기호가 런타임에 동적으로 로드될 수 있도록 동적 라이브러리로 내보내졌는지 확인하는 데 사용됩니다. 그러나 이 옵션을 사용하면 일부 불필요한 기호가 내보내져 동적 라이브러리의 크기가 커질 수 있습니다. 따라서 이 옵션은 필요할 때만 신중하게 사용하는 것이 좋습니다.

이 옵션의 역할은 모든 심볼을 Windows 플랫폼의 동적 라이브러리로 내보내는 것입니다. 그러면 런타임 시 동적 라이브러리의 모든 심볼을 다른 프로그램에서 사용할 수 있습니다. Windows 플랫폼에서 동적 라이브러리의 기본 동작은 명시적으로 내보낸 기호만 동적 라이브러리로 내보내는 것이므로 기호를 명시적으로 내보내지 않으면 다른 프로그램에서 이 기호를 사용할 수 없습니다. 이 옵션을 사용하면 다른 프로그램이 동적 라이브러리의 모든 기능을 사용할 수 있도록 모든 기호를 동적 라이브러리로 편리하게 내보낼 수 있습니다. 이것은 동적 링크 라이브러리를 개발하는 프로그래머에게 매우 유용합니다. 특히 플러그인 작성이나 다른 개발자가 사용할 라이브러리 개발과 같이 다른 프로그램에서 동적 링크 라이브러리를 널리 사용해야 하는 경우에 유용합니다.

"CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS" 옵션을 사용하지 않으면 내보내기 기호 목록(__declspec(dllexport) 사용)을 통해 명시적으로 내보낸 기호만 생성된 동적 라이브러리에 포함되고 다른 기호는 내보내지 않으므로 다른 프로그램에서 사용할 수 없습니다. 이로 인해 다른 프로그램에서 내보내지 않은 기호를 사용할 수 없어 동적 라이브러리의 모든 기능에 액세스할 수 없기 때문에 동적 라이브러리의 기능이 제한될 수 있습니다. 따라서 Windows 플랫폼에서 다른 프로그램이 동적 라이브러리의 모든 기호를 사용하도록 하려면 "CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS" 옵션을 사용하여 모든 기호를 내보내는 것이 좋습니다.

동적 라이브러리 빌드: 명령 프롬프트(또는 PowerShell)를 열고 프로젝트 디렉터리로 이동합니다. 다음 명령을 입력합니다.

mkdir build
cd build
cmake ..
cmake --build .

그러면 "build"라는 폴더가 생성되고 그 안에 동적 라이브러리 파일이 생성됩니다.

동적 라이브러리 호출

호출 코드 작성: "src" 폴더에 "main.cpp"라는 파일을 만들고 다음 코드를 작성합니다.

#include "library.h"

int main() {
    
    
    Library myLibrary;
    myLibrary.HelloWorld();
    return 0;
}

CMakeLists.txt 파일 만들기: "src" 폴더에 "CMakeLists.txt"라는 파일을 만들고 다음 코드를 작성합니다.

cmake_minimum_required(VERSION 3.0)

project(MyApp)

add_executable(MyApp main.cpp)

target_link_libraries(MyApp PRIVATE MyLibrary)

target_include_directories(MyApp PUBLIC ${
    
    CMAKE_CURRENT_SOURCE_DIR})

install(TARGETS MyApp DESTINATION bin)


이 파일은 CMake에게 실행 파일을 생성하고 동적 라이브러리에 연결하도록 지시합니다.

실행 파일 빌드: 명령 프롬프트(또는 PowerShell)로 돌아가서 다음 명령을 입력합니다.

cd ..
mkdir build-app
cd build-app
cmake ..
cmake --build .

이렇게 하면 "build-app"이라는 폴더가 생성되고 그 안에 실행 파일이 빌드됩니다.

애플리케이션 실행: 명령 프롬프트(또는 PowerShell)에서 실행 파일이 있는 디렉터리로 이동하고 다음 명령을 입력합니다.

MyApp.exe

__declspec(dllexport) 사용

__declspec(dllexport)를 사용하여 기호를 내보내는 간단한 경우로, 각각 두 개의 정수를 더하고 빼는 데 사용되는 두 개의 함수 더하기 및 빼기를 포함하는 "mylibrary"라는 동적 링크 라이브러리를 작성한다고 가정합니다. 다음은 헤더 파일 "mylibrary.h"와 소스 파일 "mylibrary.cpp"의 내용입니다.

// mylibrary.h
#ifndef MYLIBRARY_H
#define MYLIBRARY_H

#ifdef _WIN32
    #ifdef MYLIBRARY_EXPORTS
        #define MYLIBRARY_API __declspec(dllexport)
    #else
        #define MYLIBRARY_API __declspec(dllimport)
    #endif
#else
    #define MYLIBRARY_API
#endif

MYLIBRARY_API int add(int a, int b);
MYLIBRARY_API int subtract(int a, int b);

#endif  // MYLIBRARY_H

// mylibrary.cpp
#include "mylibrary.h"

MYLIBRARY_API int add(int a, int b)
{
    
    
    return a + b;
}

MYLIBRARY_API int subtract(int a, int b)
{
    
    
    return a - b;
}

이 예제에서는 MYLIBRARY_API 매크로를 정의하여 동적 라이브러리가 현재 컴파일되고 있는지 여부에 따라 내보내기 또는 가져오기 키워드를 설정합니다. Windows 플랫폼에서는 __declspec(dllexport) 키워드를 사용하여 더하기 및 빼기 함수를 내보낸 함수로 표시하여 동적 라이브러리의 다른 프로그램에서 사용할 수 있도록 합니다. 동적 라이브러리를 컴파일할 때 MYLIBRARY_API가 __declspec(dllexport)로 설정되도록 MYLIBRARY_EXPORTS 매크로를 정의해야 하며, 동적 라이브러리를 사용하는 다른 프로그램에서는 MYLIBRARY_API를 __declspec(dllimport)로 설정해야 합니다.

이 동적 라이브러리를 사용하려면 CMakeLists.txt에 다음을 추가해야 합니다.

# CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(mylibrary)

# Set C++ standard to C++11
set(CMAKE_CXX_STANDARD 11)

# Add source files
set(SOURCES mylibrary.cpp)

# Create shared library
add_library(mylibrary SHARED ${
    
    SOURCES})

# Define preprocessor macro for exporting symbols on Windows
if(WIN32)
    target_compile_definitions(mylibrary PRIVATE MYLIBRARY_EXPORTS)
endif()

이 CMakeLists.txt에서 먼저 프로젝트 이름을 지정하고 C++11 표준을 설정합니다. 그런 다음 소스 파일 "mylibrary.cpp"를 소스 파일로 지정하고 add_library 명령을 사용하여 "mylibrary"라는 동적 링크 라이브러리를 만듭니다. 마지막으로 MYLIBRARY_API 매크로를 올바르게 설정하기 위해 target_compile_definitions 명령을 사용하여 Windows 플랫폼에서 MYLIBRARY_EXPORTS 매크로를 정의합니다.

이제 이 라이브러리의 함수를 사용할 수 있습니다. 예를 들면 다음과 같습니다.

#include <iostream>
#include "mylibrary.h"

int main()
{
    
    
    int x = add(3, 4);
    int y = subtract(7, 5);
    std::cout << "3 + 4 = " << x << std::endl;
    std::cout << "7 - 5 = " << y << std::endl;
    return 0;
}

LINUX 동적 라이브러리 생성 및 사용

태그 표시

Linux 플랫폼에서 동적 링크 라이브러리의 기호 내보내기 및 가져오기 메커니즘은 Windows와 다릅니다. Linux는 기호 가져오기 및 내보내기를 제어하기 위해 "기호 버전 관리"라는 또 다른 메커니즘을 사용합니다.

Linux 플랫폼에서 -fvisibility=hidden 컴파일러 옵션을 사용하여 기호를 숨길 수 있으며 __attribute__((visibility("default")))를 명시적으로 사용하여 기호를 내보내는 경우에만 외부 링커에서 볼 수 있습니다. 예를 들어 동적 연결 라이브러리에 함수를 작성할 때 다음을 사용하여 내보낸 심볼로 표시할 수 있습니다.

__attribute__((visibility("default"))) int my_function(int arg1, int arg2) {
    
    
    // function body here
}

이는 링커에게 my_function이 동적 링크 라이브러리에서 액세스할 수 있는 함수임을 알려줍니다.

클래스 내보내기 기호

내보낸 C++ 클래스는 유사한 방식으로 내보낸 기호로 표시할 수 있습니다. 예를 들어:

class __attribute__((visibility("default"))) MyExportedClass {
    
    
public:
    MyExportedClass();
    ~MyExportedClass();
    // class member functions here
};

Linux의 기호 버전 제어 메커니즘은 기호 버전 정의, 바인딩 및 기본 버전과 같은 여러 측면을 포함하여 Windows보다 더 복잡합니다. 따라서 동적 링크 라이브러리를 작성할 때 기호 내보내기 및 가져오기가 올바르게 수행될 수 있도록 관련 문서 및 사양을 주의 깊게 연구하고 이해해야 합니다.

예제 숨기기 및 표시

코드의 보안 및 유지 관리성을 향상시키기 위해 동적 링크 라이브러리를 작성할 때 -fvisibility=hidden을 사용하여 기호를 숨기고, 표시 기호로 내보내야 하는 기호만 명시적으로 표시하는 것이 좋습니다. 이는 불필요한 기호 내보내기를 방지하고 보안 허점의 위험을 줄이며 링커 성능을 향상시킵니다. 따라서 Linux 플랫폼에서는 __attribute__((visibility("hidden")))를 사용하여 C++ 클래스를 숨겨진 기호로 표시할 수도 있습니다. 예를 들어:

class __attribute__((visibility("hidden"))) MyHiddenClass {
    
    
public:
    MyHiddenClass();
    ~MyHiddenClass();
    // class member functions here
};

class __attribute__((visibility("default"))) MyExportedClass {
    
    
public:
    MyExportedClass();
    ~MyExportedClass();
    // class member functions here
};

이렇게 하면 MyHiddenClass 클래스는 숨겨진 상태로 두고 MyExportedClass 클래스만 내보냅니다.

추천

출처blog.csdn.net/m0_49302377/article/details/130313375