Bridging C++ and Swift in XCode, what are the right Build Settings? - c++

When I try to call the functions in my C++ implementation file (marked as C compatible in the header with the #ifdef __cplusplus extern "C" {} trick), I am getting the error:
"use of unresolved identifier, 'helloWorld()'"
I created the bridging header just by adding a cpp and header file to my project and clicking "OK" when it asked if I wanted to create the bridging header. I am #including "test.h" in the bridging header, which has the function declaration inside, but for some reason Swift just cannot see the function.
The weirdest part is, I created a new project and did the EXACT same procedure, and calling helloWorld() works fine, so it's something about the existing project I'm trying to add the cpp file to that isn't working.
I'm assuming then that this is a build-settings problem, and that I must have messed them up somewhere along the lines, probably when I was trying to import a static C/CPP library (Which I've since removed, but some of the build settings I changed for it probably stayed).
So are there any build settings I should know about that will fix this? Or is there a way to just completely reset my build settings to the default (Even if that means I have to recreate the bridging header to get the bridging header build settings back in place)?
Thank you for any and all help!
James
---Edit---
Here is my cpp header:
Here is my cpp implementation file:
Here is my bridging header:
Here is the relevant portion of the Swift project:
And here is the build setting that sets the bridging header:

Alright - This has been resolved. The problem is that the bridging header needed to be realized from both the regular target and also the Testing target, which was in my existing project because I'm doing Unit Testing.
I simply went into the build settings for my testing target and added the appropriate Objective-C Bridging Header, and then it all worked fine.
Hope it helps someone!

I had the same experience. Make sure you add a Unit Test Target, then ensure the Unit Test Target has visibility of the Bridging Header file.
Another mistake I made; ensure each Swift Class, Enums used in the test case has Target Membership set correctly.

Related

'C does not support default arguments' using Swift bridging header

In an iOS Swift project I'm including a set of libraries built using C++ (HikVision/hcnetsdk.h) and while I've managed to get the frameworks to build, the header file won't compile and Xcode is giving me multiple 'C does not support default arguments'.
For example on this line:
NET_DVR_API BOOL __stdcall NET_DVR_SetConnectTime(DWORD dwWaitTime = 3000, DWORD dwTryTimes = 3);
I've checked the build settings of the project and as far as I can tell everything is set to use C++, so I'm confused as to why Swift is compiling this as C, and complaining about default arguments.
My bridging header file is as follows:
#import "ldapTest.h"
#import "hcnetsdk.h"
#import "HikDec.h"
I'm fairly sure it's a build setting somewhere but which one I don't know.
So it turns out you can't include a C++ header file which contains C++ specific keywords into a Swift bridging header file.
What I did manage to do for my specific situation was find a "C" replacement of the "C++" header which worked with a few minor tweaks.
This is the "C" header file for the HikVision HCNetSDK.h which I found online:
https://github.com/shulianghe/new-project/blob/master/pro/hcSrc/incCn/HCNetSDK.h
If anyone has a similar problem with other C++ header files, you can copy some of the #ifdef __cplusplus statements in the link above to see how it's done.

Xcode and C++ Headers

I have a question about using C++ header files in Objective-C++ modules in Xcode. Specifically, why can I #include them in source files but not header files?
Here is a specific example.
I'm using Xcode 7.2.1 and have two projects. The first is a C++ framework I package into "myFramework.framework". It exposes "myFramework.h", which in turn pulls in "myLib.h". At the top of "myLib.h" is an "#include <string>".
The second project is an Objective-C iOS app which consumes the above framework. In this project, "myViewController.mm" (Objective-C++ source) has "#import "myFramework/myFramework.h" at the top and makes reference to things defined in that header file.
At this point all is well and good. It builds and runs with no issues.
When I move the "#import myFramework/myFramework.h" line to "myViewController.h", the compile fails because it cannot locate the "" header dependency.
It doesn't matter if I change the file type for "myViewController.h" to Objective-C++ header from plain old "C Header". Either way, Xcode's header search paths don't look for standard C++ headers.
So my main question is why does it behave this way? Why is a #include/#import treated differently just because it's in a header file?
My second question is if there's some way to make Xcode treat the #include/#import the same when it's in the header file instead of the source file?
Thanks much!
Are you sure that you get the error while compiling the myViewController.mm file?
Check if myViewController.h is imported into some other, non ObjC++ file (and that that one is the file that fails to compile).
I suspect the issue with including C++ headers inside other headers is that an Objective-C source file gets to see the C++ header file, which upsets it.
If you have mixed C++/Objective-C++/Objective-C then you are probably better off only exposing a pure Objective-C interface to other modules in the project and include any C++ header files in the Objective-C++ source files only.
Alternatively make everything Objective-C++ and then you don't need to worry about it at all.
Hopefully this answers your second question as well.

