概述
《GCC的学习(五)动态库接口可见性》一文我翻译了一篇gcc官方文档,那么在实际中,这个可见性是如何体现的呢?
设置__attribute__的优点
- 减少了动态库装载时间
- 方便编译器优化代码
- 更加轻便的动态库
导出所有符号的方法
默认情况下,所有头文件的符号都将会导出。
//fun.cpp
#include <iostream>
#include "fun.h"
void printOne()
{
std::cout<<"1"<<std::endl;
}
void printTwo()
{
std::cout<<"2"<<std::endl;
}
void printThree()
{
std::cout<<"3"<<std::endl;
}
void printAny(double num)
{
std::cout<<num<<std::endl;
}
int getValue()
{
return 4396;
}
对应的头文件
//fun.h
void printOne();
void printTwo();
void printThree();
void printAny(double num);
int getValue();
两步完成动态库制作:
-fPIC
选项编译-c
源代码,生成与位置无关的目标文件fun.o;gcc -fPIC fun.cpp -c
--shared
选项生成动态库;gcc fun.o --shared -o libFun.so
使用nm -CD +动态库查看:
0000000000000880 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000a74 T printThree()
0000000000000ae7 T getValue()
0000000000000aa6 T printAny(double)
0000000000000a10 T printOne()
0000000000000a42 T printTwo()
全部函数都被导出了。
选择性导出符号的方法
gcc在编译源代码时可以指定一个默认的符号导出规则,如果你没有定义这个选项,那么其选项是默认的公有(default).
具体的:
- default 若全部公开,那没必要传递额外的到导出选项
- hidden 默认私有
- internal 暂不了解
- protect 暂不了解
比如,我在编译fun.cpp时指定了默认导出规则hidden
,
gcc -fPIC -fvisibility=hidden -c fun.cpp -shared -o libFun.so # 一定要放在一条语句执行,而且-c不能省略
对于部分需要公开的,我们可以单独指定:
void printOne();
void printTwo();
void printThree(); //没有加__attribute__选项,默认使用编译时的默认属性hidden
__attribute__((visibility ("hidden")))void printAny(double num); //显示使用hidden属性
__attribute__((visibility ("default")))int getValue();//显示指定default属性,即公有
00000000000007d0 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000a37 T getValue() #只有这个被导出
只有getValue函数被导出。用户使用时确实实现了隐藏:
PS:不要用readelf -s libFun.so查看so文件是否输出属性。不知道为啥网上都是这个。事实上,你在生成.o的时候可以用,其他情况不可以用。
用宏来帮助你
前缀分为两种,一种是可见,另一种是不可见。将其设置为宏可以帮助你简单的声明一个动态库可见性。
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
QT中也用了类似的宏:
# ifdef Q_OS_WIN
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
# elif defined(QT_VISIBILITY_AVAILABLE)
# define Q_DECL_EXPORT __attribute__((visibility("default")))
# define Q_DECL_IMPORT __attribute__((visibility("default")))
# define Q_DECL_HIDDEN __attribute__((visibility("hidden")))
# endif
这样一来我们需要保证正确的宏在恰当的时候被调用,而无须关心我们是在编译动态库或者是使用动态库了。通常,我们会增加一个特殊的头文件来解决这个问题。我们先假设我们的动态库名字叫做mysharedlib,一个特殊的头文件mysharedlib_global.h将会被创建,其内容大概是这样:
#include <QtCore/QtGlobal>
#if defined(MYSHAREDLIB_LIBRARY)
# define MYSHAREDLIB_EXPORT Q_DECL_EXPORT
#else
# define MYSHAREDLIB_EXPORT Q_DECL_IMPORT
#endif
[1] https://blog.csdn.net/mutourenzhang/article/details/47803803?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.baidujs&dist_request_id=1328680.52720.16163984131051535&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.baidujs
最后
以上就是从容大神为你收集整理的GCC的学习(六)__attribute__控制动态库可见性的全部内容,希望文章能够帮你解决GCC的学习(六)__attribute__控制动态库可见性所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复