C++ 如何优化共享库的大小?

C++ 如何优化共享库的大小?,c++,optimization,android-ndk,shared-libraries,C++,Optimization,Android Ndk,Shared Libraries,假设我们有巨大的静态库,其中包含许多不需要的特性(在下面的示例中,我们有库lib1.a和lib2.a,其中包含不需要的函数g1()和f2()) 我们希望用几个导出的方法构建共享库,这些方法只使用来自庞大库的几个函数/类。请参见下面的示例:我们希望导出函数foo() 问题 我们能告诉链接器(ld)我们想要导出哪些函数/方法吗(就像我们在Windows中为DLL所做的那样) 链接器能否解决依赖关系并删除不需要的函数/方法?或者有没有其他办法解决这个问题 如果您有解决方案,请为下面的示例编写修复程序

假设我们有巨大的静态库,其中包含许多不需要的特性(在下面的示例中,我们有库
lib1.a
lib2.a
,其中包含不需要的函数
g1()
f2()

我们希望用几个导出的方法构建共享库,这些方法只使用来自庞大库的几个函数/类。请参见下面的示例:我们希望导出函数
foo()

问题

  • 我们能告诉链接器(
    ld
    )我们想要导出哪些函数/方法吗(就像我们在Windows中为DLL所做的那样)
  • 链接器能否解决依赖关系并删除不需要的函数/方法?或者有没有其他办法解决这个问题
  • 如果您有解决方案,请为下面的示例编写修复程序
  • 示例

    文件
    1.h

    int f1( int n );
    int g1( int n );
    
    int f2( int n );
    
    文件
    2.h

    int f1( int n );
    int g1( int n );
    
    int f2( int n );
    
    文件
    foo.cpp

    #include "1.h"
    #include "2.h"
    
    int foo( int n )
    {
        return f1( n );
    }
    
    int f1( int n ) { return n; }
    int g1( int n ) { return n; }
    
    int f2( int n ) { return n; }
    
    文件
    1.cpp

    #include "1.h"
    #include "2.h"
    
    int foo( int n )
    {
        return f1( n );
    }
    
    int f1( int n ) { return n; }
    int g1( int n ) { return n; }
    
    int f2( int n ) { return n; }
    
    文件
    2.cpp

    #include "1.h"
    #include "2.h"
    
    int foo( int n )
    {
        return f1( n );
    }
    
    int f1( int n ) { return n; }
    int g1( int n ) { return n; }
    
    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
    
    在制作了target
    all
    之后,我们有了
    nm res/libFoo。因此

    ...
    000001d8 T _Z2f1i
    0000020e T _Z2g1i
    000001c4 T _Z3fooi
    ...
    

    因此,
    ld
    根据对象文件之间的依赖关系删除了
    2.o
    对象文件。但是没有从
    1.o

    中删除函数
    g1()
    ,也许链接时间优化(即GCC 4.6的选项)会有所帮助

    以及
    \uuuu属性(可见性(“隐藏”))
    和/或
    \uuu属性(弱))


    所以共享对象应该用
    -fPIC
    编译。我相信在
    *中不使用
    -fPIC
    。所以
    会使它们包含大量由
    ld处理的重定位指令。所以这是第一件尝试的事情<编译和链接时都应使用code>-flto
    ,并增加编译时间。添加属性应该一个函数一个函数地完成,并且会占用开发人员大量的时间(因为您需要选择哪些函数需要它们)。如果代码真的很大(例如,超过100KLoC的源代码),您可以考虑编码GCC插件,或者最好是扩展来定制GCC 4.6编译器来自动化这些任务,但是这需要一些工作(周,而不是小时)。p>
    我是GCC MELT的主要作者(如果对你有帮助的话,我甚至会说一些糟糕的俄语),所以我很乐意帮助你使用MELT。但在您的情况下,只有当您的库足够大,足以证明使用MELT定制GCC的工作时间超过一周时,才有价值。

    首先,正如Basile指出的,您应该在构建
    库{1,2}.a
    时添加
    -fPIC
    标志

    第二,您可以链接所有
    1.o
    ,因为这是一个很好的例子


    最简单的解决方案(比使用
    -flto
    简单得多)是通过向
    libFoo.so
    链接行添加
    -Wl,--gc节来启用链接器垃圾收集,并使用
    -ffunction节-fdata节构建
    lib{1,2}.a
    。这将有效地将每个函数变成它自己单独的“书”。

    我认为在
    *中不使用
    -fPIC
    。因此
    使它们包含大量由
    ld处理的重新定位指令。因此
    感谢
    -flto
    提示。我认为应该行得通。小问题是我在windows下使用交叉编译器,它不知道
    -flto
    选项。将立即在Mac上试用
    :)
    -flto
    仅适用于最新的GCC编译器(即GCC 4.6)。我在PC上找到的所有GCC发行版都是4.4.*及更旧版本。将生成4.6.2版本并重试。我已经尝试了
    g++$(cxflags)-f函数节-fdata节-c-o obj/$@src/$*.cpp
    。但是
    g1()
    仍然存在于
    libFoo.so
    中。我错过了什么吗?感谢“UNIX链接器如何工作”链接。我在找这样的文章。是的:你还必须打开链接器垃圾收集(我更新了答案)。谢谢。它起作用了<代码>:)
    。将阅读关于
    -ffunction sections-fdata sections
    arguments.@artyom.stv您误解了GCC文档。这些选项使GCC生成更大的对象文件,但不会显著影响最终的可执行文件(或共享库)。这些选项还使最终链接变慢,但不会影响可执行文件(或共享库)本身的执行速度。
    -flto
    很可能会给您带来额外的加速,因此您可能无论如何都应该对此进行研究。因为我们得到了
    。因此
    库~8Mb。以及其他一些数据。一些安卓设备没有足够的内存来安装应用程序。好的,“安卓”。在这种情况下的魔术词。那么请联系我或其他人使用gcc-melt@googlegroups.com(文档确实不够充分!)