在 Windows 上使用 MSVC 创建和使用动态库时需要导出导入符号(参见Windows上动态库符号的导出和导入),但在 Linux 上使用 GCC 时,一般好像不需要导入导出符号。其实不然,GCC 编译时并不是不需要导出符号,而是默认导出了所有的符号。
GCC 中也存在一个符号可见性的概念,称之为 Visibility,一般指的就是动态库中符号的可见性。默认情况下,动态库中的所有符号对于外部都是可见的,因此使用者可以直接使用动态库提供的函数。但 GCC 提供了修改可见性的方式,编译时可以通过-fvisibility参数修改默认所有符号的可见性,也可以在代码中使用__attribute__来修改某个符号的可见性。
那既然 GCC 默认已经让所有符号都可见,为什么还要提供选项来隐藏符号呢?符号全部可见岂不是更方便,不用像在 Windows 上那样麻烦的导出导入。其实不是,GCC 推荐隐藏动态库内部使用的符号,只把需要提供给外部使用的符号设置为可见。GCC 的解释为:通过隐藏那些不需要外部使用的符号,可以减少动态库的加载时间,减小动态库文件的大小,能够让编译器生成更优的代码,同时也能避免不同库之间的符号冲突。所以我们在设计动态库时,可以先通过-fvisibility参数使所有符号默认不可见,再通过__attribute__使那些需要提供给外部的符号变为可见。
-fvisibility-fvisibility参数的完整形式如下:
-fvisibility=[default|internal|hidden|protected]
visibility 有四个可以设置的值,其中 internal 和 protected 很少使用到,大部分情况下只需要使用 default 和 hidden 两个值。default 就是 GCC 的默认情况,表示所有符号都是可见的,hidden 表示设置所有符号都是不可见的。
编译动态库时,添加-fvisibility=hidden参数,使所有符号都默认不可见,例如,
g++ -fvisibility=hidden -c foo.cpp -o foo.o__attribute__((visibility(“default”)))
__attribute__中的 visibility 属性用于单独修改某个符号的可见性,会覆盖-fvisibility参数的设置。我们在头文件中声明时,将需要提供给外部使用的符号设为可见,例如,
__attribute__((visibility("default"))) void foo();
class __attribute__((visibility("default"))) Foo
{
...
};对于库的提供者,编译时需要使用__attribute__((visibility("default")))来将符号设为可见,对于库的使用者,这个关键字是可选的,不必像 Windows 上那样一个导出一个导入,但我们可以使用宏来替换这个比较长的关键字,并且兼容 Windows 上的机制。
#ifndef FOO_H
#define FOO_H
#ifdef _WIN32
#define FOO_EXPORT __declspec(dllexport)
#define FOO_IMPORT __declspec(dllimport)
#else
#define FOO_EXPORT __attribute__((visibility("default")))
#define FOO_IMPORT
#endif
#ifdef FOO_DLL
#define FOO_API FOO_EXPORT
#else
#define FOO_API FOO_IMPORT
#endif
FOO_API void func();
class FOO_API Data
{
...
};
#endif参考:
https://gcc.gnu.org/wiki/Visibility
https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

相关推荐
在AVR Studio里使用AVR-GCC
基于Atmega16L的简单音乐制作
AVRGCC/WinAVR编译环境中断函数的使用方法
arm-elg-gcc 怎么编译不了msr cpsr_cf, r1
Makefile的编写指导
m68k-elf-gcc编译的问题....
剖析C语言中a=a+++++a的无聊问题
[求助]arm-linux-gcc找不到标准库函数math.h,什么原因呢?
winavr gcc快速入门
Linux上安装GCC3.4.0编译器过程
新手求助:构造ecos环境时遇到的问题。
ICC GCC傻傻分不清?聊一聊编译器那些事儿
GCC-维基百科
GCC 中文手册
国嵌应用班-1-1(GCC程序编译)
AVR 单片机与GCC 编程V1.1版
用arm-linux-gcc.4.3.2交叉编译器编译linux-3.0.1内核
交叉编译链arm-linux-gcc-3.3.2在ubuntu10.04下的安装
基于ARM11嵌入式远程监控系统的分析与设计
arm-linux-gcc 不认arm宏汇编??
AVR 单片机GCC 程序设计