Symbol visibility¶
#include <libcork/core.h>
When writing a shared library, you should always be careful to explicitly mark which functions and other symbols are part of the library’s public API, and which should only be used internally by the library. There are a number of benefits to doing this; there is a good summary on the GCC wiki. (Note that even though that summary is on the GCC wiki, the notes apply equally well to other compilers and platforms.)
libcork provides several helper macros that make it easier to do this. We use these macros ourselves to define libcork’s public API.
Defining a library’s public API¶
On some platforms (for instance, on Windows), you must declare each public function and symbol differently depending on whether you’re compiling the library that defines the symbol, or a library or program that uses the symbol. The first is called an export, the second an import. On other platforms (for instance, GCC on Linux), the declaration of a public symbol is the same regardless of whether you’re exporting or importing the symbol. libcork provides macros that let you explicitly declare a symbol as an export or an import in a platform-independent way.
-
CORK_EXPORT
¶ -
CORK_IMPORT
¶ Explicitly declare that a symbol should be exported from the current shared library, or imported from some other shared library.
However, you will rarely need to use these macros directly. Instead, when
writing a new shared library, you should declare a new preprocessor macro
(specific to the new library), which you’ll use when declaring the library’s
public API. For instance, if you’re creating a new library called
libfoo, you would declare a new preprocessor macro called FOO_API
:
#if !defined(FOO_API)
#define FOO_API CORK_IMPORT
#endif
This ensures that anyone who wants to use libfoo doesn’t need to do anything
special; the FOO_API
macro will default to importing the symbols from
libfoo’s public API.
When building libfoo, you must set up your build system to define this
variable differently; since you need to export the symbols in this case, the
FOO_API
macro should be set to CORK_EXPORT
. Each build system will have
a different way to do this. In CMake, for instance, you’d add the following:
set_target_properties(libfoo PROPERTIES
COMPILE_DEFINITIONS FOO_API=CORK_EXPORT
)
Then, in all of your header files, you should use your new FOO_API
macro
when declaring each function or symbol in the public API:
FOO_API int
foo_load_from_file(const char *name);
FOO_API void
foo_do_something_great(int flags);
extern FOO_API const char *foo_name;
Local symbols¶
Normally, if you need a function to be local, and not be exported as part of the
library’s public API, you can just declare it static
:
static int
file_local_function(void)
{
/* This function is not visible outside of this file. */
return 0;
}
This works great as long as the function is only needed within the current
source file. Sometimes, though, you need to define a function that can be used
in other source files within the same library, but which shouldn’t be visible
outside of the library. To do this, you should define the function using the
CORK_LOCAL
macro.
-
CORK_LOCAL
¶ Declare a symbol that should be visible in any source file within the current library, but not visible outside of the library.
As an example:
CORK_LOCAL int
library_local_function(void)
{
/* This function is visible in other files, but not outside of the
* library. */
return 0;
}
Since you’re going to use this function in multiple files, you’ll want to declare the function in a header file. However, since the function is not part of the public API, this should not be defined in a public header file (that is, one that’s installed along with the shared library). Instead, you should include a private header file that’s only available in your library’s source code archive, and which should not be installed with the other public header files.