Как оптимизировать размер разделяемой библиотеки? - PullRequest
11 голосов
/ 05 ноября 2011

Скажем, у нас есть огромные статические библиотеки с множеством ненужных функций (в приведенном ниже примере есть библиотеки lib1.a и lib2.a с ненужными функциями g1() и f2()).

Мы хотимсоздать общую библиотеку с несколькими экспортированными методами, которые используют только несколько функций / классов из этих огромных библиотек.Смотрите пример ниже: мы хотим экспортировать функцию foo().

ВОПРОСЫ

  1. Можем ли мы сообщить компоновщику (ld), какие функции / методы нам нужны?экспортировать (как мы это делаем для DLL в Windows)?
  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 объектный файл в соответствии с зависимостями между объектными файлами.Но не удалил функцию g1() из 1.o.

Ответы [ 3 ]

4 голосов
/ 05 ноября 2011

Возможно Оптимизация времени соединения (т. Е. -flto опция для GCC 4.6) может помочь?

А также атрибут функции __attribute__ ((visibility ("hidden"))) и / или __attribute__ ((weak))

И код, входящий в *.so общих объектов, должен быть скомпилирован с -fPIC

3 голосов
/ 05 ноября 2011

Во-первых, как указал Basile, вы должны добавить флаг -fPIC при сборке lib{1,2}.a.

Во-вторых, вы получите все 1.o, связанные, потому что это как работают линкеры UNIX .

Самое простое решение (намного более простое, чем использование -flto) - включить сборщик мусора компоновщика путем добавления -Wl,--gc-sections к libFoo.so линии связи и построить lib{1,2}.a с помощью -ffunction-sections -fdata-sections,Это эффективно превратит каждую функцию в отдельную «книгу».

3 голосов
/ 05 ноября 2011

Я считаю, что не используя -fPIC в *.so, они содержат большое количество инструкций по перемещению, обработанных ld.so, так что это первое, что нужно попробовать. -flto следует использовать как при компиляции, так и при компоновке, и увеличить время компиляции. Добавление атрибутов должно быть сделано функция за функцией, и это займет много времени у вашего разработчика (потому что вам нужно выбрать, какие функции нуждаются в них). Если код действительно большой (например, более 100KLOC исходного кода), вы можете подумать о кодировании плагина GCC или, предпочтительно, расширения GCC MELT , чтобы настроить компилятор GCC 4.6 для автоматизации таких задач, но это требует некоторых работа (недели, а не часы).

Я являюсь основным автором GEL MELT (и я даже плохо говорю по-русски, если он вам помогает), поэтому я был бы рад помочь вам использовать MELT. Но в вашем случае это имеет смысл только в том случае, если ваша библиотека достаточно велика, чтобы оправдывать работу более недели над настройкой GCC с MELT.

...