在 gRPC 函数声明之前空宏 `GRPCAPI` 有什么影响?
What's the effect of empty macro `GRPCAPI` before gRPC function declaration?
当我阅读 gRPC 中的代码时,我发现许多 API 使用 GRPCAPI
作为限定符。
GRPCAPI grpc_channel* grpc_cronet_secure_channel_create(
void* engine, const char* target, const grpc_channel_args* args,
void* reserved);
当我点击 link 到 GRPCAPI
时,它是一个空宏。
#ifndef GPRAPI
#define GPRAPI
#endif
#ifndef GRPCAPI
#define GRPCAPI GPRAPI
#endif
了解空宏的一些用法:
- 防止包含相同 header 的多个副本
- 用作调试或删除敏感代码的开关
但是这里的GRPCAPI
两者都不属于。它只是一个标记来告诉我们函数是一个 API 吗?或者对文档或其他功能有更多影响?
它用于平台特定属性或未来属性。
对于 Windows 个 DLL,您通常指定
__declspec(dllexport)
当编译库和
__declspec(dllimport)
当 消耗库时 。
宏是编译和使用宏的便捷方式,因为您只需在 header.[=32 中将宏的值定义为 __declspec(dllexport)
/__declspec(dllimport)
=]
其他编译器属性也是如此,例如 GCC
上的 __attribute__(visibility(default))
/__attribute__(visibility(hidden))
现在,当静态链接库时,您不需要所有这些,您将宏定义为没有价值。
一个例子是:
#ifdef STATIC_LIBRARY
#define LIBRARY_API
#else
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
LIBRARY_API void foo(); // when statically linked, it's a simple void function. If dynamically linked, it's either dllexport when compiling the library or dllimport when consuming it.
另一种解释可能是调用约定修饰符。
x86(我只知道 x86)有不同的调用约定 - 这些决定了 caller/callee 如何在汇编级别处理函数的参数。
像这样:
#if WIN32
#define APICALL cdecl
#else
#define APICALL
#endif
APICALL void foo() // uses cdecl on WIN32
非常感谢@Raildex 的回答和@paulsm4 的评论,非常鼓舞人心。
但是GRPCAPI
和GPRAPI
的功能完全一样,都是用来标记API的标签。
grpc中有一个名为list_api.py的脚本使用了标签GPRAPI和GRPCAPI,这是唯一使用这两个标签的地方。
_RE_API = r'(?:GPRAPI|GRPCAPI|CENSUSAPI)([^;]*);'
for m in re.finditer(_RE_API, text): # match file content
...
在 运行 脚本之后,我们将得到:
...
- arguments: void* engine, const char* target, const grpc_channel_args* args, void*
reserved
header: include/grpc/grpc_cronet.h
name: grpc_cronet_secure_channel_create
return_type: grpc_channel*
...
当我阅读 gRPC 中的代码时,我发现许多 API 使用 GRPCAPI
作为限定符。
GRPCAPI grpc_channel* grpc_cronet_secure_channel_create(
void* engine, const char* target, const grpc_channel_args* args,
void* reserved);
当我点击 link 到 GRPCAPI
时,它是一个空宏。
#ifndef GPRAPI
#define GPRAPI
#endif
#ifndef GRPCAPI
#define GRPCAPI GPRAPI
#endif
了解空宏的一些用法:
- 防止包含相同 header 的多个副本
- 用作调试或删除敏感代码的开关
但是这里的GRPCAPI
两者都不属于。它只是一个标记来告诉我们函数是一个 API 吗?或者对文档或其他功能有更多影响?
它用于平台特定属性或未来属性。
对于 Windows 个 DLL,您通常指定
__declspec(dllexport)
当编译库和
__declspec(dllimport)
当 消耗库时 。
宏是编译和使用宏的便捷方式,因为您只需在 header.[=32 中将宏的值定义为 __declspec(dllexport)
/__declspec(dllimport)
=]
其他编译器属性也是如此,例如 GCC
__attribute__(visibility(default))
/__attribute__(visibility(hidden))
现在,当静态链接库时,您不需要所有这些,您将宏定义为没有价值。
一个例子是:
#ifdef STATIC_LIBRARY
#define LIBRARY_API
#else
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
LIBRARY_API void foo(); // when statically linked, it's a simple void function. If dynamically linked, it's either dllexport when compiling the library or dllimport when consuming it.
另一种解释可能是调用约定修饰符。 x86(我只知道 x86)有不同的调用约定 - 这些决定了 caller/callee 如何在汇编级别处理函数的参数。
像这样:
#if WIN32
#define APICALL cdecl
#else
#define APICALL
#endif
APICALL void foo() // uses cdecl on WIN32
非常感谢@Raildex 的回答和@paulsm4 的评论,非常鼓舞人心。
但是GRPCAPI
和GPRAPI
的功能完全一样,都是用来标记API的标签。
grpc中有一个名为list_api.py的脚本使用了标签GPRAPI和GRPCAPI,这是唯一使用这两个标签的地方。
_RE_API = r'(?:GPRAPI|GRPCAPI|CENSUSAPI)([^;]*);'
for m in re.finditer(_RE_API, text): # match file content
...
在 运行 脚本之后,我们将得到:
...
- arguments: void* engine, const char* target, const grpc_channel_args* args, void*
reserved
header: include/grpc/grpc_cronet.h
name: grpc_cronet_secure_channel_create
return_type: grpc_channel*
...