1.常见形式
最常见形式是 SDK
调用接口对应头文件及对应库文件,例如,简单封装一个 Add
函数:
- (1) 创建
add.h
和add.cc
两个文件:
/*
* @Author: chenjingyu
* @Date: 2024-12-31 14:33:57
* @Contact: 2458006466@qq.com
* @Description: Add.h
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
int Add(int a, int b);
#ifdef __cplusplus
}
#endif
/*
* @Author: chenjingyu
* @Date: 2024-12-31 14:34:00
* @Contact: 2458006466@qq.com
* @Description: Add.cc
*/
#include "add.h"
int Add(int a, int b) {
return a + b;
}
- (2) 编译成动态库:
libadd.so
>> g++ -shared -fPIC -o libadd.so add.cc
- (3) 交付
SDK
内容为:
sdk
├── include
│ └── add.h
├── lib
│ └── libadd.so
└── test
└── main.cc
- (4) 调用实例:
/*
* @Author: chenjingyu
* @Date: 2024-12-31 14:35:57
* @Contact: 2458006466@qq.com
* @Description: main.cc
*/
#include "add.h"
#include <cstdio>
int main(int argc, char *argv[]) {
printf("1 + 2 = %d.\n", Add(1, 2));
return 0;
}
编译运行:
>> g++ -o main ./test/main.cc -I./include ./lib/libadd.so
>> ./main
1 + 2 = 3.
2.纯库文件形式
这种需要借助 dlopen,dlsym和dlclose
函数来手动加载动态库,并调用内部符号,具体代码如下:
/*
* @Author: chenjingyu
* @Date: 2024-12-31 14:35:57
* @Contact: 2458006466@qq.com
* @Description: test
*/
#include <dlfcn.h>
#include <cstdio>
#include <cstdlib>
typedef int(*ADD)(int, int);
int main(int argc, char *argv[]) {
const char *lib_file = "./lib/libadd.so";
void *handler = dlopen(lib_file, RTLD_LAZY);
if (!handler) {
fprintf(stderr, "[%s] [%d] dlopen get error: %s.\n", __FILE__, __LINE__, dlerror());
exit(EXIT_FAILURE);
}
do {
ADD add = reinterpret_cast<ADD>(dlsym(handler, "Add"));
printf("1 + 2 = %d.\n", add(1, 2));
} while (0);
dlclose(handler);
return 0;
}
编译运行:
>> g++ -o main ./test/main.cc -ldl
>> ./main
1 + 2 = 3.
这种无需要提供头文件,但是需要使用函数指针来将库中取出的函数符号进行映射后,才能进行调用,表面看起来没有提供函数接口对应头文件,实际上需要更麻烦的函数指针来声明对应函数调用形式,感觉有点脱裤子放屁,多此一举的感觉。
3.Windows
平台
上面对应的是 Linux
平台相关 SDK
流程,Windows
平台上其实也大差不差,主要不同之处在于:当交付库为动态库时,相关接口符号需要进行显式导出:
/*
* @Author: chenjingyu
* @Date: 2024-06-15 11:22:39
* @Contact: 2458006466@qq.com
* @Description: Add.h
*/
#pragma once
#ifdef DLL_EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
API int Add(int a, int b);
#if defined(__cplusplus)
}
#endif
/*
* @Author: chenjingyu
* @Date: 2024-06-15 11:22:48
* @Contact: 2458006466@qq.com
* @Description: add.cc
*/
#include "add.h"
int Add(int a, int b) {
return a + b;
}
这里注意一下,头文件声明接口为C接口,后续纯dll载入才能成功,如果提供头文件和库文件这种方式则没有影响。
- (1) 编译动态库:打开
x64 Native Tools Command Prompt for VS 2019
工具,进入当前路径,并运行cl /LD add.cc -DDLL_EXPORTS
:
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.11.42
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
d:\software\Microsoft Visual Studio\2019\Community>G:
G:\>cd /project/C++/DLL/DLL
G:\project\C++\DLL\DLL>cl /LD add.cc -DDLL_EXPORTS
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.29.30157 版
版权所有(C) Microsoft Corporation。保留所有权利。
add.cc
Microsoft (R) Incremental Linker Version 14.29.30157.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:add.dll
/dll
/implib:add.lib
add.obj
正在创建库 add.lib 和对象 add.exp
- (2) 调用实例:
/*
* @Author: chenjingyu
* @Date: 2024-12-31 14:35:57
* @Contact: 2458006466@qq.com
* @Description: main.cc
*/
#include "add.h"
#include <cstdio>
int main(int argc, char *argv[]) {
printf("1 + 2 = %d.\n", Add(1, 2));
return 0;
}
编译链接及运行:
G:\project\C++\DLL\DLL>cl main.cc -o main /link add.lib
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.29.30157 版
版权所有(C) Microsoft Corporation。保留所有权利。
cl: 命令行 warning D9035 :“o”选项已否决,并将在将来的版本中移除
main.cc
Microsoft (R) Incremental Linker Version 14.29.30157.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
/out:main.exe
add.lib
main.obj
G:\project\C++\DLL\DLL>main
1 + 2 = 3.
- (3) 纯
dll
调用:
/*
* @Author: chenjingyu
* @Date: 2024-12-31 14:35:57
* @Contact: 2458006466@qq.com
* @Description: main.cc
*/
#include <Windows.h>
#include <cstdio>
typedef int(*ADD)(int, int);
int main(int argc, char *argv[]) {
LPCWSTR lib_file = L"./add.dll";
HMODULE handler = LoadLibraryW(lib_file);
if (!handler) {
printf("Failed to load library.\n");
return -1;
}
ADD Add = reinterpret_cast<ADD>(GetProcAddress(handler, "Add"));
FreeLibrary(handler);
printf("1 + 2 = %d.\n", Add(1, 2));
return 0;
}
编译运行:
G:\project\C++\DLL\DLL>cl main.cc -o main
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.29.30157 版
版权所有(C) Microsoft Corporation。保留所有权利。
cl: 命令行 warning D9035 :“o”选项已否决,并将在将来的版本中移除
main.cc
Microsoft (R) Incremental Linker Version 14.29.30157.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
/out:main.exe
main.obj
G:\project\C++\DLL\DLL>main.exe
1 + 2 = 3.
4.参考资料
- [1] 使用dlopen加载动态库
- [2] 使用msvc命令行编译静态库和动态库