Удаление из библиотеки С++ ненужного кода для приложения

У меня есть приложение, зависящее от многих библиотек. Я собираю все из исходников на машине с Ubuntu. Я хочу удалить любую функцию/класс, которая не требуется приложению. Есть ли какой-нибудь инструмент, чтобы помочь с этим?

P.S. Я хочу удалить из библиотеки исходный код, а не только символы из объектных файлов.


person Ashok Vishnoi    schedule 24.05.2018    source источник
comment
Возможно, см. здесь.   -  person Paul Sanders    schedule 24.05.2018
comment
Вам не нужно изменять исходный код, чтобы удалить неиспользуемые функции, методы или классы из вашего двоичного файла. Мой ответ предназначен для того, чтобы показать вам, как это сделать с помощью простого переключателя компилятора. Пожалуйста, дайте мне знать, если что-то нуждается в разъяснении.   -  person Paul Sanders    schedule 25.05.2018
comment
Я понимаю вашу точку зрения и ценю вашу помощь. Однако я хотел оптимизировать библиотеку с открытым исходным кодом, но мне не требуется полная функциональность библиотеки, поэтому, если я смогу удалить исходный код, его будет легче оптимизировать.   -  person Ashok Vishnoi    schedule 25.05.2018
comment
Почему будет легче оптимизировать? Чего я не понимаю, так это почему вы думаете, что удаление кода из исходных файлов даст результаты, отличные от того, когда компилятор и компоновщик сделают это за вас.   -  person Paul Sanders    schedule 25.05.2018
comment
Оригинальный исходный код очень большой. (~ 200 000 строк). Мне нужно около 20к LOC.   -  person Ashok Vishnoi    schedule 28.05.2018
comment
Что такое ЛОК? И если вы имеете в виду размер вашего двоичного файла, попробуйте этот флаг. Он должен удалить любой недостижимый код, и это может быть все, что вам нужно. Взламывать источник библиотеки звучит как плохая идея — вы почти наверняка что-нибудь сломаете.   -  person Paul Sanders    schedule 28.05.2018
comment
LOC-›Строки кода Я хочу удалить неиспользуемый код, оптимизировать код и поддерживать его. Поддержание всей библиотеки слишком много для небольшой функциональности.   -  person Ashok Vishnoi    schedule 28.05.2018
comment
О, ладно, я не знал, что ты подумываешь о такой радикальной операции, извини. Я думаю, что я бы просто использовал приличную IDE. У меня есть много инструментов «Intellisense», которые помогут в этом.   -  person Paul Sanders    schedule 28.05.2018


Ответы (3)


Именно для этого и создана стандартная утилита strip.

person Chugaister    schedule 24.05.2018
comment
Это просто отбрасывает символы. OP (и действительно я) хочу опустить код из окончательного исполняемого файла, который никогда не вызывается. - person Paul Sanders; 24.05.2018

Теперь я немного изучил это в контексте моего собственного проекта и решил, что это стоит полного ответа, а не просто комментария. Этот ответ основан на наборе инструментов Apple для macOS (который использует clang, а не gcc), но я думаю, что в обоих случаях все работает одинаково.

Ключом к этому является включение «оптимизации времени компоновки» при создании библиотек и исполняемых файлов. Механика этого на самом деле очень проста — просто передайте -flto в gcc и ld в командной строке. Это имеет два эффекта:

  • Код (функции/методы) в объектных файлах или архивах, который никогда не вызывается, исключается из окончательного исполняемого файла.
  • Компоновщик выполняет оптимизацию, которую может выполнить компилятор (например, встраивание функций), но со знаниями, которые выходят за границы единиц компиляции.

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

С другой стороны, это уменьшило размер моего окончательного исполняемого файла примерно на 5%, чему я очень рад. YMMV.

С другой стороны, размер моих объектных файлов увеличился примерно вдвое, а время компоновки иногда резко возросло (примерно в 100 раз). Потом, если я перелинковался, это было намного быстрее. Однако такое поведение может быть особенностью цепочки инструментов Apple. Возможно, он прячет какие-то промежуточные сборки где-то по первой ссылке. В любом случае, если вы включите эту опцию только для выпускных сборок, это не должно быть серьезной проблемой.

Более подробная информация о полном наборе параметров командной строки gcc, управляющих оптимизацией, приведена здесь: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html. Найдите на этой странице flto, чтобы сузить область поиска.

Чтобы заглянуть за кулисы, см.: https://gcc.gnu.org/onlinedocs/gccint/LTO-Overview.html

Изменить:

Немного больше информации о времени ссылки. Компоновщик Apple создает несколько огромных файлов в каталоге с именем LTOCache при создании ссылки. Я не видел их до сегодняшнего дня, поэтому они выглядят как промежуточные сборки, которые ускоряют связывание во второй раз. Что касается того, что моя начальная ссылка такая медленная, это может быть частично связано с тем, что в моем случае они созданы на сервере SMB. Но опять же, процессор был максимально загружен, так что, возможно, нет.

person Paul Sanders    schedule 24.05.2018

Хорошо, теперь, когда я лучше понимаю требования ОП, у меня есть другой ответ на этот вопрос, который, я думаю, может лучше соответствовать его потребностям. Я думаю, что решить эту проблему можно с помощью инструмента покрытия кода. В конце концов, проблема заключается в том, чтобы определить то, от чего можно безопасно избавиться. На самом деле снять его несложно.

В мою IDE (Visual Studio) встроен один из них, но я думаю, что OP использует gcc, поэтому первый порт захода выглядит как gcov. Существует ряд коммерческих вариантов, но они дорогие. Также есть потенциально полезная запись здесь.

Еще одна вещь, которая вам нужна, конечно, это программа, которая проверяет все части библиотеки, которые вы хотите сохранить, чтобы предоставить вам отчет о покрытии для работы, но похоже, что у OP это уже есть. Хорошая IDE также поможет, поскольку она значительно упрощает навигацию по коду. Ключевыми функциями Visual Studio я считаю Перейти к определению, а также быстрое и простое создание закладок.

person Paul Sanders    schedule 28.05.2018
comment
Спасибо. Это помогло мне уменьшить размер. Однако я должен удалить часть кода, который не был выполнен, и собрать код, чтобы проверить, нет ли какой-либо ошибки компиляции, поскольку инструменты покрытия предоставляют только информацию о времени выполнения. Итак, если функция была вызвана из else части оператора if..else, а во время выполнения была выполнена if часть. Затем, несмотря на то, что функция отображается как невыполненная в отчете о покрытии, ее невозможно удалить. - person Ashok Vishnoi; 03.06.2018
comment
Да, это имеет смысл. Может быть, вы можете пойти дальше и также удалить часть else (вы сказали, что хотите избавиться от как можно большего количества исходных строк). - person Paul Sanders; 03.06.2018