C++ dll動態程式庫建置架構筆記(CMake build) -1 dll程式寫法
這篇介紹如何建置一個基本的 C++ 動態程式庫。
我的系統環境:
- Win10
- CMake 3.18.4
- VisualStudio 2019
一、程式寫法差異
1.一般的寫法
my_math.h
int Add(int a, int b); class math_class { public: int Add(int a, int b); };
my_math.cpp
int Add(int a, int b) { return a+b; } int math_class::Add(int a, int b) { return a+b; }
2.dll的寫法
在需要提供給外部使用的 function 或是 class 加上 __declspec(dllexport)
,告訴編譯器這是能提供給外部使用的 API 介面。
my_math.h
extern "C" __declspec(dllexport) int Add(int a, int b); class __declspec(dllexport) math_class { public: int Add(int a, int b); };
my_math.cpp
int Add(int a, int b) { return a+b; } int math_class::Add(int a, int b) { return a+b; }
extern "C" 探討
我看其他人講解應該是能讓程式在 C 與 C++ 之間混用,如果都是 C++
環境是不是就可以不用寫,這部分我不是很清楚,求大神解惑了。
我覺得應該是將 C++ 轉為 C 語言的格式,能讓 C++ dll 程式在 C 語言上執行,因為曾經在 function 參數的部分使用 std::string 資料型態,結果使用這個 dll 的人說他無法讀到 std::string 裡面的資料,須注意可能只能使用 C 語言有的資料型態。
二、實作
檔案架構
根目錄
├─common
│ └─SVdef.h
├─Dll_1Layer
│ ├─math
│ │ ├─include
│ │ │ └─my_math.h
│ │ └─src
│ │ └─my_math.cpp
│ └─CMakeFiles.txt
└─CMakeFiles.txt
以下的定義檔是判斷在哪個系統環境,是否用 extern "C" 及
__declspec(dllexport),我的環境已知會開啟 __cplusplus
、_MSC_VER、EXPORT_API,所以 SV_EXTERN_C = extern "C",SV_EXPORTS =
__declspec(dllexport)。
判斷式裡有個判斷 defined
EXPORT_API,但你可能會發現 EXPORT_API 這個未定義,或找不到他定義在哪了,那是因為這是判斷要不要編譯成 dll 的條件,所以這個定義寫在 CMakeLists.txt 裡。
SVdef.h
#ifndef SV_DEF_h_ #define SV_DEF_h_ #ifndef SV_EXTERN_C # ifdef __cplusplus && defined EXPORT_API # define SV_EXTERN_C extern "C" # else # define SV_EXTERN_C # endif #endif #ifndef SV_EXPORTS # if (defined _WIN32 || defined WINCE || defined __CYGWIN__ || defined _MSC_VER) && defined EXPORT_API # define SV_EXPORTS __declspec(dllexport) # elif defined __GNUC__ && __GNUC__ >= 4 && defined EXPORT_API # define SV_EXPORTS __attribute__ ((visibility ("default"))) # endif #endif #ifndef SV_EXPORTS # define SV_EXPORTS #endif #endif //SV_DEF_h_
my_math.h
#ifndef math_H_ #define math_H_ #include "SVdef.h" SV_EXTERN_C SV_EXPORTS int Add(int a, int b); SV_EXTERN_C SV_EXPORTS int Subtraction(int a, int b); SV_EXTERN_C SV_EXPORTS int Multiply(int a, int b); SV_EXTERN_C SV_EXPORTS int Divided(int a, int b); SV_EXTERN_C SV_EXPORTS int Squared(int a, int b); class SV_EXPORTS math_class
{ public: int Add(int a, int b); int Subtraction(int a, int b); int Multiply(int a, int b); }; #endif //math_H_
SV_EXTERN_C 會被取代為 extern "C"
SV_EXPORTS 會被取代為 __declspec(dllexport)
my_math.cpp
int Add(int a, int b) { return a+b; } int math_class::Add(int a, int b) { return a+b; } int math_class::Subtraction(int a, int b) { return a-b; } int math_class::Multiply(int a, int b) { return a*b; }
三、使用CMake編譯
1.CMake 語法簡單介紹:
# 設定變數 set (變數名稱 變數值) # 加入include header INCLUDE_DIRECTORIES(資料夾路徑) # 編譯成"動態程式庫"或"靜態程式庫" # 動態程式庫參數是SHARED,靜態程式庫參數是STATIC ADD_LIBRARY(專案名稱 動/靜態參數 需要的cpp檔案) # c++ define target_compile_definitions(專案名稱 屬性 define的名稱)
2.實作
Dll_1Layer/CMakeLists.txt
set (THE_MODULE "Dll_1Layer_math") # include header INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/common) INCLUDE_DIRECTORIES(./include) # output Dll_1Layer_math.lib Dll_1Layer_math.dll ADD_LIBRARY(${THE_MODULE} SHARED src/my_math.cpp) target_compile_definitions(${THE_MODULE} PRIVATE EXPORT_API) # c++ define EXPORT_API
EXPORT_API 的定義寫 target_compile_definitions(${THE_MODULE} PRIVATE
EXPORT_API)裡。
編譯完會輸出兩個之後需要使用的檔案:
- Dll_1Layer_math.dll
- Dll_1Layer_math.lib
留言
張貼留言