I'm reading the Dear ImGui API, and i'm wondering what does it mean to add a pre-processor variable (here IMGUI_API) before the function declaration like this :
#ifndef IMGUI_API
#define IMGUI_API
#endif
...
namespace ImGui
{
...
IMGUI_API float GetWindowWidth();
...
};
Thanks in advance !
Like Hans Passant said - it won't always be empty.
One of the main properties of dynamic shared objects (and DLLs in Windows) is that the internal symbols of the library are not exposed to the user. In GCC, this is done by specifying the default symbol visibility to "hidden" on the command line when building the library. However, this has the undesirable effect of making all symbols, including the ones you want users to call, hidden, which makes your library effectively useless.
GCC provides a way to manually control visibility - __attribute__((visibility("default")))
. This marks a function as having default visibility, meaning it will be exposed by the DSO. This attribute is specified before the function declaration.
This creates a new problem - the users of your library don't need/want this attribute specified on your library functions when they include your header file. When your header is included by the user, these definitions should be removed, leaving just a bare function declaration.
There's two ways to solve this - have two copies of your header, or use the preprocessor to change the code before compilation. Most (almost all) library programmers choose the latter, as keeping two copies of the same file synced is very difficult.
The way the writers of ImGui have implemented the latter option is rather elegant - rather than defining their API marker inline, like so:
#ifdef IMGUI_API_BUILD
#define IMGUI_API __attribute__((visibility("default")))
#else
#define IMGUI_API
#endif
They've defined it as follows:
#ifndef IMGUI_API
#define IMGUI_API
#endif
This has the effect of defining the symbol to a default value if it hasn't been overridden.
The genius of this is actually in the compilation process - by specifying the definition of IMGUI_API
on the command line, they can change the behavior of the code without exposing elements of their build process to the world.
All they have to do is add -D IMGUI_API=__attribute((visibility("default")))
to the compiler command line and the header file magically marks every API function as being exported from the shared object.
In fact, they can change the definition to any value they want without exposing that detail in the header file used by other programmers in this way. Debug information, additional function options, specifying hot/cold path info... all of this can be specified on the command line without needing to place that information into the header file.
Edit:
Looking through their code now, it seems they haven't realized this, and have created a very powerful shared-library solution for Linux without meaning to. Despite that, all of the above is still valid - other libraries can do the same thing.