Linux共享库控制导出函数

2020-10-29 14:39:00 浏览数 (1)

点击上方蓝字可直接关注!方便下次阅读。如果对你有帮助,麻烦点个在看或点个赞,感谢~ 文章首发 公众号—— Pou光明

在上海出差辛勤工作的第三天......

之前的文章介绍了Linux中对共享库中同名函数的处理规则——根据链接库的顺序来确定调用哪个函数。

本次介绍共享库其他一些有意思的性质。

在我们开发过程中,难免会使用到第三方库,而且时不时还需要更新,某些情况下还要兼容不同版本并维护。

按照上次验证的结果,如果两个不同版本库中有同名函数,并且需要兼容,那我们如何确定要调用哪个函数呢?使用链接库的顺序来处理,显然不是一个好办法。【虽然大部分情况下库的函数名称都是不一样的】

再来一个场景,当我们拿到第三方库和头文件,我们还想看下库里面还有哪些其他的函数接口,这时可以使用 nm -D *.so 进行查看。下面以libone.so为例说明,红线部分为我自己定义的函数。

为了解耦函数,会将功能模块拆解成多个函数,但实际暴露给用户的时候可能只有几个。如果想让用户使用nm -D *.so命令查看时只看到封装的几个函数,在编写makefile时可以使用CFLAGS = -fvisibility=hidden 标志,再将给用户的函数名称前加上__attribute__((visibility("default")))即可。

makefile使用CFLAGS = -fvisibility=hidden标志时,会将所有函数全部隐藏,不使用该标志时,默认所有函数全部公开。

gcc 版本4以上可用【未测试】。

测试用例源码:

1. Create shareLib

libOne.h

代码语言:javascript复制
#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

    /*
*名称:测试用例
*描述:
*参数:无
*返回值:0————成功;其他————错误号。
*说明:
*/
    OPEN_API_DEFAULT int myPrintfDefault();

    OPEN_API_HIDDEN int myPrintfHidden();

#ifdef __cplusplus
}
#endif

#endif

libOne.c

代码语言:javascript复制
#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 is lib One default ! n");
    return 0;
}

OPEN_API_LIBONETEST_HIDDEN int myPrintfHidden()
{
    printf("Hi , I am is lib One hidden ! n");
    return 0;
}

Makefile :

代码语言:javascript复制
#################################################################
#                     PRIVATE PART                              #
#################################################################
APP_STACK_DIR = .
# 内部头文件
INC_CFLAGS  = -I $(APP_STACK_DIR)/Inc
# 对外接口目录
#INC_CFLAGS  = -I $(APP_STACK_DIR)/Intf
# 动态链接库
#LDFLAGS  = -lName  -lName

# 源文件
CSRC  = $(APP_STACK_DIR)/Src/*.c
C_OBJS  = $(patsubst %.c,%.o,$(wildcard $(CSRC)))
# 动态库编译标志
DEBUG = y
ifeq ($(DEBUG),y)
DEBUG_CFLAGS  = -DDEBUG
DEBUG_CFLAGS  = -g
endif
CFLAGS  = -c
CFLAGS  = -Os
CFLAGS  = -Wall
CFLAGS  = -fPIC
CFLAGS  = -fvisibility=hidden  #隐藏属性
CFLAGS  = $(DEBUG_CFLAGS) 
# 目标文件
#Target_Lib=$(APP_STACK_DIR)./appTest/libOne.a
Target_Dll=$(APP_STACK_DIR)./appTest/lib/libone.so
TARGET = $(Target_Lib) $(Target_Dll)
# 编译规则
all:$(TARGET)
$(Target_Lib):$(C_OBJS)
  $(AR) rcs $@ $^
  @echo -e "n>>>>> Compiling *$(Target_Lib)* sucessfully endedn"
$(Target_Dll):$(C_OBJS)
  $(CC) -shared $^ -o $@
  @echo -e "n>>>>> Compiling *$(Target_Dll)* sucessfully endedn"
$(C_OBJS):%.o:%.c
  $(CC) $(CFLAGS) $(INC_CFLAGS) $< -o $@ 
.PHONY:all clean 
clean:
  -rm -f $(C_OBJS)
  -rm -f $(TARGET)

2. Test Code

如需完成测试工程代码,可在Pou光明公众号后台留言。

3. __attribute__((visibility("hidden"))) 将函数对外隐藏

0 人点赞