如何优化共享库的大小?

发布于 2024-12-14 00:36:17 字数 1664 浏览 0 评论 0原文

假设我们有巨大的静态库,其中包含许多不需要的功能(在下面的示例中,我们有库 lib1.alib2.a ,其中包含不需要的函数 g1()< /code> 和 f2())。

我们希望使用一些导出方法来构建共享库,这些方法仅使用该巨大库中的少数函数/类。请参见下面的示例:我们要导出函数 foo()

问题

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

示例

文件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 目标文件根据目标文件之间的依赖关系。但没有从 1.o 中删除函数 g1()

Say we have huge static libraries with lots of unneeded features (in the example below we have libraries lib1.a and lib2.a with unneeded functions g1() and f2()).

We want to build shared library with a few exported methods which use only a few functions/classes from that huge libraries. See example below: we want to export function foo().

QUESTIONS

  1. Can we tell linker (ld) which functions/methods we want to export (like we do it for DLL in Windows)?
  2. Can linker resolve dependecies and remove unneeded functions/methods? Or is there any other way to solve the problem?
  3. If you have a solution, please, write the fixes for the example below.

EXAMPLE

File 1.h:

int f1( int n );
int g1( int n );

File 2.h:

int f2( int n );

File foo.cpp:

#include "1.h"
#include "2.h"

int foo( int n )
{
    return f1( n );
}

File 1.cpp:

int f1( int n ) { return n; }
int g1( int n ) { return n; }

File 2.cpp:

int f2( int n ) { return n; }

File 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

And after making target all we have nm res/libFoo.so:

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

So ld has removed 2.o object file according to dependencies between object files. But didn't remove function g1() from 1.o.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

亣腦蒛氧 2024-12-21 00:36:17

也许链接时间优化(即-flto< GCC 4.6 的 /code>选项)有帮助吗?

还有 函数属性 __attribute__ ((visibility ("hidden "))) 和/或 __attribute__ ((weak))

并且进入 *.so 共享对象的代码应使用 -fPIC< 进行编译/代码>

Perhaps Link Time Optimization (i.e. -flto option to GCC 4.6) could help?

And also the function attribute __attribute__ ((visibility ("hidden"))) and/or __attribute__ ((weak))

And code going into *.so shared objects should be compiled with -fPIC

江湖正好 2024-12-21 00:36:17

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

其次,您可以链接所有 1.o,因为这就是 UNIX 链接器的方式工作。

最简单的解决方案(比使用 -flto 简单得多)是通过将 -Wl,--gc-sections 添加到 libFoo.so< 来打开链接器垃圾收集/code> 链接线,并使用 -ffunction-sections -fdata-sections 构建 lib{1,2}.a。这将有效地将每个功能变成自己单独的“书”。

First, as Basile pointed out, you should add -fPIC flag when building lib{1,2}.a.

Second, you get all of 1.o linked in because that's how UNIX linkers work.

The simplest solution (much simpler than using -flto) is to turn on linker garbage collection by adding -Wl,--gc-sections to libFoo.so link line, and to build lib{1,2}.a with -ffunction-sections -fdata-sections. This will effectively turn each function into its own separate "book".

意犹 2024-12-21 00:36:17

我相信在 *.so 中不使用 -fPIC 会使它们包含大量由 ld.so 处理的重定位指令,所以这是首先要尝试的事情。 -flto 应该在编译和链接时都使用,并增加编译时间。添加属性应该逐个函数完成,并且会花费开发人员大量时间(因为您需要选择哪些函数需要它们)。如果代码真的很大(例如超过 100KLOC 的源代码),您可以考虑编写 GCC 插件,或者最好是 GCC MELT 扩展来自定义 GCC 4.6 编译器以自动执行此类任务,但这需要一些工作(几周,而不是几小时)。

我是 GCC MELT 的主要作者(如果对您有帮助的话,我什至会说一些糟糕的俄语),所以我很乐意帮助您使用 MELT。但就您而言,只有当您的库足够大,足以证明需要花费一周以上的时间使用 MELT 自定义 GCC 时,这是值得的。

I believe that not using -fPIC in *.so make them contain a big lot of relocation instructions processed by ld.so, so this is the first thing to try. -flto should be used both when compiling and when linking, and increase the compilation time. Adding the attributes should be done function by function, and would take a lot of your developer's time (because you need to choose which functions need them). If the code is really big (e.g. more than 100KLOC of source code), you could consider coding a GCC plugin or preferably a GCC MELT extension to customize your GCC 4.6 compiler to automate such tasks, but this require some work (weeks, not hours).

I am the main author of GCC MELT (and I even speak some bad Russian if it helps you), so I would be delighted to help you using MELT. But in your case, it is worthwhile only if your library is big enough to justify working more than a week on customizing GCC with MELT.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文