3

So I want to publicly expose a Box2D (C++) pointer to other Objective-C++ classes in my cocos2d + box2d project. I declare a method "getWorld" in my interface which references C++ class b2World and imports Box2D.h. All the files in my project are .mm extension, and I get the following compile error:

In file included from DebugDrawLayer.mm:2:
In file included from World.h:10:
In file included from external/Box2d/Box2D/Box2D.h:34:
external/Box2d/Box2D/Common/b2Settings.h:22:10: fatal error: 'cassert' file not found
#include <cassert>

I guess Box2D.h is somehow compiled as C instead of C++, but I fail to understand how this happens. According to the log the include chain clearly starts from a .mm file.

Update:

The log says for World.mm (compiled earlier) that it clearly compiles as objective-c++

CompileC Objects-normal/i386/World.o World.mm normal i386 objective-c++ com.apple.compilers.llvm.clang.1_0.compiler 

but for DebugDrawLayer.mm it says objective-c

CompileC Objects-normal/i386/DebugDrawLayer.o DebugDrawLayer.mm normal i386 objective-c com.apple.compilers.llvm.clang.1_0.compiler

Both files are set as default - Objective-C++ source. What gives..?

Joakim Tall
  • 308
  • 2
  • 7
  • 13
  • 1
    Open `DebugDrawLayer.mm` in the Xcode primary editor. Then open the File Inspector (View > Utilities > Show File Inspector). In the File Inspector there's a File Type popup menu. What file type is selected? Is it “Default - Objective-C++ source”? – rob mayoff Aug 21 '12 at 07:36
  • @robmayoff Yeah it's "Default - Objective-C++ source". There seems to be some black magic at work here:) – Joakim Tall Aug 22 '12 at 11:24

6 Answers6

19

This appears to be a MAJOR bug in Xcode4, nothing to do with compiler settings - just Xcode internals.


UPDATE:

I eventually found the root cause. Yes, it's a bug in Xcode/LLVM. It compiles files in the wrong order, and then overrides its own settings, and breaks itself. Apple's tech support was too incompetent to even understand the problem, so I doubt they'll be fixing the bug anytime soon.

(NB: Skip this section, and see below, for my original answer, that gives a BRUTE FORCE but VERY QUICK TO DO solution)

What happens is ... if the compiler "sees" a C++ header while processing a C class ... it then marks that header (internally) as "C" (even when this is literally impossible).

Later on, when it comes back to that header, trying to compile it with C++, it finds it has already told-itself that the header is "C" (because it's incredibly stupid) ... and promptly crashes.

The correct solution (which requires lots of time and effort) is to go through EVERY C FILE in your project, and check (manually, because Xcode sucks) EVERY reference to EVERY header file -- and, for each one, EVERY header file it imports ... etc.

(this can take hours)

...until you find the chain of imports that leads to a C file "seeing" a C++ header.

All of this should be automated (but isn't). And the root problem shouldn't happen (if Xcode were correctly written).


I tried everything listed elsewhere on the web, most of the solutions are "keep removing/adding the file, and eventually Xcode will fix itself if you're lucky".

I wasn't lucky. The only thing that worked was:

  1. Go to build settings for your project
  2. find the "Compile Sources As" setting
  3. set it to "Objective-C++"
  4. re-build

The actual name/value is: "GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp" - so my guess is that this sidesteps Xcode's (broken!) internal logic.

Adam
  • 32,900
  • 16
  • 126
  • 153
  • No, I'm saying it should respect its own settings, it should respect the compiler, it should respect the programming language. Compiling a C++ file (that it knows is C++) with a C compiler is just ... all kinds of wrong. – Adam Sep 05 '13 at 14:43
3

I had same error and I just renamed one of my class(from which I call my box2d classes) from className.m to className.mm and now it works.

1

I had problems with this in my Cocos2D/Box2D project, it wasn't solved until I renamed ALL my .m files in my project (excluding the ones in Cocos2D of course) to .mm to compile them as Objective-C++.

I guess @Adam's solution works too, but I prefer to leave compilation settings as "According to File Type", feels cleaner.

Tom Söderlund
  • 4,743
  • 4
  • 45
  • 67
  • 2
    The problem is: Apple DOES NOT RESPECT the "according to file type" setting. Basically: that setting is a lie. So, yeah ... you can leave it at that setting, but all you're getting is the ILLUSION of "cleaner". – Adam Feb 04 '13 at 12:58
1

Actually correct solution it's take your code into:

#if __cplusplus

// … your code … 

#endif // __cplusplus
Volodymyr B.
  • 3,369
  • 2
  • 30
  • 48
0

Removing DebugDrawLayer from the project and then re-adding it again solved the issue. Maybe there were some strange compiler settings on the file in the build phases settings, never checked those.

Joakim Tall
  • 308
  • 2
  • 7
  • 13
0

I had this problem when having the #import "Box2D.h" in Prefix.pch. I changed the #import "Box2D.h" to be in each file that uses it instead.

Johan S
  • 3,531
  • 6
  • 35
  • 63