Мощь и беспомощность автоматической оптимизации

Удаление неиспользуемых функций


Большинство компиляторов не удаляют неиспользуемые функции из исходного текста, поскольку используют технологию раздельной компиляции, транслируя исходные тексты в объектные модули, собираемые линкером в исполняемый файл, динамическую библиотеку или драйвер.

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

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

Вот потому-то и не рекомендуется держать весь проект в одном файле (особенно если это библиотека). Помещайте в файл только "родственные" функции, _всегда_ используемые в паре и по отдельности не имеющие никакого смысла. Посмотрите как устроена стандартная библиотека языка Си — большинство функций реализованы в "своем" собственном файле, компилируемом в obj, содержащим _только_ эту функцию и ничего сверх нее! Множество таких obj объединяются библиотекарем в один lib-файл, откуда линкер свободно достает любую необходимую функцию, не таща ничего остального! Собственно говоря, именно для этого библиотеками и придумали. Программисты, помещающие реализации всех функций своей библиотеки в один-единственный файл, совершают большую ошибку!

Из всех рассматриваемых компиляторов, только Intel C++ умеет отслеживать неиспользуемые функции, предотвращая их включение в obj (для этого ему необходимо указать ключ–ipo, активирующий режим глобальной оптимизации).



Содержание раздела