假设我们拥有包含许多不需要的功能的巨大静态库(在下面的示例中,我们有库lib1.a
和lib2.a
,其中包含不需要的函数g1()
和f2()
)。< / p>
我们希望使用一些导出的方法构建共享库,这些方法只使用那些巨大的库中的一些函数/类。请参阅下面的示例:我们要导出函数foo()
。
问题
ld
)我们要导出哪些函数/方法(就像我们在Windows中为DLL做的那样)?示例
档案1.h
:
int f1( int n );
int g1( int n );
档案2.h
:
int f2( int n );
档案foo.cpp
:
#include "1.h"
#include "2.h"
int foo( int n )
{
return f1( n );
}
档案1.cpp
:
int f1( int n ) { return n; }
int g1( int n ) { return n; }
档案2.cpp
:
int f2( int n ) { return n; }
档案makefile
:
CXXFLAGS = -g -I. -Wall -Wno-sign-compare
all: prepare libFoo.so
clean:
rm -f obj/*.a obj/*.o res/*.so
prepare:
mkdir -p src
mkdir -p obj
mkdir -p res
lib1.a lib2.a: lib%.a: %.o
ar r obj/$@ obj/$*.o
1.o 2.o foo.o: %.o:
g++ $(CXXFLAGS) -c -o obj/$@ src/$*.cpp
libFoo.so: lib1.a lib2.a foo.o
ld -shared -o res/libFoo.so obj/foo.o -Lobj -l1 -l2
制作目标all
后,我们有nm res/libFoo.so
:
...
000001d8 T _Z2f1i
0000020e T _Z2g1i
000001c4 T _Z3fooi
...
因此ld
已根据目标文件之间的依赖关系删除了2.o
目标文件。但是没有从g1()
删除功能1.o
。
答案 0 :(得分:4)
或许链接时间优化(即GCC 4.6的-flto
选项)可能会有所帮助吗?
还有function attribute __attribute__ ((visibility ("hidden")))
和/或__attribute__ ((weak))
进入*.so
共享对象的代码应该使用-fPIC
答案 1 :(得分:3)
我认为在-fPIC
中不使用*.so
会使它们包含由ld.so
处理的大量重定位指令,因此这是首先尝试的内容。编译和链接时都应使用-flto
,并增加编译时间。添加属性应该逐个函数完成,并且需要花费大量开发人员的时间(因为您需要选择需要它们的函数)。如果代码非常大(例如,超过100KLOC的源代码),您可以考虑编写GCC插件或最好是GCC MELT扩展来自定义GCC 4.6编译器以自动执行此类任务,但这需要一些工作(几周)而不是几小时)。
我是GCC MELT的主要作者(如果它对你有所帮助,我甚至会说一些不好的俄语),所以我很乐意帮助你使用MELT。但在您的情况下,只有当您的库足够大以证明使用MELT定制GCC的工作超过一周时才值得。
答案 2 :(得分:3)
首先,正如Basile指出的那样,您应该在构建-fPIC
时添加lib{1,2}.a
标记。
其次,您将所有1.o
链接在一起,因为它是how UNIX linkers work。
最简单的解决方案(比使用-flto
简单得多)是通过将-Wl,--gc-sections
添加到libFoo.so
链接行来启用链接器垃圾回收,并使用{构建lib{1,2}.a
{1}}。这将有效地将每个功能转变为自己独立的“书”。