2016-03-03 11 views
5

Mam niewielki problem, którego nie jestem pewien.Ostrzeżenie o kompilacji nie jest wyświetlane podczas kompilowania na komputerze lokalnym z ONLY_ACTIVE_ARCH = NIE

W naszych wielu projektach chcielibyśmy zmienić "Traktuj ostrzeżenia jako błędy" (GCC_TREAT_WARNINGS_AS_ERRORS) na YES.

Chcielibyśmy również pozostawić domyślne ustawienie projektu Xcode "Buduj tylko aktywną architekturę" (ONLY_ACTIVE_ARCH) na YES dla debugowania i NO dla wydania.

Ma to jednak jedną WIELKĄ wadę. Kod takie jak ...

NSUInteger bob = 12234; 
NSLog(@"bob %lu", bob); 

powinna przedstawić następujące rodzaje ostrzegawcze (a więc błąd w naszym przypadku):

wartości typu „NSUInteger” nie powinny być wykorzystywane jako argumenty formacie; dodać wyraźnie obsady do „unsigned long” zamiast

jednak gdy deweloperzy budują i testowanie lokalnie oni nie napotykają To ostrzeżenie/błąd ale kiedy zobowiązać się do repozytorium i nasza ciągła integracja przebiega xcodebuild z wiersza poleceń pojawia się ostrzeżenie, a ich kompilacja nie powiedzie się. Jest to oczywiście frustrujące.

Zakładam, że ma to coś wspólnego z różnicą między budową architektury podczas korzystania z Xcode a korzystaniem z xcodebuild z wiersza poleceń.

Wysłałem przykładowy projekt tutaj ...

https://github.com/OliverPearmain/ArchitectureDependantCompileWarning

podaję 2 schematów. Jeśli skompilujesz dla symulatora iPhone 6S przy użyciu "ArchitectureDependantCompileWarning" (który używa konfiguracji kompilacji Debug, a tym samym ONLY_ACTIVE_ARCH==YES), nie otrzymasz ostrzeżenia, a rzeczy będą się dobrze kompilować. Jeśli użyjesz schematu "ArchitectureDependantCompileWarning-FAILS" (który używa konfiguracji wydania wersji, a tym samym ONLY_ACTIVE_ARCH==NO), to napotkasz ostrzeżenie i kompilacja się nie powiedzie.

Chciałbym jakoś zapewnić, że to ostrzeżenie ZAWSZE napotykane podczas budowania symulatora z ONLY_ACTIVE_ARCH==NO. czy to możliwe?

+0

Zakładam, że nie jest to możliwe, ale mogę się mylić. Ostrzeżenie pojawia się, ponieważ 'unsigned int' jest przekazywana, gdy oczekiwany jest' unsigned long'. Więc gdy 'NSUInteger' jest' unsigned long' to wszystko wygląda dobrze. Mogę sobie wyobrazić, że można dopasować proces kompilacji do utworzenia jakiegoś pliku znacznika dla każdej wymaganej architektury na końcu udanej kompilacji, a kontrola wersji odrzuca zatwierdzenie, jeśli pliki znaczników nie są poprawne (cokolwiek to może oznaczać w szczegółach - może plik znacznika jest poprawny, jeśli jest nowszy niż wszystkie pliki źródłowe?). –

+0

Jedynym sposobem, w jaki udało mi się to złapać, jest zawsze budowanie "ogólnego urządzenia iOS" nawet w trybie debugowania, który ma taki sam efekt praktyczny (jak ja to rozumiem) jako ONLY_ACTIVE_ARCH = NO. Ale jeśli masz zamiar to zrobić, równie dobrze możesz zbudować go dla wszystkich łuków nawet w trybie debugowania, co jest oczywiście niewygodne. Być może dostosuj lokalny cel testowy jednostki (który, jak zakładam, deweloperzy działają lokalnie przed zatwierdzeniem), aby zbudować dla wszystkich łuków? – Palpatim

+0

Jako pewna praktyczna rada,% zd wydrukuje NSInteger poprawnie i bez ostrzeżenia na dowolnej architekturze, więc używanie% zd będzie dobrym nawykiem. – gnasher729

Odpowiedz

1

Powodem tego jest zmiana długości słowa po wyemitowaniu 5 sekund. Innymi słowy, iPhone 5s i inne mają procesor 64-bitowy, podczas gdy wszystkie poprzednie iPhony miały 32-bitowy procesor.

Oto faktycznie typedef dla NSUInteger

#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 
typedef long NSInteger; 
typedef unsigned long NSUInteger; 
#else 
typedef int NSInteger; 
typedef unsigned int NSUInteger; 
#endif 

Widać, że na 32-bitowy procesor, NSUInteger jest wyraźnie zdefiniowana jako unsigned int natomiast dla procesorem 64-bitowym, NSUInteger jest wyraźnie broni jako unsigned long .

A więc, patrząc na ten kod ...

NSUInteger bob = 12234; 
NSLog(@"bob %lu", bob); 

Przez 4s, to NSLog ma niedopasowanie od NSUInteger jest wyraźnie zdefiniowana jako unsigned int i format specifier %lu jest unsigned long. To bardzo jawne niedopasowanie jest przyczyną ostrzeżenia dla procesorów 32-bitowych. W przypadku procesora 64-bitowego nie występuje niezgodność, a zatem brak ostrzeżenia.

Sugerowana poprawka w ostrzeżeniu zakłada, że ​​zamierzasz użyć unsigned long. Jednak tutaj jest alternatywne rozwiązanie.

NSUInteger bob = 12234; 
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 
NSLog(@"bob %lu", bob); 
#else 
NSLog(@"bob %u", bob); 
#endif 

Najważniejsze jest to, że to, co staramy się robić to produkować ostrzeżenie niedopasowanie, gdy nie ma rozbieżności, co jest właściwe ani możliwe.

EDIT:

To nie jest przypadek błędu niedopasowania upadającego manifestować jako ostrzeżenie/błędu. Tam dosłownie nie jest niedopasowanie. Jedynym sposobem na pojawienie się tego błędu jest fakt, że w rzeczywistości występuje niezgodność. Wystąpi niezgodność tylko wtedy, gdy budujesz na architekturach, dla których definicja NSUInteger spowodowałaby niezgodność w określonym kodzie, o którym wspomniałeś. Istnieje już standardowy sposób, aby tak się stało: ustaw "Buduj tylko aktywną architekturę" na NIE dla wszystkich twoich schematów.

+0

Dobrze, ale to nie odpowiada na pytanie, jak włączyć ostrzeżenia o długości słowa zawsze na wszystkich platformach. – JAL

+0

Moja bateria klawiatury umarła, a moja odpowiedź została przesłana, zanim skończyłem. Zmieniłem akumulator i skończyłem odpowiedź. –

+0

Naprawdę doceniam, że poświęciłeś czas na udzielenie odpowiedzi na to pytanie, z korzyścią dla innych. Jednak doskonale zdaję sobie sprawę z przyczyn i historii związanych z zachowaniem, które opisałem. To, o co pytam w swoim OP, to sposób na zapewnienie tego błędu dla osób mniej nieświadomych, nawet gdy budują one na niektórych symulatorach. –

Powiązane problemy