diff --git a/ChangeLog b/ChangeLog index a2c80f585..2b3bb3a0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2020-07-05 David Turner + + [build] Improve visibility support of library function names. + + * include/freetype/config/public-macros.h + (FT_PUBLIC_FUNCTION_ATTRIBUTE): New macro to tag functions as + public (and thus exportable). + (FT_EXPORT): Use it. + + * include/freetype/config/compiler-macros.h + (FT_INTERNAL_FUNCTION_ATTRIBUTE): New macro to tag functions as + internal to the library (and thus hidden). Note that on ELF + systems, all internal functions have hidden visibility, which avoids + the need to enforce this when invoking the compiler (e.g., with an + option like `-fvisibility=hidden'). + + (FT_FUNCTION_DECLARATION, FT_FUNCTION_DEFINITION): New base macros + to deal with C and C++ linkage issues at the same time. + + (FT_LOCAL, FT_LOCAL_DEF, FT_LOCAL_ARRAY, FT_LOCAL_ARRAY_DEF, + FT_BASE, FT_BASE_DEF, FT_EXPORT_VAR, FT_BASE_CALLBACK, + FT_BASE_CALLBACK_DEF): Redefined using new macros. + 2020-07-05 David Turner [build] Split off more stuff from `ftconfig.h'. diff --git a/include/freetype/config/public-macros.h b/include/freetype/config/public-macros.h index b62092ba6..b1fa0f2b3 100644 --- a/include/freetype/config/public-macros.h +++ b/include/freetype/config/public-macros.h @@ -49,38 +49,41 @@ FT_BEGIN_HEADER -/* Define a public FreeType API function. This ensures it is properly exported - * or imported at build time. +/* Mark a function declaration as public. This ensures it will be properly + * exported to client code. Place this before a function declaration. + * + * NOTE: This macro should be considered an internal implementation detail, and + * not part of the FreeType API. It is only defined here because it is needed + * by FT_EXPORT() */ -#ifndef FT_EXPORT - -#ifdef FT2_BUILD_LIBRARY - -#if defined( _WIN32 ) && defined( DLL_EXPORT ) -#define FT_EXPORT( x ) __declspec( dllexport ) x -#elif defined( __GNUC__ ) && __GNUC__ >= 4 -#define FT_EXPORT( x ) __attribute__(( visibility( "default" ) )) x -#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 -#define FT_EXPORT( x ) __global x -#elif defined( __cplusplus ) -#define FT_EXPORT( x ) extern "C" x -#else -#define FT_EXPORT( x ) extern x +#if defined(_WIN32) +# if defined(FT2_BUILD_LIBRARY) && defined( DLL_EXPORT ) +# define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllexport ) +# elif defined( DLL_IMPORT ) +# define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllimport ) +# endif +#elif (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__) +# define FT_PUBLIC_FUNCTION_ATTRIBUTE __attribute__((visibility("default"))) +#elif defined(__SUNPRO_C) && __SUNPRO_C >= 0x550 +# define FT_PUBLIC_FUNCTION_ATTRIBUTE __global #endif -#else /* !FT2_BUILD_LIBRARY */ - -#if defined( _WIN32 ) && defined( DLL_IMPORT ) -#define FT_EXPORT( x ) __declspec( dllimport ) x -#elif defined( __cplusplus ) -#define FT_EXPORT( x ) extern "C" x -#else -#define FT_EXPORT( x ) extern x +#ifndef FT_PUBLIC_FUNCTION_ATTRIBUTE +# define FT_PUBLIC_FUNCTION_ATTRIBUTE /* nothing */ #endif -#endif /* !FT2_BUILD_LIBRARY */ - -#endif /* !FT_EXPORT */ +/* Define a public FreeType API function. This ensures it is properly exported + * or imported at build time. The macro parameter is the function's return type + * as in: + * + * FT_EXPORT( FT_Bool ) FT_Object_Method( FT_Object obj, ... ); + * + */ +#ifdef __cplusplus +#define FT_EXPORT( x ) FT_PUBLIC_FUNCTION_ATTRIBUTE extern "C" x +#else +#define FT_EXPORT( x ) FT_PUBLIC_FUNCTION_ATTRIBUTE extern x +#endif FT_END_HEADER diff --git a/include/freetype/internal/compiler-macros.h b/include/freetype/internal/compiler-macros.h index d7b6cfa24..1f432bca5 100644 --- a/include/freetype/internal/compiler-macros.h +++ b/include/freetype/internal/compiler-macros.h @@ -22,42 +22,70 @@ FT_BEGIN_HEADER + /* Fix compiler warning with sgi compiler. */ +#if defined( __sgi ) && !defined( __GNUC__ ) +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif +#endif + /* `FT_UNUSED` indicates that a given parameter is not used -- */ /* this is only used to get rid of unpleasant compiler warnings. */ #ifndef FT_UNUSED #define FT_UNUSED( arg ) ( (arg) = (arg) ) #endif - /* Fix compiler warning with sgi compiler. */ #if defined( __sgi ) && !defined( __GNUC__ ) -#if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) -#pragma set woff 3505 -#endif +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif #endif +/* When defining a macro that expands to a non-trivial C statement, use + * FT_BEGIN_STMNT and FT_END_STMNT to enclose the macro's body. This ensures + * there are no surprises when the macro is invoked in conditional branches. + * + * E.g.: + * #define LOG(...) \ + * FT_BEGIN_STMNT \ + * if (logging_enabled) \ + * log(__VA_ARGS__); \ + * FT_END_STMNT + */ +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) + +/* FT_DUMMY_STMNT expands to an empty C statement. Useful for conditionally + * define statement macros, as in: + * + * #ifdef BUILD_CONFIG_LOGGING + * # define LOG(...) \ + * FT_BEGIN_STMNT \ + * if (logging_enabled) \ + * log(__VA_ARGS__); \ + * FT_END_STMNT + * #else + * # define LOG(...) FT_DUMMY_STMNT + * #endif + */ +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT + #ifdef _WIN64 - /* only 64bit Windows uses the LLP64 data model, i.e., */ - /* 32bit integers, 64bit pointers */ + /* only 64bit Windows uses the LLP64 data model, i.e., */ + /* 32-bit integers, 64-bit pointers. */ #define FT_UINT_TO_POINTER( x ) (void*)(unsigned __int64)(x) #else #define FT_UINT_TO_POINTER( x ) (void*)(unsigned long)(x) #endif - - /************************************************************************** - * - * miscellaneous - * - */ - - -#define FT_BEGIN_STMNT do { -#define FT_END_STMNT } while ( 0 ) -#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT - - - /* `typeof` condition taken from gnulib's `intprops.h` header file */ +/* Use FT_TYPEOF(type) to cast a value to |type|. This is useful to suppress + * signedness compilation warnings in macros as in: + * + * #define PAD_(x, n) ( (x) & ~FT_TYPEOF( x )( (n) - 1 ) ) + * + * `typeof` condition taken from gnulib's `intprops.h` header file + */ #if ( ( defined( __GNUC__ ) && __GNUC__ >= 2 ) || \ ( defined( __IBMC__ ) && __IBMC__ >= 1210 && \ defined( __IBM__TYPEOF__ ) ) || \ @@ -67,64 +95,98 @@ FT_BEGIN_HEADER #define FT_TYPEOF( type ) /* empty */ #endif +/* Mark a function declaration as internal to the library. This ensures that + * it will not be exposed by default to client code, and helps generate smaller + * and faster code on ELF-based platforms. Place this before a function + * declaration. + */ +#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__) +#define FT_INTERNAL_FUNCTION_ATTRIBUTE __attribute__((visibility("hidden"))) +#else +#define FT_INTERNAL_FUNCTION_ATTRIBUTE /* nothing */ +#endif - /* Use `FT_LOCAL` and `FT_LOCAL_DEF` to declare and define, */ - /* respectively, a function that gets used only within the scope of a */ - /* module. Normally, both the header and source code files for such a */ - /* function are within a single module directory. */ - /* */ - /* Intra-module arrays should be tagged with `FT_LOCAL_ARRAY` and */ - /* `FT_LOCAL_ARRAY_DEF`. */ - /* */ +/* FreeType supports compiling its C sources to be compiled as C++ instead, + * this introduces a number of subtle issues. + * + * The main one is that a C++ function declaration and its definition must have + * the same 'linkage'. Because all FreeType headers declare their function with + * C linkage (i.e. within an extern "C" { .. } block, due to the magic of + * FT_BEGIN_HEADER and FT_END_HEADER), then their definition in FreeType + * sources should also be prefixed with 'extern "C"' when compiled in C++ mode. + * + * The FT_FUNCTION_DECLARATION() and FT_FUNCTION_DEFINITION() macros are + * provided to deal with this case, as well as FT_CALLBACK_DEF et al below. + */ + +/* FT_FUNCTION_DECLARATION(type) can be used to write a C function declaration, + * and ensure it will have C linkage when the library is built with a C++ + * compiler. The parameter is the function's return type, so a declaration + * would look like: + * + * FT_FUNCTION_DECLARATION(int) foo(int x); + * + * NOTE: Technically, all FreeType headers put their function declarations + * inside an extern "C" block, giving them C linkage. This means that using + * this macro is only necessary within internal source files, but using it in + * a header will be harmless. + * + * NOTE: Do not use directly, use FT_LOCAL()/FT_BASE()/FT_EXPORT() instead. + */ +#ifdef __cplusplus +#define FT_FUNCTION_DECLARATION( x ) extern "C" x +#else +#define FT_FUNCTION_DECLARATION( x ) extern x +#endif + +/* Same as FT_FUNCTION_DECLARATION(), but for function definitions instead. + * NOTE: Do not use directly, use FT_LOCAL_DEF()/FT_BASE_DEF()/FT_EXPORT_DEF() + * instead. + */ +#ifdef __cplusplus +#define FT_FUNCTION_DEFINITION( x ) extern "C" x +#else +#define FT_FUNCTION_DEFINITION( x ) x +#endif + +/* Use FT_LOCAL()/FT_LOCAL_DEF() to declare and define an internal FreeType + * function that is only used by the sources of a single src/module/ directory. + * This ensures the functions are turned into static ones at build time, + * resulting in smaller and faster code. + */ #ifdef FT_MAKE_OPTION_SINGLE_OBJECT -#define FT_LOCAL( x ) static x -#define FT_LOCAL_DEF( x ) static x +# define FT_LOCAL( x ) static x +# define FT_LOCAL_DEF( x ) static x #else -#ifdef __cplusplus -#define FT_LOCAL( x ) extern "C" x -#define FT_LOCAL_DEF( x ) extern "C" x -#else -#define FT_LOCAL( x ) extern x -#define FT_LOCAL_DEF( x ) x +#define FT_LOCAL( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE FT_FUNCTION_DECLARATION( x ) +#define FT_LOCAL_DEF( x ) FT_FUNCTION_DEFINITION( x ) + +#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ + +/* Use FT_LOCAL_ARRAY()/FT_LOCAL_ARRAY_DEF() to declare and define a constant + * array that must be accessed from several sources in the same src/module/ + * sub-directory, but are otherwise internal to the library. + */ +#define FT_LOCAL_ARRAY( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE extern const x +#define FT_LOCAL_ARRAY_DEF( x ) const x + +/* Use FT_BASE()/FT_BASE_DEF() to declare or define an internal library + * function that are used by more than one single module. + */ +#define FT_BASE( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_DEF( x ) FT_FUNCTION_DEFINITION( x ) + + +/* NOTE: Conditionally define FT_EXPORT_VAR() due to its definition in + * src/smooth/ftgrays.h to make the header more portable. + */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) FT_FUNCTION_DECLARATION( x ) #endif -#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ - -#define FT_LOCAL_ARRAY( x ) extern const x -#define FT_LOCAL_ARRAY_DEF( x ) const x - - - /* Use `FT_BASE` and `FT_BASE_DEF` to declare and define, respectively, */ - /* functions that are used in more than a single module. In the */ - /* current setup this implies that the declaration is in a header file */ - /* in the `include/freetype/internal` directory, and the function body */ - /* is in a file in `src/base`. */ - /* */ -#ifndef FT_BASE - -#ifdef __cplusplus -#define FT_BASE( x ) extern "C" x -#else -#define FT_BASE( x ) extern x -#endif - -#endif /* !FT_BASE */ - - -#ifndef FT_BASE_DEF - -#ifdef __cplusplus -#define FT_BASE_DEF( x ) x -#else -#define FT_BASE_DEF( x ) x -#endif - -#endif /* !FT_BASE_DEF */ - - /* When compiling FreeType as a DLL or DSO with hidden visibility */ /* some systems/compilers need a special attribute in front OR after */ /* the return type of function declarations. */ @@ -160,29 +222,8 @@ FT_BEGIN_HEADER /* To export a variable, use `FT_EXPORT_VAR`. */ /* */ -/* NOTE: See for FT_EXPORT() definition */ - -#ifndef FT_EXPORT_DEF - -#ifdef __cplusplus -#define FT_EXPORT_DEF( x ) extern "C" x -#else -#define FT_EXPORT_DEF( x ) extern x -#endif - -#endif /* !FT_EXPORT_DEF */ - - -#ifndef FT_EXPORT_VAR - -#ifdef __cplusplus -#define FT_EXPORT_VAR( x ) extern "C" x -#else -#define FT_EXPORT_VAR( x ) extern x -#endif - -#endif /* !FT_EXPORT_VAR */ - +/* See for the FT_EXPORT() definition */ +#define FT_EXPORT_DEF( x ) FT_FUNCTION_DEFINITION( x ) /* The following macros are needed to compile the library with a */ /* C++ compiler and with 16bit compilers. */ @@ -213,23 +254,14 @@ FT_BEGIN_HEADER /* Some 16bit compilers have to redefine these macros to insert */ /* the infamous `_cdecl` or `__fastcall` declarations. */ /* */ -#ifndef FT_CALLBACK_DEF #ifdef __cplusplus #define FT_CALLBACK_DEF( x ) extern "C" x #else #define FT_CALLBACK_DEF( x ) static x #endif -#endif /* FT_CALLBACK_DEF */ -#ifndef FT_BASE_CALLBACK -#ifdef __cplusplus -#define FT_BASE_CALLBACK( x ) extern "C" x -#define FT_BASE_CALLBACK_DEF( x ) extern "C" x -#else -#define FT_BASE_CALLBACK( x ) extern x -#define FT_BASE_CALLBACK_DEF( x ) x -#endif -#endif /* FT_BASE_CALLBACK */ +#define FT_BASE_CALLBACK( x ) FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_CALLBACK_DEF( x ) FT_FUNCTION_DEFINITION( x ) #ifndef FT_CALLBACK_TABLE #ifdef __cplusplus