기사 디렉토리
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 클래스만 내보냅니다.