GNU C 的一大特色就是__attribute__ 机制。
#ifndef AddressBook_AddressBookDefines_h //如果没有定义这个头文件
#define AddressBook_AddressBookDefines_h //接下来就定义这个文件,#ifdef __cplusplus //是c++的意思,判断是不是c++语言
#define AB_EXTERN extern "C" __attribute__((visibility ("default")))
//如果是c++语言,就要包含c语言,
//因为在C++里面写C要加上那个说明一下!
//也就是默认为这个动态库外面是不可见的,__attribute__((visibility ("heiden")))或者不设置,默认,设置为:default之后就可以让外面的类看见了。
#else
#define AB_EXTERN extern __attribute__((visibility ("default")))
//否则,这样就可以了
#endif
#endif
so文件,在Linux是动态库文件
visibility用于设置动态链接库中函数的可见性,将变量或函数设置为hidden,则该符号仅在本so中可见,在其他库中则不可见。
g++在编译时,可用参数-fvisibility指定所有符号的可见性(不加此参数时默认外部可见,参考man g++中-fvisibility部分);若需要对特定函数的可见性进行设置,需在代码中使用__attribute__设置visibility属性。
编写大型程序时,可用-fvisibility=hidden设置符号默认隐藏,针对特定变量和函数,在代码中使用__attribute__ ((visibility("default")))另该符号外部可见,这种方法可用有效避免so之间的符号冲突。(这里不是很理解)
实例:
visibility2.cc中可以调用fun1,原因是visibility1.o和visibility2.o同属于一个so文件。
visibility1.cc:
#include <stdio.h>
extern "C" void fun1()
{
printf("in %s\n",__FUNCTION__);
}
__attribute__ ((visibility("hidden"))) void fun1();//若编译此文件时使用了参数-fvisibility=hidden,则此行可以省略
visibility2.cc:
#include <stdio.h>
extern "C" void fun1();
extern "C" void fun2()
{
fun1();
printf("in %s\n",__FUNCTION__);
}
__attribute__ ((visibility("default"))) void fun2();
//若编译此文件时没有使用参数-fvisibility或设置参数-fvisibility=default,则此行可以省略
main.cc:
extern "C" void fun1();
extern "C" void fun2();
int main()
{
fun1();
fun2();
return 0;
}
ll:test
test:main.o libvisibility.so
g++ -o test main.o -lvisibility -L .
main.o::main.cc
g++ -c main.cc
libvisibility.so:visibility1.o visibility2.o
g++ -shared -o libvisibility.so visibility1.o visibility2.o
visibility1.o:visibility1.cc
g++ -fvisibility=hidden -fPIC -c visibility1.cc
visibility2.o:visibility2.cc
g++ -fvisibility=hidden -fPIC -c visibility2.cc
clean:
rm -f *.o *.so test
$ make
g++ -c main.cc
g++ -fvisibility=hidden -fPIC -c visibility1.cc
g++ -fvisibility=hidden -fPIC -c visibility2.cc
g++ -shared -o libvisibility.so visibility1.o visibility2.o
g++ -o test main.o -lvisibility -L .
main.o: In function `main':
main.cc:(.text+0x5): undefined reference to `fun1'
collect2: ld returned 1 exit status
make: *** [test] Error 1
可以看到,main()中可以不可用调用fun1,可以调用fun2,因为fun1已经设置为外部不可见,fun2设置为外部可见。
使用readelf对各个.o文件分析可以看到,fun1的Vis属性为HIDDEN,fun2的Vis属性为DEFAULT:
$ readelf -s visibility1.o|grep fun
6: 0000000000000007 5 OBJECT LOCAL DEFAULT 6 _ZZ4fun1E12__FUNCTION__
12: 0000000000000000 30 FUNC GLOBAL HIDDEN 2 fun1
$ readelf -s visibility2.o|grep fun
6: 0000000000000007 5 OBJECT LOCAL DEFAULT 6 _ZZ4fun2E12__FUNCTION__
12: 0000000000000000 35 FUNC GLOBAL DEFAULT 2 fun2
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND fun1
$ readelf -s libvisibility.so|grep fun
9: 00000000000006ac 35 FUNC GLOBAL DEFAULT 12 fun2
41: 000000000000071d 5 OBJECT LOCAL DEFAULT 14 _ZZ4fun1E12__FUNCTION__
43: 0000000000000729 5 OBJECT LOCAL DEFAULT 14 _ZZ4fun2E12__FUNCTION__
48: 000000000000068c 30 FUNC LOCAL HIDDEN 12 fun1
54: 00000000000006ac 35 FUNC GLOBAL DEFAULT 12 fun2
from:
http://www.tuicool.com/articles/ziyY3u
http://www.cnblogs.com/astwish/p/3460618.html