Связь между компилятором MSVC и опцией компоновщика для свертывания COMDAT
На этот вопрос есть несколько ответов о SO, но мой немного отличается. Прежде чем пометить как дубликат, пожалуйста, сделайте это.
MSVC всегда предоставлял опцию компилятора /Gy для включения одинаковых функций в разделы COMDAT. В то же время компоновщик также предоставляет параметр /OPT:ICF. Правильно ли я понимаю, что эти два варианта должны использоваться совместно? То есть, в то время как первые пакеты функционируют в COMDAT, последний исключает избыточные COMDAT. Это верно?
Если да, то либо мы используем оба, либо выключаем оба?
2 ответа
Ответ от кого-то, кто общался со мной в автономном режиме. Помог мне понять эти варианты намного лучше.
===================================
По сути, это правда. Предположим, мы говорим только на C или C++, но без функций-членов. Без /Gy компилятор создает объектные файлы, которые в некотором смысле неприводимы. Если компоновщик хочет только одну функцию от объекта, он получает их все. Это особенно важно при программировании для библиотек, так что если вы хотите быть добрыми к пользователям библиотеки, вы должны написать свою библиотеку как множество небольших объектных файлов, обычно по одной нестатической функции на объект, чтобы пользователь библиотека не раздувается от необходимости нести код, который фактически никогда не выполняется.
С /Gy компилятор создает объектные файлы с COMDAT. Каждая функция имеет свой собственный COMDAT, который в некоторой степени является мини-объектом. Если компоновщик хочет только одну функцию от объекта, он может выбрать только эту. Переключатель компоновщика /OPT дает вам некоторый контроль над тем, что делает компоновщик с этой избирательностью, но без /Gy выбирать нечего.
Или очень мало. По крайней мере, возможно, что компоновщик мог бы, например, свернуть функции, каждая из которых представляет собой весь код в объектном файле и имеет одинаковый код. Конечно, возможно, что компоновщик может удалить весь объектный файл, который не содержит ничего, на что есть ссылки. В конце концов, он делает это с объектными файлами в библиотеках. Однако на практике это правило гласило: если вы добавляете объектный файл, отличный от COMDAT, в командную строку компоновщика, вы говорите, что хотите это в двоичном файле, даже если на него нет ссылок. Разница между тем, что возможно, и тем, что сделано, как правило, огромна.
Лучше всего придерживаться быстрого ответа. Опции компоновщика выигрывают от возможности отделить функции (и переменные) от каждого объектного файла, но разделение зависит от кода и данных, которые были организованы в COMDAT, что является работой компилятора.
===================================
Как ответил Раймонд Чен в январе 2013 года
Как объяснено в документации для /Gy, связывание на уровне функций позволяет отбрасывать функции во время прохождения "неиспользуемой функции", если вы запрашиваете это через /OPT:REF. Это не меняет фактическую классическую модель для связывания. Название флага вводит в заблуждение. Это не "выполнить связывание на уровне функций". Он просто включает его, сообщая компоновщику, где начинаются и заканчиваются функции. И это не столько связывание на уровне функций, сколько разобщение на уровне функций. -Raymond
(Этот фрагмент может иметь больше смысла в некотором дополнительном контексте: вот посты о классической модели ссылок: 1, 2
Так что в двух словах - да. Если вы активируете один переключатель без другого, заметного воздействия не будет.