Mac SDK: использование последнего SDK, но обеспечивающее обратную совместимость с более ранней целью развертывания
Как всегда, когда Apple обновляет OS X, последний XCode 4.4 сбрасывает старый (10.6) SDK, и мне нужно использовать 10.7 SDK (или 10.8, я полагаю) и устанавливаю цель развертывания 10.6 для обеспечения совместимости.
Я предпочитаю ссылку на старый SDK, потому что я знаю, что не могу по ошибке вводить вызовы API, которые еще не существуют. Что-то, что я обнаружил, что регулярно занимаюсь, когда я в последний раз пробовал обратный подход.
Что я нахожу, так это то, что я использую функцию завершения кода в XCode, чтобы выбрать "правильный" вызов для простого класса, такого как NSWorkspace, тогда все хорошо работает во время разработки, я забываю об этом и когда я выпускаю новую версию: Кабум! Все приложение взрывается в более ранних версиях OS X во время выполнения; часто в труднодоступных местах: -)
Или, по крайней мере, это была ситуация для меня несколько лет назад.
Конечно, теперь есть способ либо:
-
убедитесь, что вы не вводите вызовы API, которые еще не доступны в вашей целевой среде развертывания, даже если они определены в SDK
-
обнаружение таких вызовов во время сборки или статического анализа
Я уверен, что кое-что пропустил, где-то вдоль линии. Пожалуйста, просветите меня!
С уважением,
Франк
Ответы
Ответ 1
Конечно, теперь есть способ либо:
-
убедитесь, что вы не вводите вызовы API, которые еще не доступны в вашей цели развертывания, даже если они определены в SDK
-
обнаружение таких вызовов во время сборки или статического анализа
Нет, нет. Да, вы должны открыть радар (bugreport.apple.com) против него. Если вам нравится, вы можете обмануть мой: rdar://11985733
Да, единственным жизнеспособным решением, несмотря на рекомендацию Apple, является копирование старых SDK и связь с ними.
Я потратил довольно много времени на общение с командой Xcode именно по этой проблеме на WWDC 2012. Они согласились, что это сломалось. В настоящее время план по его исправлению не существует. Эскалация радара заключается в том, как мы воздействуем на Apple на эти вещи.
Ответ 2
Я обычно копирую SDK из более старых версий в более новый, чтобы компилятор меня сбил, если я использую что-то, что не поддерживается.
Также вы можете просто взглянуть на Quick Help при вызове некоторых методов, о которых вы не уверены, например, на скриншоте вы можете увидеть, что метод launchApplicationAtURL доступен только из 10.6
![enter image description here]()
Ответ 3
У меня была эта неприятная проблема и в iOS. Это на самом деле еще более раздражает на iOS, так как пользователь должен синхронизировать свое устройство с iTunes и включать отправку отчета о сбое до отправки отчета о сбое в отличие от Mac OS X, где вам не нужно все это делать. Недавно мне удалось добавить проверку времени компиляции для проверки API-интерфейсов в отношении старых версий SDK. Сначала я объясню, как я сделал это для iOS, а затем попытаюсь помочь вам адаптировать эту технику для Mac OS X. Я не много программирую для Mac atm, поэтому я могу только реально вести вас в правильном направлении из своего опыта с iOS, но я буду проверять мои предложения позже сегодня, как только вернусь с работы и даю конкретный ответ.
Итак, вот что я сделал для iOS:
Мне сначала пришлось получить более старый Симулятор SDK, который я хотел получить. Я мог бы легко получить это, загрузив старые версии Xcode 3 (не 4), которые включали необходимый SDK.
Затем мне пришлось установить SDK. Это было не слишком сложно, поэтому я не буду здесь объяснять многое. Но SDK хранятся в папке Packages
. Эта папка хорошо видна в более ранних версиях Xcode 3, но скрыта в более поздних версиях. Вы можете легко открыть его в любом случае через терминал. Кроме того, после изменения Xcode 4.3, где папка Developer
перемещена в Xcode.app, поэтому мне пришлось установить SDK в папку tmp и переместить SDK в Xcode.app самостоятельно. Затем мне нужно было перезапустить Xcode, если бы я его открывал.
После этого я продублировал конфигурацию debug
в вашем проекте и назвал ее, в моем случае, что-то вроде iOS 4.3 API Check
или что-то в этом роде - не имеет большого значения. Затем я изменил базовый SDK этой новой конфигурации на старый SDK, который я установил. Установленный SDK не был указан, поэтому мне пришлось выбрать other
и ввести, опять же в моем случае, iphonesimulator4.3
.
Наконец, когда мне нужно было проверить старые версии SDK, я изменил конфигурацию для Run <appname>.app
в моей схеме проекта на мою конфигурацию iOS 4.3 API Check
. И вот мы идем, проверка времени компиляции против iOS 4.3.
Что касается Mac OS X, я уверен, что вы можете достичь той же цели с помощью этого же метода. Для Mac SDK нет симуляторов, поэтому я думаю, что для этого будет работать обычный SDK. Что касается получения старого SDK, если у вас установлен Xcode 4.2 (после того, как Xcode 4.3 изменил его, так что папка Developer
находится в Xcode.app), тогда вы должны найти 10.6 SDK. Если вы этого не сделаете, я бы предположил, что Apple имеет аналогичную вещь для iOS, где загрузка SDK доступна в Dev Center или где-то в Интернете...
Что касается установки базового SDK, если он не указан, я думаю, что это имя MacOSX10.6
или любая другая версия, которую вы используете.
Все остальное должно быть одинаковым, но, как упоминалось ранее, я проведу этот метод позже сегодня и отредактирую свой ответ, чтобы дать более конкретный ответ, но я бы предположил, что этот метод будет работать для Mac SDK.
Ответ 4
Я проверяю свой код, взломав Availability.h, чтобы заставить компилятор помечать слабые символы как предупреждения/ошибки. В моем текущем (Xcode 5/llvm) воплощении я использую код ниже. Он предупреждает, когда я использую символ, введенный в iOS 6.0 или новее. Я думаю, что это довольно понятно. Кажется, что макросы нуждаются в обновлении при каждом обновлении SDK, поэтому пройдите осторожно. О, и у вас также есть предупреждения об утомлении, поэтому я использую это только один раз, чтобы дважды проверить свой условный код.
#undef __NSi_6_0
#define __NSi_6_0 deprecated=1.0
#undef __NSi_6_1
#define __NSi_6_1 deprecated=1.0
#undef __NSi_7_0
#define __NSi_7_0 deprecated=1.0
#undef __NSd_6_0
#define __NSd_6_0
#undef __NSd_6_1
#define __NSd_6_1
#undef __NSd_7_0
#define __NSd_7_0
См. также http://iphone.m20.nl/wp/2013/10/xcode-5-and-flagging-weak-linked-unavailable-symbols-from-a-newer-sdk/
Ответ 5
Я также предположил, что компилятор предупредит меня о "слишком новом" использовании API для версии ОС для развертывания. но оказалось, что компилятор не предупреждает вас об этом по умолчанию. одна из причин может заключаться в том, что вы все равно можете использовать новый API, проверяя наличие во время исполнения "responsesToSelector:", например, на более новой версии ОС, даже если целевая версия развертывания была старше. вам нужно добавить параметр компилятора -Wpartial-availability, который доступен на Xcode 7.3+ (для подтверждения), чтобы получить "предупреждение:" что-то "является частичным: введено в macOS 10. x".
на macOS 10.12.3 с Xcode 8.2.1:
$ cat foo.m
#include <Foundation/Foundation.h>
BOOL foo()
{
return [@"foo" containsString:@"bar"];
}
$ cc -mmacosx-version-min=10.9 -Wpartial-availability foo.m -c -o foo.o
foo.m:5:20: warning: 'containsString:' is partial: introduced in macOS 10.10 [-Wpartial-availability]
return [@"foo" containsString:@"bar"];
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSString.h:132:1: note:
'containsString:' has been explicitly marked partial here
- (BOOL)containsString:(NSString *)str NS_AVAILABLE(10_10, 8_0);
^
foo.m:5:20: note: explicitly redeclare 'containsString:' to silence this warning
return [@"foo" containsString:@"bar"];
^
1 warning generated.
см. также: Есть ли способ для XCode предупреждать о новых вызовах API?