When I read the code in gRPC, I found many APIs using GRPCAPI
as qualifier.
GRPCAPI grpc_channel* grpc_cronet_secure_channel_create(
void* engine, const char* target, const grpc_channel_args* args,
void* reserved);
When I click the link to GRPCAPI
, it's an empty macro.
#ifndef GPRAPI
#define GPRAPI
#endif
#ifndef GRPCAPI
#define GRPCAPI GPRAPI
#endif
I understand some usages of empty macro:
- preventing multiple copies of the same header being included
- used as a switch for debug or removing sensitive code
But here the GRPCAPI
belongs to neither. Is it just a marker to tell us the function is an API? Or more effect for document or others functions?
CodePudding user response:
Its either for platform specific attributes or for future attributes.
For Windows DLLs, you usually specify
__declspec(dllexport)
when compiling the library and
__declspec(dllimport)
when consuming the library.
A macro is the convenient way to both compile and consume it because you only define the value of the macro to be __declspec(dllexport)
/__declspec(dllimport)
within the header.
the same goes for other compiler attributes, such as __attribute__(visibility(default))
/__attribute__(visibility(hidden))
on GCC
Now when the library is statically linked, you don't need all that and you define the macro to have no value.
An example would be:
#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.
Another explanation can be a calling convention modifier. x86 (I only know x86) has different calling conventions - these decide how the caller/callee treats parameters of functions on the assembly level.
Something like this:
#if WIN32
#define APICALL cdecl
#else
#define APICALL
#endif
APICALL void foo() // uses cdecl on WIN32
CodePudding user response:
I really appreciate the answer from @Raildex and comment from @paulsm4, which are very inspiring.
But the exactly function of GRPCAPI
and GPRAPI
is used to mark APIs as a label.
There is a script in grpc named list_api.py using the label GPRAPI and GRPCAPI, which is the only place using these two labels.
_RE_API = r'(?:GPRAPI|GRPCAPI|CENSUSAPI)([^;]*);'
for m in re.finditer(_RE_API, text): # match file content
...
After running the script, we'll get:
...
- 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*
...