Controlling Exported Functions in Linux Shared Libraries

Click the blue text above to follow directly! Convenient for next reading. If this helps you, please give it a thumbs up or a like, thank you~ Article First Published Official Account – Pou Guangming

On the third day of diligently working on a business trip in Shanghai……

The previous article introduced the rules for handling functions with the same name in shared libraries in Linux – determining which function to call based on the order of the linked libraries.

This time, we will introduce some other interesting properties of shared libraries.

During our development process, we inevitably use third-party libraries, and sometimes we need to update them, and in certain cases, we need to maintain compatibility with different versions.

Based on the results verified last time, if there are functions with the same name in two different versions of a library, and we need compatibility, how do we determine which function to call? Clearly, handling this by the order of linked libraries is not a good approach. 【Although in most cases the function names of libraries are different】

Another scenario is when we obtain a third-party library and header files, and we want to see what other function interfaces are available in the library. We can use nm -D *.so to check. Below, we will illustrate using libone.so as an example, with the red line part being functions I defined myself.

Controlling Exported Functions in Linux Shared Libraries

To decouple functions, we will break down functionality into multiple functions, but in reality, only a few may be exposed to users. If we want users to see only the encapsulated functions when using the nm -D *.so command, we can use CFLAGS += -fvisibility=hidden in the makefile, and then prepend the function names exposed to users with __attribute__((visibility("default"))).

When using CFLAGS += -fvisibility=hidden in the makefile, all functions will be hidden. If this flag is not used, all functions are public by default.

GCC version 4 and above can be used 【not tested】.

Test case source code:

1. Create shareLib

libOne.h

#ifndef __LIBONE_API_H__#define __LIBONE_API_H__
#define OPEN_API_DEFAULT __attribute__((visibility("default")))
#define OPEN_API_HIDDEN __attribute__((visibility("hidden")))
// #define OPEN_API_LIBONETEST
#ifdef __cplusplus
extern "C" {
#endif
    /**Name: Test case*
    * Description:*
    * Parameters: None*
    * Return Value: 0 ———— Success; Others ———— Error number.*
    * Explanation:*/
    OPEN_API_DEFAULT int myPrintfDefault();
    OPEN_API_HIDDEN int myPrintfHidden();
#ifdef __cplusplus
}
#endif
#endif

libOne.c

#include "libOne.h"
#include <stdio.h>
#define OPEN_API_LIBONETEST_DEFAULT __attribute__((visibility("default")))
#define OPEN_API_LIBONETEST_HIDDEN __attribute__((visibility("hidden")))
// #define OPEN_API_LIBONETEST_SRC
OPEN_API_LIBONETEST_DEFAULT int myPrintfDefault() {
    printf("Hi, I am lib One default! \n");
    return 0;
}
OPEN_API_LIBONETEST_HIDDEN int myPrintfHidden() {
    printf("Hi, I am lib One hidden! \n");
    return 0;
}

Makefile :

##################################################################                     PRIVATE PART                              ##################################################################
APP_STACK_DIR = .
# Internal header files
INC_CFLAGS += -I $(APP_STACK_DIR)/Inc
# External interface directory
#INC_CFLAGS += -I $(APP_STACK_DIR)/Intf
# Dynamic link library
LDFLAGS += -lName  -lName
# Source files
CSRC += $(APP_STACK_DIR)/Src/*.c
C_OBJS += $(patsubst %.c,%.o,$(wildcard $(CSRC)))
# Dynamic library compilation flags
DEBUG = y
ifeq ($(DEBUG),y)
DEBUG_CFLAGS += -DDEBUG
DEBUG_CFLAGS += -g
endif
CFLAGS += -c
CFLAGS += -Os
CFLAGS += -Wall
CFLAGS += -fPIC
CFLAGS += -fvisibility=hidden  # Hidden attribute
CFLAGS += $(DEBUG_CFLAGS) # Target files
#Target_Lib=$(APP_STACK_DIR)./appTest/libOne.a
Target_Dll=$(APP_STACK_DIR)./appTest/lib/libone.so
TARGET = $(Target_Lib) $(Target_Dll)
# Compilation rules
all: $(TARGET)
$(Target_Lib): $(C_OBJS)  $(AR) rcs $@ $^
  @echo -e "\n>>>>>> Compiling *$(Target_Lib)* successfully ended\n"
$(Target_Dll): $(C_OBJS)  $(CC) -shared $^ -o $@
  @echo -e "\n>>>>>> Compiling *$(Target_Dll)* successfully ended\n"
$(C_OBJS): %.o: %.c  $(CC) $(CFLAGS) $(INC_CFLAGS) $< -o $@
.PHONY: all clean
clean:  -rm -f $(C_OBJS)  -rm -f $(TARGET)

2. Test Code

Controlling Exported Functions in Linux Shared Libraries

If you need the complete test project code, please leave a message in the backend of the Pou Guangming official account.

3. __attribute__((visibility(“hidden”))) hides functions from external access

Controlling Exported Functions in Linux Shared Libraries

Welcome everyone to follow the official account – Pou Guangming

Leave a Comment