Apple привносит в мир много нового. Удачные нововведения приживаются, а неудачные понемногу отмирают. Кстати неудачных решений оказывается не так уж и мало и я считаю это абсолютно нормальным. В конце концов мы уважаем Apple именно за готовность идти на риск и экспериментировать:)
Все это в полной мере относится и к средствам разработки. В прошлой заметке я писал о нестандартном алгоритме поиске заголовочных файлов в XCode. Сегодня я хочу подробнее остановиться на так называемых SDK — в XCode этим термином называют комплект библиотек и заголовочных файлов под определенную версию iOS или Mac OS. Зачем нужны SDK в понимании xCode?
- Каждый SDK лежит в своей отдельной папке и безболезненно сосуществует в другими SDK — это позволяет вести разработку под разные ОС на одном компьютере. Раньше SDK лежали в /Developer/SDKs; к четвертой серии xCode они переехали внутрь xCode.app.
- Настроить проект под определенную версию OS — плевое дело. Достаточно указать SDK в настройках проекта.
Технически, это реализовано следующим образом. Apple добавила в компилятор ключ --sysroot. Значение sysroot дописывается как префикс в пути для поиска заголочных файлов и библиотек. Этой модификации подвержены как стандартные пути (ex: /usr/include), так и пользовательские пути, добавленные ключами -I и -L.
Работает это следующим образом. Допустим в настройках XCode выбран SDK macosx10.6. XCode передает компилятору ключ --sysroot=/Developer/SDKs/MacOSX10.6.sdk. В результате /usr/include превращается в /Developer/SDKs/MacOSX10.6.sdk/usr/include. То же самое происходит с путями для поиска библиотек и фреймворков. Как легко догадаться, внутри SDK есть usr/include и usr/lib с соответствующим содержимым.
Теперь самое время перейти к загадочной опции «Additional SDKs» в XCode.
Зачем это нужно? Допустим вы — компания, выпускающая middleware. Вы оформляете свои библиотеки и фреймворки в виде XCode SDK. Чтобы использовать ваш middleware в проекте, достаточно указать полный путь до вашего SDK в разделе Additional SDKs в настройках XCode. Заголовочные файлы и библиотеки становятся доступны автоматически.
Кстати, можно использовать много дополнительных SDK одновременно.
К сожалению, как это часто бывает, красивую идею губит реализация.
Для поддержки Additional SDKs, XCode приходится проделывать много дополнительной работы, что проявляется тормозами при сборке проекта. Для каждого используемого сочетания базового и дополнительных SDK, во временной папке создается объединенное дерево файлов из всех SDK и путь до этой папки передается в --sysroot. Вместо честного копирования файлов используются симлинки, но все равно процесс не быстрый.
Для желающих экспериментировать с Additional SDK, я подготовил проект на github. Обратите внимание на SDKSettings.plist. Этот файл необходим, чтобы XCode «признал» SDK.
В своих проектах я не использую Additional SDK и вместо этого вручную настраиваю пути для поиска хидеров, библиотек и фреймворков.
Бонус: SDK и версии ОС
Для каждой очередной версии ОС выходит новый SDK. Однако это не значит, что проект, скомпилированный с macosx10.8 SDK будет работать только на Mac OS X 10.8 и не запустится на более ранних ОС.
Версия SDK 10.8 означает, что SDK включает в себя все API которые доступны в Mac OS X 10.8 и более ранних системах (за исключением deprecated API). Если проект не использует возможностей, которые отсутствуют в OS X 10.6, тогда проект будет без проблем работать на 10.6.
Более интересная ситуация, когда мы задействуем новые фичи, если они доступны, а для старых систем используем альтернативную реализацию. Для этого используется weak linking. «Слабо прилинкована» может быть как целая динамическая библиотека, так и отдельная функция из динамической библиотеки. Если при запуске не удается найти слабо прилинкованную библиотеку, программа продолжит выполняться как ни в чем не бывало, а линкер подставит NULL в качестве адреса отсутствующих функций. Разумеется, если вызвать функцию, которой нет, программа упадет.
Поэтому перед вызовом мы сравниваем адрес функции с NULL, и если функция не доступна, используем альтернативную реализацию.
Минимальная поддерживаемая версия Mac OS указывается в настройках проекта (MACOSX_DEPLOYMENT_TARGET). Все более поздние API автоматически помечаются для weak linking. Сделано это с помощью макросов, которые объявлены в /usr/include/Availability.h.
Автор: mejedi