Подтвердить что ты не робот

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

  • обнаружение таких вызовов во время сборки или статического анализа

Я уверен, что кое-что пропустил, где-то вдоль линии. Пожалуйста, просветите меня!

С уважением,

Франк

4b9b3361

Ответ 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?