Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect C++ compiler with macro in Xcode?

I'm mixing Objective-C (*.m) and Objective-C++ (*.mm) source files in an iOS project. When I import a C++ header file in a *.m file how can I exclude the C++-specific code in the header file? I want to use a compiler macro, something like:

// SomeClass.h - a file I want to import in C++ and Objectice-C classes

#if CPLUSPLUS
#import "CPlusPlusLibrary.h"
#endif 

@interface SomeClass : BaseClass
{

#if CPLUSPLUS
  CPlusPlusClass* variable;
#endif    

}

@end
like image 780
Felix Avatar asked Apr 15 '11 14:04

Felix


1 Answers

That would fail badly because an instance of SomeClass would have a different size and layout depending on whether it's compiled from a .m or a .mm file.

Here's what I would do (with added code to make it includable from .c and .cp as well):

#ifdef __OBJC__
    #import <Foundation/Foundation.h>
#endif

#ifdef __cplusplus
    #include "CPlusPlusLibrary.h"
#endif

#ifdef __cplusplus
    class CPlusPlusClass;
#else
    typedef struct CPlusPlusClass CPlusPlusClass;
#endif

#ifdef __OBJC__
    @class AnotherObjCClass;
    @interface SomeObjCClass : NSObject
    {
        CPlusPlusClass* _variableCPP;
        AnotherObjCClass* _variableObjC;
    }
#else
    typedef struct ObjC_AnotherObjCClass AnotherObjCClass;
    typedef struct ObjC_SomeClass SomeObjCClass;
#endif

#ifdef __cplusplus
extern "C" { // Callable from C
#endif   
    void CFunctionTakingCPlusPlusClass(CPlusPlusClass* foo);
    void CFunctionTakingSomeObjCClass(SomeObjCClass* foo);      
#ifdef __cplusplus
}
#endif

Note that when compiling a .mm file, both __OBJC__ and __cplusplus are defined. #include and #import are roughly equivalent in Objective-C (a superset of C-99), but you must use #include for anything visible to C/C++.

Remember that in C, a struct foo* with foo never defined (pointer to anonymous structure) is a perfectly valid type, so what this does is typedef "other language classes" as anonymous structs which you can pass around by pointer w/o looking at the contents.

I'll leave as an exercise how this interacts with ARC for ObjC instance variables. (There might be dragons and/or you may need __unsafe_unretained)

IIRC, if you use the same name for the struct as the C++ class, the debugger will show the right information if it has it available. I'm not sure if that's safe for Obj-C so I used a different name.

Also, try to avoid including the C++ header (just #include it in your .mm implementation file) unless you need it for types other than the anonymous class. Alternatively, you might create a wrapper header for it that looks like the top of this file.

HTH, -Steve

like image 90
Steve Sisak Avatar answered Sep 20 '22 21:09

Steve Sisak