C++动态库打包及调用二三事

MirrorYuChen
MirrorYuChen
发布于 2024-12-31 / 14 阅读
0
0

C++动态库打包及调用二三事

1.常见形式

​ 最常见形式是 SDK调用接口对应头文件及对应库文件,例如,简单封装一个 Add函数:

  • (1) 创建 add.hadd.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.参考资料


评论