Почему флаг компоновщика -ObjC необходим для связывания категорий в статических библиотеках? (LLVM)
Относительно этого технического Q&A от Apple: http://developer.apple.com/library/mac/
Я думаю, что компилятор может пометить вызовы методов, определенных в категориях, во время компиляции (он знает, что они были определены в категории, а не в основном классе, потому что прототип был в @interface Class (Category)
section) - чтобы можно было построить таблицу в объектных файлах "методов внешней категории". Затем компоновщик, выполнив обычное связывание, должен иметь возможность объединять / объединять и обрабатывать таблицы "методов внешних категорий" из всех объектов и искать подходящие символы в соответствующих категориях классов из всех связанных каркасов / библиотек / объектов, затем он может вытянуть те, которые еще не были "в" цели.
Там должно быть что-то, что я скучаю, но что это? Почему это невозможно?
1 ответ
Линкер обрабатывает статические библиотеки как большую старую коллекцию случайных частей, из которых он будет рисовать отдельные части для выполнения любых запросов символов от остальной части блока ссылок.
Т.е. если основная программа вызывает _foo
а также _foo
появляется только в статической библиотеке, затем _foo
, вместе с любыми зависимыми символами, будет перетащен в.
Однако при вызове метода в категории отсутствует конкретная ссылка на символ из-за динамизма Objective-C.
-ObjC
flag сообщает компоновщику, что из-за этого он должен извлечь все категории из статической библиотеки и поместить их в основной двоичный файл.
Это немного сбивает с толку, и предполагается, что компилятор должен быть умнее в этом (и, конечно, он должен оказывать помощь на уровне инструментов разработчика). Важно помнить несколько вещей:
Все, что объявлено в заголовочном файле, в значительной степени теряется к тому времени, когда компоновщик переворачивается. Символы создаются единицами компиляции, а не заголовочными файлами. Заголовочные файлы в значительной степени генерируют обещание, что символ будет конкретно создан позднее или выполнен по ссылке, но не может создать символ сам по себе (или иначе каждый модуль компиляции - каждый.o - в итоге получит копию символ и веселье начнутся во время соединения).
Objective-C полностью динамичен. Когда ты сказал
[(id)foo bar];
, единственным требованием является то, чтоbar
определяется где-то ранее. Не имеет значения, реализован ли он вообще (во всяком случае, до времени выполнения).Категории не должны иметь соответствующие @implementations; категория может использоваться, чтобы объявить, что методы могут существовать, и, фактически, до добавления
@optional
в@protocol
было принято использовать категорию наNSObject
(Ewwwwww) без@implementation
сказать "Эй, этот необязательный метод может существовать во время выполнения".Компиляция и компоновка - это совершенно разные процессы. Компиляция - это расширение кода и превращение его в библиотеки исполняемых байтов. Связывание - это все, что нужно для того, чтобы взять эти библиотеки и объединить их во что-то, что действительно можно запустить, включая разрешение всех зависимостей между библиотеками. Компилятор на самом деле не знает, как что-то может быть связано, и компоновщик не имеет никакой информации о том, где вещи (которые не давали жестких символов) могли быть определены.
Конечный результат?
У компоновщика недостаточно информации для разрешения зависимостей.