3

I have an application to which I added some new functionality. This was tested in Debug mode, but when compiling for Release introduced a number of errors.

A bit of detective work showed these were caused by calls to convert a point between the NSView class and the CALayer class e.g.

- (NSPoint)convertPoint:(NSPoint)aPoint fromView:(NSView *)aView
- (CGPoint)convertPoint:(CGPoint)aPoint toLayer:(CALayer *)layer
error: incompatible type for argument 1 of 'convertPoint:toLayer:'

Attempts to correct this resulted in exchanging one set of errors for another, and I discovered the problem in NSPoint:-

Prior to Mac OS X v10.5 the coordinates were represented by float values rather than CGFloat values. When building for 64 bit systems, or building 32 bit like 64 bit, NSPoint is typedef’d to CGPoint.

I had been compiling for the default "Standard (32/64-bit Intel)" Architecture changing this to "64-bit Intel" resolved the problem. I could resolve the problem by including explicit conversions between NSPoint and CGPoint, although this is clumsy (and unnecessary in 64-bit).

I tried to discover what "Standard (32/64-bit Intel)" Architecture actually means, but drew a blank. The only thing I could find was this:-

A list of the architectures for which the product will be built. This is usually set to a predefined build setting provided by the platform. If more than one architecture is specified, a universal binary will be produced.

Poking around in Application Packages did not seem to show much difference between Standard (32/64-bit Intel) and 64-bit Intel.

Can anyone shed any light on this, and is there any point in trying to produce "Standard (32/64-bit Intel)" in an Application targeting 10.6 or later?

Milliways
  • 1,265
  • 1
  • 12
  • 26

1 Answers1

6

A bit of detective work showed these were caused by calls to convert a point between the NSView class and the CALayer class e.g.

- (NSPoint)convertPoint:(NSPoint)aPoint fromView:(NSView *)aView
- (CGPoint)convertPoint:(CGPoint)aPoint toLayer:(CALayer *)layer
error: incompatible type for argument 1 of 'convertPoint:toLayer:'

Attempts to correct this resulted in exchanging one set of errors for another, and I discovered the problem in NSPoint:-

Prior to Mac OS X v10.5 the coordinates were represented by float values rather than CGFloat values. When building for 64 bit systems, or building 32 bit like 64 bit, NSPoint is typedef’d to CGPoint.

Correct. When building for 32-bit, NSPoint is a separate structure that isn't compatible with CGPoint according to C, although they do actually hold the same values in the same format.

The “building 32 bit like 64 bit” part is a macro you can define that makes that and a few other things get defined the same way as in 64-bit builds. The macro's name is NS_BUILD_32_LIKE_64; define it to 1 to turn that feature on. I recommend it.

I had been compiling for the default "Standard (32/64-bit Intel)" Architecture changing this to "64-bit Intel" resolved the problem.
I could resolve the problem by including explicit conversions between NSPoint and CGPoint, although this is clumsy (and unnecessary in 64-bit).

Yup. These are the two other solutions.

I tried to discover what "Standard (32/64-bit Intel)" Architecture actually means, but drew a blank. The only thing I could find was this:-

A list of the architectures for which the product will be built. This is usually set to a predefined build setting provided by the platform. If more than one architecture is specified, a universal binary will be produced.

That's the definition of the Architectures (ARCHS) setting generally, not that specific value.

Poking around in Application Packages did not seem to show much difference between Standard (32/64-bit Intel) and 64-bit Intel.

Can anyone shed any light on this, and is there any point in trying to produce "Standard (32/64-bit Intel)" in an Application targeting 10.6 or later?

A few things changed in 64-bit Mac OS X, including:

  • Some new features appeared in the language, such as non-fragile instance variables. This lets you add instance variables at runtime and, more usefully, conceal instance variable declarations within your implementation file instead of publicizing them within the header.
  • The definitions of the geometric structures changed. This is what you ran into. You can now freely pass an NSPoint where a CGPoint is expected and vice versa, and the same for the other structures.
  • Similarly, many methods that previously took or returned a number of points as a float now take or return it as CGFloat, which may be defined as double.
  • NSUInteger is defined as unsigned long, not unsigned int, and likewise for NSInteger.

Some of these things are flat-out not compatible with 32-bit OS X, such as the language changes; it's possible to write a program that you simply cannot build for 32-bit.

Other breakages are softer. As noted above, some definitions changed in 64-bit, but the older definitions remain the default in 32-bit for compatibility, but you can switch them with the aforementioned macro.

So why does this matter?

Mac models introduced before late 2006/early 2007 only supported the 32-bit Intel architecture (IA32, a.k.a. i386). Around early 2007, Apple started introducing Macs that supported the 64-bit architecture (x86-64) as well.

Mac OS X running on 64-bit hardware can (so far) always run 32-bit software, but Mac OS X running on 32-bit hardware can only run 32-bit software. Mac OS X itself was built for both until Lion; now, it requires a 64-bit Mac.

So the only reason to build for 32-bit is that you want to support five-year-old hardware (e.g., if that's what you have). If you'd rather get the newer language features and don't mind abandoning the customers who have five-year-old Macs, then go 64-bit-only and don't look back.

That's assuming, of course, that you don't have any hand-written i386 assembly code or code that uses no-longer-supported functions in Carbon. If you do, then that's another potential incentive to stick with 32-bit. Just be aware that support for 32-bit programs in Mac OS X may go away someday.

Apple has relevant documentation:

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
  • Thanks for the informative reply. I did try #define NS_BUILD_32_LIKE_64 1, but this did not seem to help, but I am more comfortable sticking to 64-bit. I had read the documents, but they seemed to discourage 64-bit – Milliways Dec 04 '11 at 07:09
  • 2
    @Milliways: Discourage 64-bit? It should be the other way: 32-bit support is discouraged for modern code. – Peter Hosey Dec 04 '11 at 08:04