制作优美的库文件

目录

前言

一、项目工程

二、制作过程

1.编译选项

2.符号处理

总结


前言

本文讲的是如何制作库文件,你可能会问了,制作库文件不就是一个编译命令吗?没错,生成一个库文件就是用一条编译命令即可达到目的,但是如果制作一个接口完美封装、安全、高效的库文件,还是需要查阅很多资料,了解很多编译原理才能做到的,本文就是我查阅了很多资料,花了几天时间,做了很多次实验而实现的,下面就是我对这个功能的总结。


一、项目工程

设计一个数组元素的加减乘除作为库对外的接口

INT32 ARRAY_ADD(INT32 array[], UINT32 ItemNum);

INT32 ARRAY_MINUS(INT32 array[], UINT32 ItemNum);

INT32 ARRAY_MUL(INT32 array[], UINT32 ItemNum);

INT32 ARRAY_DIV(INT32 array[], UINT32 ItemNum);

INT32 ARRAY_MOD(INT32 array[], UINT32 ItemNum);

计算过程需要调用基本的加减乘除函数,这些接口是库里面的调用,不希望被导出到库外面

INT32 add (int a, int b);

INT32 div(INT32 a, INT32 b);

INT32 minus(INT32 a, INT32 b);

INT32 mod(INT32 a, INT32 b);

INT32 mul(INT32 a, INT32 b);

目录结构如下:

二、制作过程

        根据我的期望,库外面只能访问到数组运算的接口,其他接口都不希望被看到,那么按照如下步骤实现。

1.编译选项

GCC有非常多的选项可供我们使用,C++ visibility属性可以控制共享文件导出符号,我们的需求主要具备以下几个条件:

GCC版本需要大于4.0

编译时需要增加选项 -fvisibility=hidden and -fvisibility-inlines-hidden

__attribute__((visibility ("default")))  被这个修饰的接口可以被导出

__attribute__((visibility("hidden")))   被这个修饰的接口不可以被导出,只能在库内部调用

-Wl,--exclude-libs,ALL  当调用了其他静态库的函数时,也能够从我们库里面导出,增加这个编译选项就是将使用的其他库里的函数禁止导出。但是我实验了不成功,还不知道原因,你知道的话欢迎留言告诉我。

参考资料:

Visibility - GCC Wiki

https://www.akkadia.org/drepper/dsohowto.pdf     P18  2.2.2节

该资料中定义了一套完备的宏定义,针对我们这个工程,只需要下面的即可:

#ifndef _PUBLIC_H
#define _PUBLIC_H

#if __GNUC__>=4
    #define CAL_API_PUBLIC __attribute__((visibility ("default")))
    #define CAL_API_LOCAL __attribute__((visibility("hidden")))
#else
    #define CAL_API_PUBLIC 
    #define CAL_API_LOCAL 
#endif

#endif

2.符号处理

编译命令:

gcc  -Wl,--exclude-libs,ALL -fvisibility=hidden -I. -c *.c -o *.o;

重新链接成目标文件

ld -r $(OBJS) -o $(TARGET).o

隐藏掉hidden属性的接口及本地接口,此时不需要导出的符号从nm命令查看已经从U类型编程了u类型

objcopy --localize-hidden --discard-locals $(TARGET).o $(TARGET).o

去掉无用的符号,这里可以将u类型的去掉,只剩下U或者T类型的接口

strip --strip-unneeded $(TARGET).o

打包

ar crv $(TARGET).a $(TARGET).o

最终只导出了需要的接口


总结

        隐藏接口除了安全性,还可以避免库与库之间的函数名重复的问题,所以编程要不断的思考,怎么样将自己的工作做的精益求精,找到对的,适合的解决办法。

猜你喜欢

转载自blog.csdn.net/huyongfu2004/article/details/122325462