一、偶遇 error: undefined reference to  xxx 问题

  尝试封装通用的接口到一个private.so,然后供客户端使用,private.so编译出来后由sample.cpp依赖调用其中封装的接口,但是一直报error: undefined reference to  xxx的错误,并且检查so、头文件都依赖正确,c方式编译的函数也用extern "C" 声明。

#ifdef __cplusplus
extern "C" {
#endif xxx #ifdef __cplusplus
}
#endif

  于是用如下方法查看so的符号表根本找不到定义的 xxx 函数:

readelf -s private.so
nm -D private.so

  从Android.mk定位问题发现编译参数 CAMX_CFLAGS += -fvisibility=hidden ,此参数的作用就是将函数名隐藏,需要暴露给用户的函数接口可以单独通过 __attribute__((visibility ("default"))) 声明避免被隐藏。

LOCAL_CFLAGS := $(CAMX_CFLAGS)
LOCAL_CPPFLAGS := $(CAMX_CPPFLAGS)

  因此如下声明后,xxx函数就能被链接找到,编译通过。

#ifdef __cplusplus
extern "C" {
#endif __attribute__((visibility ("default"))) xxx #ifdef __cplusplus
}
#endif

  -fvisibility 参数具体说明如下:

man gcc:

-fvisibility=default|internal|hidden|protected
Set the default ELF image symbol visibility to the specified option---all symbols are marked with this unless overridden within the code. Using this feature can very
substantially improve linking and load times of shared object libraries, produce more optimized code, provide near-perfect API export and prevent symbol clashes. It is
strongly recommended that you use this in any shared objects you distribute. Despite the nomenclature, "default" always means public; i.e., available to be linked against from outside the shared object. "protected" and "internal" are pretty useless
in real-world usage so the only other commonly used option is "hidden". The default if -fvisibility isn't specified is "default", i.e., make every symbol public---this
causes the same behavior as previous versions of GCC. A good explanation of the benefits offered by ensuring ELF symbols have the correct visibility is given by "How To Write Shared Libraries" by Ulrich Drepper (which can be
found at <http://people.redhat.com/~drepper/>)---however a superior solution made possible by this option to marking things hidden when the default is public is to make the
default hidden and mark things public. This is the norm with DLLs on Windows and with -fvisibility=hidden and "__attribute__ ((visibility("default")))" instead of
"__declspec(dllexport)" you get almost identical semantics with identical syntax. This is a great boon to those working with cross-platform projects. For those adding visibility support to existing code, you may find #pragma GCC visibility of use. This works by you enclosing the declarations you wish to set visibility
for with (for example) #pragma GCC visibility push(hidden) and #pragma GCC visibility pop. Bear in mind that symbol visibility should be viewed as part of the API interface
contract and thus all new code should always specify visibility when it is not the default; i.e., declarations only for use within the local DSO should always be marked
explicitly as hidden as so to avoid PLT indirection overheads---making this abundantly clear also aids readability and self-documentation of the code. Note that due to ISO
C++ specification requirements, "operator new" and "operator delete" must always be of default visibility. Be aware that headers from outside your project, in particular system headers and headers from any other library you use, may not be expecting to be compiled with visibility
other than the default. You may need to explicitly say #pragma GCC visibility push(default) before including any such headers. extern declarations are not affected by -fvisibility, so a lot of code can be recompiled with -fvisibility=hidden with no modifications. However, this means that calls to
"extern" functions with no explicit visibility use the PLT, so it is more effective to use "__attribute ((visibility))" and/or "#pragma GCC visibility" to tell the compiler
which "extern" declarations should be treated as hidden. Note that -fvisibility does affect C++ vague linkage entities. This means that, for instance, an exception class that is be thrown between DSOs must be explicitly marked
with default visibility so that the type_info nodes are unified between the DSOs. An overview of these techniques, their benefits and how to use them is at <http://gcc.gnu.org/wiki/Visibility>.

二、动态库函数隐藏技巧

  向客户提供动态链接库(.so)时,有些关键的函数名不希望暴露出去,此时便可以通过gcc的-fvisibility=hidden选项对编译生成的so进行函数符号隐藏,如:LOCAL_CPPFLAGS +=-fvisibility=hidden,执行编译后,使用nm -D xxx.so命令或者readelf --symbols xxx.so查看函数名的确被隐藏,但此时是将所有函数名都隐藏了,那么客户加载so时需要调用的接口函数名(xxx)也会找不到定义,导致编译报undefined reference to xxx错误,所以需要暴露(导出)的函数前应该增加属性__attribute__ ((visibility("default")))设置成可见。

例如:

__attribute__ ((visibility("default")))
void hello(void)
{
}

  实际项目开发中可以通过宏来控制,更加方便:

#ifdef DCIRDLL_EXPORTS
#ifdef PLATFORM_LINUX
#define MYDCIR_API __attribute__((visibility ("default"))) //Linux动态库(.so)
#else
#define MYDCIR_API __declspec(dllexport)            //Windows动态库(.dll)
#endif
#else
#define MTDCIR_API
#endif

  在头文件中声明即可:


MTDCIR_API const voide hello();

  

-end-

最新文章

  1. JS-改变页面的颜色之变化核心-获取六位的随机数
  2. (BFS)poj1465-Multiple
  3. 小甲鱼PE详解之输入表(导入表)详解2(PE详解08)
  4. GNU glibc
  5. ASP.Net IE10 _doPostBack 未定义错误【转】
  6. I/O多路转接 --- UNIX环境高级编程
  7. 层次节点——NODE节点
  8. chroot
  9. 实时音视频互动系列(下):基于 WebRTC 技术的实战解析
  10. windows 10 安装tensorflow
  11. ocelot 自定义认证和授权
  12. CAN总线为什么要有两个120Ω的终端电阻?
  13. Windows7上安装Ubuntu双系统
  14. C 单向链表的创建、插入及删除
  15. C#调用C++(QT5.5.1项目)的C++/CLI(CLR项目)项目技术笔记
  16. struts2_模型驱动
  17. django配置一个网站建设
  18. 搞明白GOROOT,GOPATH,GOBIN,project目录
  19. centos/rhel 7 几个最重要变化(systemd,firewalld,networkmanager,文件系统)
  20. 20165306学习基础和C语言基础调查

热门文章

  1. RobHess的SIFT代码解析步骤四
  2. liunx加载JX2410标准配置文件
  3. Flutter——Image组件(图片组件)
  4. 《浏览器工作原理与实践》&lt;07&gt;变量提升:JavaScript代码是按顺序执行的吗?
  5. selenium八种定位元素方法
  6. 微信小程序 getSystemInfoSync
  7. BZOJ2140 稳定婚姻[强连通分量]
  8. django-session的使用---数据库,缓存型
  9. python镜像
  10. MyEclipse运行项目出现 The user operation is waiting for &quot;Building workspace&quot; to complete