Как остановить привязку библиотеки, когда функция, которая от нее зависит, не вызывается?

сначала я создам небольшую программу:

#include <gmpxx.h>

void function() {
    //mpf_class num;
    return;
}

int main() {}

Обратите внимание, что я включаю стороннюю библиотеку, но не использую ее содержимое.
Я приступаю к компиляции программы:

$ g++ main.cpp -Wl,--as-needed -lgmp -lgmpxx
$ readelf -d a.out | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

Несмотря на то, что я подключил к этой программе две дополнительные библиотеки, я передал флаг --as-nedded, который обнаружил, что эти две библиотеки на самом деле не нужны во время выполнения. Таким образом, readelf показывает нам, что на самом деле они не были связаны.

(gcc на самом деле связывает дополнительные библиотеки C и C++ с вашим двоичным файлом помимо libc, но флаг --as-needed обнаружил, что они тоже не нужны.)

Здесь я ссылаюсь на код библиотеки, но на самом деле он мне не нужен:

#include <gmpxx.h>

void function() {
    mpf_class num;
    return;
}

int main() {}

$ g++ main.cpp -Wl,--as-needed -lgmp -lgmpxx
$ readelf -d a.out | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libgmp.so.10]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

Вопрос: я исходил из того, что неиспользуемые функции выбрасываются и не становятся частью двоичного кода. Предполагая, что компилятор понимает, что код «функции» не нужен, и может его отбросить, почему он также не может понять, что связывание gmp также больше не нужно?

Интересно, что запуск команды с полной оптимизацией,

$ g++ -Ofast main.cpp -Wl,--as-needed -lgmp -lgmpxx
$ readelf -d a.out | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libgmp.so.10]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

приводит к тому, что некоторые из неявно связанных библиотек gcc будут исключены, когда ранее неоптимизированные были сохранены из-за включения gmp.

Вопрос. Способен ли компилятор исключить эту стороннюю библиотеку, учитывая, что код библиотеки никогда не будет выполнен?


person Trevor Hickey    schedule 24.03.2014    source источник


Ответы (1)


Если компилятор абсолютно уверен в том, что какой-то код никогда не будет использоваться, его можно просто выбросить. Если это так, вызов не будет отображаться в объекте, а библиотека пропущена.

В примере функции, которая не вызывается, по умолчанию она имеет значение extern, поэтому компилятор не может знать, вызвана ли она из другого файла, и не может избавиться от нее. Но большинство компиляторов просто компилируют функцию за раз и проводят небольшой анализ внутри функции. Поэтому я сомневаюсь, что какой-либо текущий компилятор скомпилирует этот файл (с static void function()), заметит, что функция не вызывается, и удалит его. Возможно, умный компоновщик (который выполняет анализ всей программы) сделает это, но я не рассматривал это слишком внимательно.

person vonbrand    schedule 24.03.2014
comment
Хорошо подмечено. Я считаю, что соглашение теперь состоит в том, чтобы обернуть их в анонимные пространства имен вместо использования статического. Оба будут работать одинаково, и это действительно решение. - person Trevor Hickey; 24.03.2014