Visibility in shared objects

In the GNU Compiler Collection (GCC) environment, the term that is used for exporting is visibility. As it applies to functions and variables in a shared object, visibility refers to the ability of other shared objects to call a C/C++ function. Functions with default visibility have a global scope and can be called from other shared objects. Functions with hidden visibility have a local scope and cannot be called from other shared objects.

Visibility can be controlled by using either compiler options or visibility attributes. The -fvisibility=default compiler option (used in conjunction with the -fvisibility inlines=default compiler option for C++ programs) is used to define all of the functions in a shared object as visible (global scope). These compiler options are available on all z/TPF-supported compilers. Adding the visibility attribute can override a compiler option.

Using the z/TPF MakeTPF tool makes it relatively easy to control the visibility of functions by changing the makefile to specify APP_EXPORT or to use the visibility attribute in the program.

MakeTPF and visibility

The maketpf APP_EXPORT variable controls which functions are local to the shared object and which functions can be called from other shared objects, where APP_EXPORT can be set to: ALL, VISIBILITY, LIST, or ENTRY.
  • ALL is used to make all functions visible by default at compile time, by adding the -fvisibility=default compiler option (used in conjunction with the -fvisibility inlines=default compiler option for C++ programs) to the compile commands. Individual functions can be hidden by using the visibility attribute; add __attribute__ ((visibility("hidden")) to the functions you want to hide.
    Note: Avoid adding __attribute__ ((visibility("hidden")) to C++ code unless it is essential for class member functions to be hidden. For more information about potential problems when you use visibility with C++ classes, see Special considerations for C++ classes.
  • VISIBILITY is used to hide all functions by default at compile time, by adding the -fvisibility=hidden compiler option (used in conjunction with the -fvisibility inlines=hidden compiler option for C++ programs) to the compile commands. Individual functions can be made visible by using the visibility attribute; add __attribute__ ((visibility("default")) to the functions you want to make visible.
    Note: Use this option for shared objects that contain only C language code because runtime problems can occur when you use this option on a shared object that contains C++ code. For more information about potential problems when you use visibility with C++ classes, see Special considerations for C++ classes.
  • LIST is used to indicate that the list of visible functions is provided in an export file. As with ALL, the -fvisibility=default compiler option (used in conjunction with the -fvisibility inlines=default compiler option for C++ programs) is used at compile time to make the functions visible; however, at link time, the export file provides:
    • A list of functions that are to be hidden.
    • A list of functions that are visible.
    Note: You must use the LIST option and export files when hiding functions that are coded in assembly language, because there is no assembly option that is equivalent to the -fvisibility option. For more information, see Export files.
  • ENTRY is used to indicate that only the function specified by APP_ENTRY is made visible. This is also controlled at link time by using the base/exp/app_entry.exp export file. For more information, see Export files.

Examples

  • To make all of the functions for a given program visible except for the ftpc_get_file function, specify APP_EXPORT := ALL in the makefile for the program and code the following in your C/C++ application source code:
    __attribute__ ((visibility("hidden"))) 
    size_t ftpc_get_file (void *ptr, size_t size, size_t nmemb, void *stream)
    { 
      ...
    } 
    Adding the attribute hides the C/C++ function.
  • To hide all of the functions for a given program except for the mq_msg function, specify APP_EXPORT := VISIBILITY in the makefile for the program and code the following in your C/C++ application source code:
    __attribute__ ((visibility("default")))  
    char *mq_msg(size_t buffer_length);  
    Adding the attribute makes the C/C++ function visible.
  • In this example, the makefile for program ABCD makes all functions visible by default. However, the application hides uncallableFunction( ) by declaring it as a static function; the application also hides anotherUncallableFunction( ) by using the visibility("hidden") attribute. An important distinction to make is that the scope of the hidden function in terms of visibility is the shared object, while the scope of the static function is limited to the object.
    abcd.mak:
    APP := ABCD
    APP_EXPORT := ALL
    C_SRC := program.c
    
    
    program.h:
      void callableFunction( );
      void anotherCallableFunction( );
      static void uncallableFunction( );
      __attribute__ ((visibility("hidden")))
      void anotherUncallableFunction( );
    

Special considerations for C++ classes

C++ classes have a number of vague linkage entities; for example, typeinfo and vtable. These entities take on the visibility attribute of the class; therefore, if a class is hidden, the entities are hidden, which might have undesirable side effects. Some side effects include not being able to be inherited from a class in a different shared object and not being able to get thrown by an exception.
For example, a common problem that is introduced when you compile a class with the -fvisibility=hidden option is when the now-hidden class needs to run a constructor from another shared object (such as running a constructor for an inherited class); it appears to compile and link, but you will receive a runtime linkage error.
Note: Unless you know that the C++ logic is contained in the same shared object without the need to use CPP1 or any other C++ library, avoid using APP_EXPORT := VISIBILITY.

In general, it is best not to use the visibility option for C++ object-oriented programs because of the danger of generating runtime errors that are difficult to debug. Instead, take advantage of the inherent characteristics of C++ object-oriented programs, such as encapsulation, namespaces, inheritance, and other characteristics.

If, however, you do use the visibility option for C++ programs, use it with declarations; in most cases, you do not need to specify the visibility option in the definition.

Export files

Also called version scripts, export files in the z/TPF system are meant to be used when you have C/C++ functions that are coded in basic assembly language (BAL) that need to be hidden (not shared globally); the only way to hide them is by using an export file. With an export file, you can hide functions that were visible at assemble (or compile) time. However, at link time, you cannot make visible any functions that were hidden at assemble or compile time.

The executable and linking format (ELF)-compatible compilers support export files for z/TPF applications that require specific symbols to be modified. For more information about export files, see the GNU website.

For more information about using export files with the MakeTPF build solution, see Create an export file and Update export files.