Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile Warning Not Encountered When Compiling on Local Machine with ONLY_ACTIVE_ARCH = NO

Tags:

xcode

ios

I have a slight problem that I'm not sure how to solve.

In our multiple projects we would like to change "Treat Warnings as Errors" (GCC_TREAT_WARNINGS_AS_ERRORS) to YES.

We would also like to leave the Xcode default project setting of "Build Active Architecture Only" (ONLY_ACTIVE_ARCH) to YES for Debug and NO for Release.

This has one MAJOR drawback however. Code such as...

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

Should produce the following type of warning (and therefore error in our case):

Values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead

HOWEVER when developers are building and testing locally they DO NOT ENCOUNTER this warning/error but when they commit to our repository and our continous integration runs xcodebuild from the command line the warning is encountered and their build fails. This is obviously rather frustrating.

I assume this has something to do with the difference between what architecture's are being build when using Xcode and when using xcodebuild from the command line.

I have uploaded a sample project here...

https://github.com/OliverPearmain/ArchitectureDependantCompileWarning

I've included 2 schemes. If you compile for an iPhone 6S simulator using the "ArchitectureDependantCompileWarning" (which uses the Debug build configuration and thus ONLY_ACTIVE_ARCH==YES) you get no warning and things compile fine. If you use the "ArchitectureDependantCompileWarning-FAILS" scheme (which uses the Release build configuration and thus ONLY_ACTIVE_ARCH==NO) then the warning is encountered and compilation fails.

I would like somehow to ensure that this warning is ALWAYS encountered when building for the simulator with ONLY_ACTIVE_ARCH==NO. Is this possible?

like image 777
Oliver Pearmain Avatar asked Nov 08 '22 19:11

Oliver Pearmain


1 Answers

The reason for this is the change in word length when the 5s came out. In other words, the 5s and greater iPhones have a 64-bit processor, while all previous iPhones had a 32-bit processor.

Here's the actually typedefs for 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

You can see that for a 32-bit processor, NSUInteger is explicitly defined as a unsigned int whereas for a 64-bit processor, NSUInteger is explicitly defends as a unsigned long.

So, looking at this code...

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

For a 4s, this NSLog has a mismatch since NSUInteger is explicitly defined as a unsigned int and the format specifier %lu is a unsigned long. This very explicit mismatch is the reason that the warning exists for 32-bit processors. For a 64-bit processor there is no mismatch and thus no warning.

The suggested fix in the warning assumes that you intended to use the unsigned long. However, here is an alternative solution.

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

The bottom line is that what you are trying to do is to produce a mismatch warning when there is no mismatch, which is neither appropriate nor possible.

EDIT:

This isn't a case of a mismatch error failing to manifest as a warning/error. There literally is not a mismatch. The only way for this error to show up is for there to actually be a mismatch. There will only be a mismatch if you are building against architectures for which the definition of NSUInteger would create a mismatch in the specific code that you mentioned. There is already a standard way to make this happen: set "Build Active Architecture Only" to NO for all of your schemes.

like image 176
Jeff Wolski Avatar answered Nov 14 '22 22:11

Jeff Wolski