在Linux下动态库(.so)中,通过GCC的C++ visibility属性可以控制共享文件导出符号。在GCC 4.0及以上版本中,有个visibility属性,可见属性可以应用到函数、变量、模板以及C++类。

限制符号可见性的原因:从动态库中尽可能少地输出符号是一个好的实践经验。输出一个受限制的符号会提高程序的模块性,并隐藏实现的细节。动态库装载和识别的符号越少,程序启动和运行的速度就越快。导出所有符号会减慢程序速度,并耗用大量内存。

“default”:用它定义的符号将被导出,动态库中的函数默认是可见的。”hidden”:用它定义的符号将不被导出,并且不能从其它对象进行使用,动态库中的函数是被隐藏的。default意味着该方法对其它模块是可见的。而hidden表示该方法符号不会被放到动态符号表里,所以其它模块(可执行文件或者动态库)不可以通过符号表访问该方法。

要定义GNU属性,需要包含__attribute__和用括号括住的内容。可以将符号的可见性指定为visibility(“hidden”),这将不允许它们在库中被导出,但是可以在源文件之间共享。实际上,隐藏的符号将不会出现在动态符号表中,但是还被留在符号表中用于静态链接

导出列表由编译器在创建共享库的时候自动生成,也可以由开发人员手工编写。导出列表的原理是显式地告诉编译器可以通过外部文件从对象文件导出的符号是哪些。GNU用户将此类外部文件称作为”导出映射”。

以下是测试代码,各个文件的内容如下:

Dynamic_Library/library.hpp:

#ifndef FBC_LIBRARY_LIBRARY_HPP_
#define FBC_LIBRARY_LIBRARY_HPP_// reference: https://gcc.gnu.org/wiki/Visibility
//            https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/SymbolVisibility.html#ifdef __GNUC__ >= 4 // it means the compiler is GCC version 4.0 or later#ifdef FBC_EXPORT#warning "===== dynamic library ====="#define FBC_API_PUBLIC __attribute__((visibility ("default")))#define FBC_API_LOCAL __attribute__((visibility("hidden")))#else#warning "===== static library ====="#define FBC_API_PUBLIC#define FBC_API_LOCAL#endif
#else#error "##### requires gcc version >= 4.0 #####"
#endif#ifdef __cplusplus
extern "C" {
#endifFBC_API_PUBLIC int library_add(int a, int b);
FBC_API_LOCAL void print_log();#ifdef FBC_EXPORT
FBC_API_PUBLIC int value;
#endif#ifdef __cplusplus
}
#endiftemplate<typename T>
class FBC_API_PUBLIC Simple {
public:Simple() = default;void Init(T a, T b);T Add() const;private:T a, b;
};#endif // FBC_LIBRARY_LIBRARY_HPP_

Dynamic_Library/library.cpp:

#include "library.hpp"
#include <iostream>
#include <string>FBC_API_PUBLIC int library_add(int a, int b)
{
#ifdef FBC_EXPORTvalue = 11;
#endiffprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);return (a+b);
}FBC_API_LOCAL void print_log()
{fprintf(stderr, "print_log function is hidden, in dynamic library: %s, %d\n", __FUNCTION__, __LINE__);
}template<typename T>
void Simple<T>::Init(T a, T b)
{this->a = a;this->b = b;
}template<typename T>
T Simple<T>::Add() const
{fprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);return (a + b);
}template class Simple<int>;
template class Simple<std::string>;

Test_Dynamic_Library/test_library.hpp:

#ifndef FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_
#define FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_namespace test_library_ {#ifdef __cplusplusextern "C" {
#endifint test_library_1();
int test_library_2();
int test_library_3();#ifdef __cplusplus}
#endif} // namespace test_library_#endif // FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_

Test_Dynamic_Library/test_library.cpp:

#include "test_library.hpp"
#include <iostream>
#include <string>#include <library.hpp>namespace test_library_ {int test_library_1()
{int a{ 4 }, b{ 5 }, c{ 0 };c = library_add(a, b);fprintf(stdout, "%d + %d = %d\n", a, b, c);#ifdef FBC_EXPORTfprintf(stdout, "dynamic library: value: %d\n", value);
#endifreturn 0;
}int test_library_2()
{Simple<int> simple1;int a{ 4 }, b{ 5 }, c{ 0 };simple1.Init(a, b);c = simple1.Add();fprintf(stdout, "%d + %d = %d\n", a, b, c);Simple<std::string> simple2;std::string str1{ "csdn blog: " }, str2{ "http://blog.csdn.net/fengbingchun" }, str3;simple2.Init(str1, str2);str3 = simple2.Add();fprintf(stdout, "contents: %s\n", str3.c_str());return 0;
}int test_library_3()
{
#ifdef FBC_EXPORTfprintf(stdout, "dynamic library cann't run print_log function\n");
#elseprint_log();
#endifreturn 0;
}} // namespace test_library_

