msvc的__declspec(dllexport)

一、__declspec(dllexport)的含义

_declspec(dllexport) 是 Microsoft 特定的一个编译器扩展,用于指示编译器将符号导出到动态链接库(DLL)中。它并不是一个标准 C++ 关键字或语法,而是 __declspec 关键字的一个特定用法。__declspec 是 "declare specifier" 的缩写,表示声明说明符。dllexport 则是 "DLL export" 的缩写,表示将符号导出到 DLL 中。

因此,__declspec(dllexport) 的含义可以分解为:

  • __declspec:声明说明符,用于指定某些属性或行为。
  • dllexport:DLL 输出,表示将符号导出到 DLL 中。

使用场景

  1. 创建 DLL: 当您创建一个 DLL 并希望某些函数或变量可以被外部模块调用时,您可以使用 __declspec(dllexport) 来导出这些符号。

  2. 声明导出的符号: 使用 __declspec(dllexport) 声明的函数或变量将在编译时生成相应的导出信息,使得这些符号可以被其他模块识别和使用。

二、__declspec(dllexport)具体指示构建工具链中哪些程序的哪些行为

 

__declspec(dllexport)`的作用主要体现在编译和链接阶段,具体指示构建工具链中编译器和链接器的行为。

编译器行为(如 cl.exe)

1. 符号导出:
- 当编译器遇到使用 __declspec(dllexport)声明的符号(例如函数或变量)时,它会将这些符号标记为导出符号。这意味着这些符号将在生成的对象文件中被标记为需要导出。
- 编译器会在对象文件的符号表中添加相应的导出信息,使得这些符号在链接阶段可以被识别为导出符号。

链接器行为(如 link.exe)

1. 创建导出表:
- 链接器在生成 DLL 时,会根据对象文件中的导出符号信息创建导出表。导出表包含所有被标记为导出的符号,使得这些符号可以被其他模块识别和使用。
- 导出表是 DLL 文件的一部分,包含符号的名称、地址等信息。

2. 生成导出库文件:
- 链接器还会生成一个导出库文件(`.lib` 文件),该文件包含导出符号的引用信息。这个库文件用于在编译和链接使用该 DLL 的应用程序时提供符号解析。
- 应用程序在链接阶段使用这个导出库文件来解析对 DLL 中导出符号的引用。

### 示例

假设我们有以下代码:

cpp

// MyLibrary.h
#ifndef MYLIBRARY_H
#define MYLIBRARY_H

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

MYLIBRARY_API void MyFunction();

#endif // MYLIBRARY_H

cpp

// MyLibrary.cpp
#include "MyLibrary.h"

void MyFunction() {
// Function implementation
}

 

构建过程:

1. 编译阶段:
- 使用 cl.exe 编译 MyLibrary.cpp:
sh

cl /c /DMYLIBRARY_EXPORTS MyLibrary.cpp

 

- 编译器将 MyFunction 标记为导出符号,并在生成的对象文件 MyLibrary.obj 中包含相应的导出信息。

2. 链接阶段:
- 使用 link.exe 将对象文件链接为 DLL:
sh

link /DLL /OUT:MyLibrary.dll MyLibrary.obj


- 链接器根据对象文件中的导出符号信息创建导出表,并将其包含在生成的 `MyLibrary.dll` 中。
- 链接器还生成一个导出库文件 `MyLibrary.lib`,用于在其他模块中链接和使用该 DLL。

总结

__declspec(dllexport)` 主要影响编译器和链接器的行为:

编译器:标记符号为导出符号,并在对象文件中包含相应的导出信息。
链接器:创建导出表并生成导出库文件,使得这些符号可以被其他模块识别和使用。

 

三、g++类似的行为

 

在 Linux 下使用 g++ 构建共享库(Shared Library)时,虽然没有直接等价于 __declspec(dllexport)的关键字,但可以通过其他方法实现类似的导出符号功能。主要有以下几种方式:

1. 使用 __attribute__((visibility("default")))

GCC 提供了 __attribute__机制,可以用来控制符号的可见性。__attribute__((visibility("default")))类似于 __declspec(dllexport),用于将符号导出到共享库中。

示例:

cpp

// MyLibrary.h
#ifndef MYLIBRARY_H
#define MYLIBRARY_H

#if defined(__GNUC__) && __GNUC__ >= 4
#define MYLIBRARY_API __attribute__((visibility("default")))
#else
#define MYLIBRARY_API
#endif

MYLIBRARY_API void MyFunction();

#endif // MYLIBRARY_H

 

 

cpp

// MyLibrary.cpp
#include "MyLibrary.h"

void MyFunction() {
// Function implementation
}

 

构建共享库:

sh

g++ -fPIC -shared -o libMyLibrary.so MyLibrary.cpp

 



2. 使用版本脚本(Version Script)

版本脚本是一种更为灵活的方法,可以精确控制哪些符号被导出。通过在链接阶段指定版本脚本,可以明确指定哪些符号应该被导出。

示例:

创建版本脚本 `MyLibrary.map`:

{
global:
MyFunction;
local:

};

 

构建共享库:

sh

g++ -fPIC -shared -o libMyLibrary.so MyLibrary.cpp -Wl,--version-script=MyLibrary.map

 

3. 默认导出所有符号

在构建共享库时,可以通过编译器选项导出所有符号。不过,这种方法不推荐用于大型项目,因为它会导出所有符号,可能导致命名冲突。

 构建共享库:

sh

g++ -fPIC -shared -o libMyLibrary.so MyLibrary.cpp

 

总结

在 Linux 下使用 g++构建共享库时,可以通过以下几种方法实现导出符号的功能:

1. __attribute__((visibility("default"))):类似于 __declspec(dllexport),用于导出特定符号。
2. 版本脚本:通过版本脚本精确控制导出符号。
3. 默认导出所有符号:不推荐,但可以通过编译器选项导出所有符号。

这些方法可以根据具体需求选择使用,以便在 Linux 下实现与 __declspec(dllexport)`类似的功能。

posted @ 2024-09-30 15:49  卖雨伞的小男孩  阅读(49)  评论(0编辑  收藏  举报