How do I know which header is being included?

I'm writing a set of unit tests, and creating stubs for classes that the unit test needs to compile and link. I would like to know whether the real header is being included, or the fake(stub) header is being included for these headers that I'm tying to stub out.
Any ideas on how to test this?
Nevermind, I found a solution. You can simply put the following in the fake header:
#pragma message ("Mock is being included")
and that will be printed when compiling, so you know which header is being #include'd.
If you have access to GCC/G++, use the -M option.
If you use Visual Studio: Go to Project Settings, then Configuration Properties, then C/C++, then Advanced, then Show Includes. It activates the compiler switch /showIncludes.
Both will output the dependency list at compile time.
Better than having to modify header files....

Include <string> not found compile error in Xcode 4.2

I'm getting include not found compile error in XCode. I have an iOS app project that i use Objective-c and c++ as mix.
Initially, i created one .h file and one .cpp file in my ios project. Then, I renamed the .cpp file to .mm file.
Here is my .h file;
TestLog.h
#ifndef CalculatorDemo_TestLog_h
#define CalculatorDemo_TestLog_h
#include <string>
using namespace std;
class TestLog
{
private:
string logString;
public:
void Log(string logMessage);
};
#endif
TestLog.mm
#include "TestLog.h"
void TestLog::Log(string logMessage)
{
//this->logString->append(logMessage);
}
What am I missing? Do I need to add std c++ library to my targetS? Something related to Search Header Paths?
I just need to use string type.
Thanks much for in advance
select project -> build setting -> apple LLVM compiler 5.1 -> language
In Compile Sources As change to Objective-C++
There's a quirk in XCode. I noticed it in 7.3. Most projects recognize .mm files and the STL, while one project I had did not. The fix was that I had to click on the top-left project icon, then click Targets > Build Phases > Link Binary with Libraries > and add in AppKit.framework. Next, I had to click Targets > Build Settings > search on "Compile Sources", and set it to "Objective C++" on all possible columns. Then, do a Clean and then a Build from the Product menu. This compiled properly then. Then, go back to that Compile Sources again and set it back to "According to File Type" on all possible columns. Then, click Build from the Product menu again. At that point, it compiled properly and allowed me to utilize the "according to file type" option, which I like better.
Oh, and if doing Cocoa stuff, don't forget to add the following header in your files:
#import <Cocoa/Cocoa.h>
And if doing command line stuff, don't forget to add the following instead of the Cocoa header:
#import <Foundation/Foundation.h>
i believe you need to include the whole path to the library. similarly to say "foundation" & "uiview" frameworks.
#import <Foundation/Foundation.h>
or
#import <UIKit/UIKit.h>
and yes, make sure you add the library to your target.
So I was having this issue with the Cocoapods library Bypass and none of these solutions did anything. The problem was with a file which Cocoapods creates called an umbrella header. This is located in <POD_NAME>/Support Files/<POD_NAME>-umbrella.h. Delete it, and it should build just fine.
Now for the explanation of why this is necessary: the umbrella header is mixing both C++ and Objective-C code directly in a header which is a big no-no apparently and ends up completely breaking the C++ imports. By removing it (which seems to have no effect?) this conflicting import which Cocoapods unknowingly created will go away.
Ran into this with xcode 12.4 with a project that is objective-c, but where I need one C++ modul. Solution: wrap the contents of the .h file in:
#if defined __cplusplus
declarations
#endif
Apparently xcode is not good at detecting a mix of sources.
see Expected ; after top level declarator, error in xcode
This often happens when Xcode doesn't understand that a C++ header file you've imported into Objective-C is actually for C++ code.
So you can solve this problem by finding the Objective-C file that imports C++ code, and simply change its extension from .m to .mm

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

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.
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.
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.