Test_Dynamic_Library/main.cpp:

#include <iostream>
#include "test_library.hpp"int main()
{test_library_::test_library_1();test_library_::test_library_2();test_library_::test_library_3();return 0;
}

CMakeLists.txt:

# CMake file for Samples_Dynamic_Library# 设定依赖的CMake版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)# 指定项目名称
PROJECT(Test_Dynamic_Library)# 打印相关信息, CMAKE_CURRENT_SOURCE_DIR指的是当前处理的CMakeLists.txt所在的路径
MESSAGE(STATUS "current path: ${CMAKE_CURRENT_SOURCE_DIR}")# 使CMake支持C++11特性
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu++0x")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")# 定义用户自定义变量
SET(PATH_DYNAMIC_LIBRARY_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Dynamic_Library)
SET(PATH_TEST_DYNAMIC_LIBRARY_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Test_Dynamic_Library)
SET(PATH_DYNAMIC_LIBRARY_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Dynamic_Library)
#MESSAGE(STATUS "Dynamic Library cpp files path: ${PATH_DYNAMIC_LIBRARY_CPP_FILES}")
#MESSAGE(STATUS "Test Dynamic Library cpp files path: ${PATH_TEST_DYNAMIC_LIBRARY_CPP_FILES}")# 递归查询所有匹配的文件:*.cpp
FILE(GLOB_RECURSE DYNAMIC_LIBRARY_CPP_LIST ${PATH_DYNAMIC_LIBRARY_CPP_FILES}/*.cpp)
FILE(GLOB_RECURSE TEST_DYNAMIC_LIBRARY_CPP_LIST ${PATH_TEST_DYNAMIC_LIBRARY_CPP_FILES}/*.cpp)
#MESSAGE(STATUS "Dynamic Library cpp list: ${DYNAMIC_LIBRARY_CPP_LIST}")
#MESSAGE(STATUS "Test Dynamic Library cpp list: ${TEST_DYNAMIC_LIBRARY_CPP_LIST}")IF (BUILD_DYNAMIC_LIBRARY)# 添加编译参数,添加-D预编译宏定义,可以一次添加多个ADD_DEFINITIONS(-DFBC_EXPORT)# 生成动态库ADD_LIBRARY(Dynamic_Library SHARED ${DYNAMIC_LIBRARY_CPP_LIST})
ELSE()ADD_LIBRARY(Static_Library STATIC ${DYNAMIC_LIBRARY_CPP_LIST})
ENDIF()# 指定需要包含的头文件
INCLUDE_DIRECTORIES(${PATH_DYNAMIC_LIBRARY_INCLUDE_DIR})# 生成可执行文件Test_Dynamic_Library
ADD_EXECUTABLE(Test_Dynamic_Library ${TEST_DYNAMIC_LIBRARY_CPP_LIST})
IF (BUILD_DYNAMIC_LIBRARY)# 用来为target添加需要链接的共享库,指定工程所用的依赖库,包括动态库和静态库TARGET_LINK_LIBRARIES(Test_Dynamic_Library Dynamic_Library)
ELSE()TARGET_LINK_LIBRARIES(Test_Dynamic_Library Static_Library)
ENDIF()

编译方法(ReadMe.txt):

在Linux下通过CMake编译Samples_Dynamic_Library中的测试代码步骤:
将终端定位到Linux_Code_Test/Samples_Dynamic_Library,依次执行如下命令:
$ mkdir build
$ cd build
// Note:-DBUILD_DYNAMIC_LIBRARY=1,编译生成动态库; -DBUILD_DYNAMIC_LIBRARY=0, 编译生成静态库
$ cmake -DBUILD_DYNAMIC_LIBRARY=1 ..
$ make (生成动态库和执行文件)
$ ./Test_Dynamic_Library

GitHub:https://github.com/fengbingchun/Linux_Code_Test

Linux下__attribute__((visibility (default)))的使用相关推荐

  1. C语言之__attribute__((visibility(“default“)))等gcc flag讲解(六十二)

    目录 1.概述 2.程序说明 <1>.test.h <2>.test.c <3>.main.c 3.编译实验 <1>.gcc显示声明:-fvisibil ...

  2. Linux下__attribute__((aligned(n)))的使用

    关键字__attribute__允许你在定义struct.union.变量等类型时指定特殊属性.此关键字后面是跟着双括号括起来的属性说明.__attribute__不属于标准C语言,它是GCC对C语言 ...

  3. __attribute__((visibility(default)))

    网址:http://blog.csdn.net/mutourenzhang/article/details/47803803 网址:http://www.cnblogs.com/fortunely/p ...

  4. linux怎么判断全局符号,Linux下全局符号覆盖有关问题

    Linux下全局符号覆盖问题 在windows上,默认情况下,动态库中的符号都是对外隐藏的,除非你显示的指出要导出哪些符号,否则外界是看不到的.但是linux下情况刚好相反,对静态变量和全局变量,li ...

  5. __attribute__((visibility()))

    Table of Contents __attribute__((visibility("default"))) 1. 当-fvisibility=hidden时 2. 当-fvi ...

  6. Linux下减小动态库大小的方法

    在一些业务场景下,需要对动态库的大小进行限制,主要有如下几种方法: 1. 编译选项使用-Os,表示以最小化大小为优化方向 2. 去除-g选项,进而去除调试信息 3. 通过strip裁剪符号及调试信息 ...

  7. Linux下locale: Cannot set LC_CTYPE to default locale: No such file or directory警告

    在Linux下使用locale命令提示如下警告: locale: Cannot set LC_CTYPE to default locale: No such file or directory lo ...

  8. Linux下的静态链接库和动态链接库编程

    Linux下的静态链接库和动态链接库编程 参考: Linux下的静态链接库和动态链接库编程 - Histring - 博客园 Mac下静态库和动态库的创建和使用_C/C++_vincent2610的专 ...

  9. 64位Slitaz Linux下Glibc 2.20编译式更新安装成功

    目录 一.编译需求 二.编译前的环境 三.编译的程序包 四.开始编译 五.总结 一.编译需求 我使用的是64位Slitaz的linux系统(中文),glibc的版本只有2.14.1,运行teamvie ...

最新文章

  1. php时间处理类,PHP常见的日期处理
  2. Apache ZooKeeper - ZK的ACL权限控制( Access Control List )
  3. html5新知识点,Html5基本知识点
  4. 点击模型:达观数据提升算法精度的利器
  5. [学习备忘录]编译gdb及gdbserver
  6. android 电量详情,Android应用开发之Android 8.0 电池-)耗电详情获取方法
  7. Apache 安全配置方法
  8. android c语言串口通信,安卓串口通信能用的modebus CRC16计算,附对应的C语言CRC16
  9. 2.SRE:Google运维解密 --- Google 生产环境:SRE 视角
  10. (day 08 - 先序遍历+判断+递归)剑指 Offer 26. 树的子结构
  11. 使用 JavaScript 生成二维码 —— QRCode.js
  12. spring-第十三篇之零配置支持
  13. 「2020目标一」项目管理PMP
  14. 【硬件】PIC32单片机烧写器以及线序说明
  15. Hurst指数估计方法(时域)——DFA
  16. 计算机标准用户英文名称,标准计算机专业英文简历范文
  17. ffmpeg批量将图片合并为视频
  18. 基于微信小程序的宿舍管理平台
  19. java 对照 术语_JAVA的部分术语中英文对照(
  20. 微信小程序云开发上传word文档到云存储器

热门文章

  1. 代码运行时间测试C++
  2. 深度学习--TensorFlow(4)BP神经网络(损失函数、梯度下降、常用激活函数、梯度消失梯度爆炸)
  3. opencv中image watch插件安装与使用教程
  4. 微信有电脑客户端吗_如何在一个电脑上登录多个微信号
  5. TypeScript 的 ?: 、两个问号、?. 分别是什么意思?
  6. 设置VSCode Git签出分支快捷键Alt+G
  7. python pdb 基础调试
  8. Linux虚拟机连不上网
  9. Mybatis学习记录-使用问题总结之一DISTINCT
  10. tensorflow学习笔记————分类MNIST数据集