Xcode: Referencing C++ project from Objective-C pr

2019-05-31 11:29发布

I'm beginning to tear my hair out over this, so it's time to post here!

I have a C++ project in XCode, built as a Command Line Tool. All .cpp files have been renamed as .mm, there is one .hh and a few .h headers. I've specified 'Compile Sources As -> Objective-C++' in Build Settings.

I have another XCode project for an iOS app. This is set to 'Compile Sources As -> According to File Type'. I can't set it to compile everything as Objective-C++ since some parts of the project won't compile as Obj-C++.

There is one class in the iOS app where I wish to utilise my C++ project, and it consists of files MyClass.hh, MyClass.mm; they were simply .h and .m but I renamed them in the hope of remedying this problem.

I dragged my cpp project into the iOS project. I then added a Target Dependency in the iOS Build Phases to point to the cpp CLI application.

In MyClass.hh I have

#include "../path/to/CppProject/ImportAll.h"

..which is a header file that successively 'include's all headers from the cpp project. I then go about my business, creating one property within MyClass.hh which is a pointer to a cpp object, and various references within MyClass.mm to cpp classes.

The darn thing just won't compile though - I get a ton of messages relating to my cpp classes like this:

MyCPPFile.h:10: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token

Is the compiler not recognising that MyClass.hh is Objective-C++ not Objective-C? Should I have a target dependency which is a library instead of pointing to this CLI app, perhaps?

I've googled around for a while trying to solve the problem. I've seen references to people using

#ifdef __cplusplus

or else having to rename files to .mm to get things working, but in other cases people simply say they drag and drop projects across with no issues.

Can someone please enlighten me, and explain what key steps I should be performing to make this work? I'd be very grateful! Thank you.

2条回答
何必那么认真
2楼-- · 2019-05-31 11:33

Thanks to everyone who gave me suggestions.

Having created my projects anew from scratch, I fiddled and logic-ed my way to the solution. Note that - at least in my case - no use of #ifdef __cplusplus was required, nor any other preprocessor directive. Only file suffix changing is essential (as detailed below).

Here's the process:

Create C++ Static Library and Include/Link with Objective-C Library (e.g. iOS app) in XCode 4:

  • In XCode 4 create a New Project of type Cocoa Touch Static Library. Hereafter we shall refer to this project as 'CProj'.
  • In CProj workspace create/import as many C++ classes as required. No special suffix for filenames is necessary - all my files are .h and .cpp.
  • In XCode create/open any Objective-C project e.g. iOS app. Hereafter we shall refer to this project as 'ObjProj'.
  • Find CProj.xcodeproj in Finder (typically /Documents/CProj/CProj.xcodeproj), drag it onto the visible ObjProj project icon at the top of your XCode Project Navigator (visible file/folder hierarchy on left side in XCode). This now places CProj as a nested project within ObjProj.
  • Left click ObjProj project icon in Project Navigator, a new pane emerges to the right, left click Build Phases in this pane.
  • Under Target Dependencies click '+' icon and select CProj library icon below listed CProj project. Click OK.
  • Under Link Binary With Libraries click '+' icon and select CProj library icon from within Workspace collapsible folder at top of window presented.

File Renaming Rules

  • Where including a CProj header in ObjProj, use path backtracking to identify import, e.g. #include "../../MyProj/MyImport.h" to step 2 dirs backwards then step into MyProj folder.

  • Any ObjProj implementation file including a CProj header must be renamed from .m to .mm . Any ObjProj header file including a CProj header must be renamed from .h to .hh .

  • Any ObjProj file including a file whose suffix is now .hh (consequence of step above) must be renamed in the same manner.

An example: Consider you have files A.h, A.m, B.h, B.m. A.m imports B.h, and B.h includes one or more CProj headers. B.m includes type references, using CProj classes included via B.h . First renaming is B.h -> B.hh since it contains includes. Then B.m -> B.mm since it contains type references to CProj (no includes necessary since B.h has already done them). Then A.m -> A.mm since A.m which contained an include for B.h now has an include for the renamed file, B.hh .

P.S. Note that the C++ library doesn't like to auto-rebuild when it should - I often have to 'Clean' then 'Build' in ObjProj after updating CProj from within it.

查看更多
女痞
3楼-- · 2019-05-31 11:56

It sounds like the crux of your problem is this:

Is the compiler not recognising that MyClass.hh is Objective-C++ not Objective-C?

The compiler is not recognizing that MyClass.hh is Objective-C++ code. Or any other code; the compiler never sees MyClass.hh (in all likelyhood).

By convention, header files are never passed to the compiler by default. Only the source files (.cpp, .m, et cetera) are -- the preprocessor that is run on those files results a translation unit that contains the original source file plus all the included headers and resolved macros.

So the problem is that you probably have a .mm source file that imports MyClass.hh, which in turn includes the C++ header file. But the compiler is trying to compile the resulting translation unit as Objective-C++ and encountering some C++-specific stuff in that header. In fact, I suspect that this problem has nothing at all to do with the additional target dependencies and such that you've got set up: I think you could reproduce it minimally with a very simple Objective-C++ application that includes the header. You should try that and see, it will either confirm my theory (after all I'm just speculating since you haven't shown enough source for me to know for sure) or indicate that the problem is elsewhere.

The solution is probably to use preprocessor guards like #ifdef __cplusplus (there's a useful catalog of predefined symbols here) to hide the C++-specific code from the Objective-C++ compiler (or the other way around in some cases). Note that this may be difficult to impossible to do based on the actual content of the header.

查看更多
登录 后发表回答