Мне нужно сильно оптимизировать размер исполняемого файла ( ARM
разработка), и я заметил, что в моей текущей схеме сборки ( gcc
+ ld
) неиспользуемые символы не удаляются.
Использование arm-strip --strip-unneeded
для результирующих исполняемых файлов / библиотек не меняет выходной размер исполняемого файла (я понятия не имею, почему, возможно, он просто не может) .
Каким будет способ (если он существует) изменить мой строительный конвейер, чтобы неиспользуемые символы были удалены из результирующего файла?
Я бы даже не подумал об этом, но моя текущая встраиваемая среда не очень "мощная" и экономия даже 500K
на 2M
результатах приводит к очень хорошему увеличению производительности загрузки.
Обновить:
К сожалению, текущая gcc
версия, которую я использую, не имеет -dead-strip
опции, и -ffunction-sections... + --gc-sections
for ld
не дает существенной разницы для конечного результата.
Я шокирован тем, что это даже стало проблемой, потому что я был уверен, что это gcc + ld
должно автоматически удалять неиспользуемые символы (зачем им вообще их сохранять?).
boost
библиотеки, полученный.exe
файл будет содержать много неиспользуемых объектных файлов и из-за спецификаций моей текущей встроенной среды выполнения , запуск10mb
приложения занимает гораздо больше времени, чем, например, запуск500k
приложения.Ответы:
Для GCC это выполняется в два этапа:
Сначала скомпилируйте данные, но скажите компилятору разделить код на отдельные разделы в блоке перевода. Это будет сделано для функций, классов и внешних переменных с использованием следующих двух флагов компилятора:
Свяжите единицы перевода вместе с помощью флага оптимизации компоновщика (это заставляет компоновщик отбрасывать разделы, на которые нет ссылок):
Итак, если у вас был один файл с именем test.cpp, в котором были объявлены две функции, но одна из них не использовалась, вы можете опустить неиспользуемый файл с помощью следующей команды gcc (g ++):
(Обратите внимание, что -Os - это дополнительный флаг компилятора, который сообщает GCC об оптимизации по размеру)
источник
mingw
этим не работает статически статическая линковка libstdc ++ и libgcc с флагом-static
. Параметр компоновщика-strip-all
немного помогает, но все же сгенерированный исполняемый файл (или dll) примерно в 4 раза больше, чем то, что сгенерирует Visual Studio. Дело в том, что я не могу контролировать, какlibstdc++
был скомпилирован. Должен бытьld
единственный вариант.Если верить этому потоку , вам необходимо передать
-ffunction-sections
и-fdata-sections
в gcc, который поместит каждую функцию и объект данных в отдельный раздел. Затем вы даете и--gc-sections
GNU ld удалить неиспользуемые разделы.источник
Вы захотите проверить свои документы для вашей версии gcc & ld:
Однако для меня (OS X gcc 4.0.1) я нахожу их для ld
И этот полезный вариант
Также в gcc / g ++ man есть примечание о том, что определенные виды удаления мертвого кода выполняются только в том случае, если при компиляции включена оптимизация.
Хотя эти параметры / условия могут не подходить для вашего компилятора, я предлагаю вам поискать что-то подобное в своих документах.
источник
mingw
.-dead_strip
неgcc
вариант.Привычки программирования тоже могут помочь; например, добавить
static
к функциям, доступ к которым не осуществляется за пределами определенного файла; используйте более короткие имена для символов (может немного помочь, скорее всего, не слишком); использовать поconst char x[]
возможности; ... этот документ , хотя и говорит о динамических общих объектах, может содержать предложения, которые, если им следовать, могут помочь уменьшить конечный размер двоичного вывода (если ваша цель - ELF).источник
.so
в Linux), поэтому имена символов должны быть сохранены, чтобы API, такие какctypes
модуль FFI Python, могли использовать их для поиска символов по имени во время выполнения.Ответ есть
-flto
. Вы должны передать его как на этапах компиляции, так и на этапах связывания, иначе он ничего не сделает.На самом деле он работает очень хорошо - уменьшил размер написанной мной программы микроконтроллера до менее чем 50% от ее предыдущего размера!
К сожалению, это показалось немного глючным - у меня были случаи, когда что-то строилось неправильно. Возможно, это произошло из-за используемой мной системы сборки (QBS; она очень новая), но в любом случае я бы рекомендовал вам включить ее только для вашей окончательной сборки, если это возможно, и тщательно протестировать эту сборку.
источник
-flto
я не понимаю, что она делает за сценой.-flto
что он не компилирует каждый файл в сборку, он компилирует их в LLVM IR, а затем последняя ссылка компилирует их, как если бы они все были в одной единице компиляции. Это означает, что он может удалить неиспользуемые функции и встроенные не-static
единицы, а также, возможно, другие вещи. См. Llvm.org/docs/LinkTimeOptimization.htmlХотя это и не о символах, если идти по размеру - всегда компилировать с
-Os
и-s
флаги.-Os
оптимизирует результирующий код для достижения минимального размера исполняемого файла и-s
удаляет таблицу символов и информацию о перемещении из исполняемого файла.Иногда - если желателен небольшой размер - игра с разными флагами оптимизации может иметь - а может и не иметь - значение. Например, переключение
-ffast-math
и / или-fomit-frame-pointer
временами может сэкономить вам даже десятки байтов.источник
-ffast-math
нанес серьезный ущерб полностью совместимому со стандартами программному коду C ++, поэтому я бы никогда не рекомендовал его.Мне кажется, что ответ Nemo правильный. Если эти инструкции не работают, проблема может быть связана с версией gcc / ld, которую вы используете, в качестве упражнения я скомпилировал пример программы, используя инструкции, подробно описанные здесь.
Затем я скомпилировал код, используя все более агрессивные переключатели удаления мертвого кода:
Эти параметры компиляции и связывания привели к созданию исполняемых файлов размером 8457, 8164 и 6160 байтов, соответственно, наиболее существенный вклад вносит объявление «strip-all». Если вы не можете произвести аналогичные сокращения на своей платформе, возможно, ваша версия gcc не поддерживает эту функцию. Я использую gcc (4.5.2-8ubuntu4), ld (2.21.0.20110327) в Linux Mint 2.6.38-8-generic x86_64
источник
strip --strip-unneeded
работает только с таблицей символов вашего исполняемого файла. На самом деле он не удаляет исполняемый код.Стандартные библиотеки достигают желаемого результата, разделяя все свои функции на отдельные объектные файлы, которые объединяются с помощью
ar
. Если вы затем свяжете полученный архив как библиотеку (т.-l your_library
Е. Дадите опцию ld), тогда ld будет включать только объектные файлы и, следовательно, символы, которые фактически используются.Вы также можете найти некоторые ответы на этот аналогичный вопрос использования.
источник
Я не знаю, поможет ли это в вашем текущем затруднительном положении, поскольку это новая функция, но вы можете указать видимость символов глобально. Передача
-fvisibility=hidden -fvisibility-inlines-hidden
при компиляции может помочь компоновщику впоследствии избавиться от ненужных символов. Если вы создаете исполняемый файл (в отличие от общей библиотеки), делать больше нечего.Дополнительная информация (и подробный подход, например, для библиотек) доступна в вики GCC .
источник
Из руководства GCC 4.2.1, раздел
-fwhole-program
:источник
-flto
.Вы можете использовать двоичный файл удаления в объектном файле (например, исполняемом файле), чтобы удалить из него все символы.
Примечание: он изменяет сам файл и не создает копию.
источник