Почему для связывания категорий в статических библиотеках необходим флаг компоновщика -ObjC? (LLVM)

Относительно этого технического Q & A от Apple: http://developer.apple.com/library/mac/#qa/qa1490/_index.html

Я думаю, что компилятор мог отмечать вызовы методам, определенным в категориях во время компиляции (он знает, что они были определены в категории, а не в основном классе, потому что прототип был в разделе @interface Class (Category)), чтобы он мог построить таблицу в объектных файлах "методы внешней категории". Затем компоновщик, выполнив обычную привязку, должен иметь возможность конкатенации/слияния и обработки таблиц "внешних категорий" со всех объектов и поиска соответствующих символов в соответствующих категориях классов из всех связанных фреймворков/библиотек/объектов, затем могут вытащить те, которые еще не были "в" цели.

Должно быть, что-то мне не хватает, но что это? Почему это невозможно?

Ответ 1

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

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

Однако, когда вы вызываете метод в категории, нет специальной ссылки на символ из-за динамизма Objective-C.

Флаг -ObjC указывает компоновщику, что из-за этого он должен захватить все категории из статической библиотеки и переместить их в основной двоичный файл.


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

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

  • Objective-C является полностью динамическим. Когда вы говорите [(id)foo bar];, единственным требованием является то, что bar определяется где-то ранее. Неважно, действительно ли оно реализовано вообще (до тех пор, пока не будет выполнено).

  • Категории не должны иметь соответствующие @implementations; категорию можно использовать, чтобы объявить, что методы могут существовать и, фактически, до добавления @optional в @protocol, было принято использовать категорию на NSObject (ewwwwww) без @implementation, чтобы сказать: "Эй, этот необязательный метод может существовать во время выполнения".

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

Конечный результат?

У компоновщика недостаточно информации для разрешения зависимостей.