So, I have a C++ project that I want to put into a framework that will act as a wrapper (written in Objective-C/C++) to the C++ code, so that I can later use this in a Swift or Objective-C project by simply adding the framework to the app.
What I have accomplished so far:
Created all the wrappers
Exposed the wrapper's public headers in the build phase
Added a run-script in the build phase to simply copy all the C++ headers (keeping their file directory structure) into the framework's directory, so that they are available to the app using the framework. The reason for me to do this and not just put them in the headers' field of the build phase is because there are a lot of files and folders and doing that would require me to change every header to #include "LocalHeader.h" rather than how it is currently written as #include "CppRootFolder/Subfolder/Header.h". Also I would rather not do this because I want to keep the C++ files unaltered.
The problem:
Everything seems to work well except that when building the actual app, xcode will error out saying it can't find the files inside the file structure. To illustrate what I mean, I have the following:
The umbrella file for the framework will #include "CppRootFolder/umbrella.h" (the c++ umbrella file)
In CppRootFolder/umbrella.h, I have several #include "CppRootFolder/Subfolder/Header.h"
Each one of the headers inside each subfolder include other headers referencing them from the root folder of the c++ code.
My take on this:
It seems clear to me that the issue is that the compiler needs to find the headers from the root folder of the c++ code. So, in the actual App, in build settings, I add a header search path to: $BUILT_PRODUCTS_DIR/FrameworkName.framework/Headers, which is where I copied all the headers with the script. However, the build fails and produces a lot of random errors not recognizing types that are already defined.
Any ideas on how I can get this to work?
Thanks
UPDATE (Logs):
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "Headers/Box2D.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:
#import "World.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:
#import "Box2D/Box2D.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:34:10: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:34:
#include "Box2D/Common/b2Settings.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Settings.h:153:8: error: must use 'struct' tag to refer to type 'b2Version'
extern b2Version b2_version;
^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "Headers/Box2D.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:
#import "World.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:
#import "Box2D/Box2D.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:35:10: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:35:
#include "Box2D/Common/b2Draw.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Draw.h:22:10: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Draw.h:22:
#include "Box2D/Common/b2Math.h"
^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Math.h:28:31: error: unexpected type name 'int32': expected expression
int32 ix = *reinterpret_cast<int32*>(&x);
When you write a wrappers C++ should not be visible outside.
So #include "cppHedarFile.h" should not be accessible outside the wrapper, otherwise you will have an errors about using C++ in Objective C code.
So there should not be umbrella header file for C++ headers.
Please provide technical details: copy paste error message you are seeing. Your interpretation of error can be misleading.
You didn't paste everything but this line:
/Box2D.framework/Headers/Box2D/Common/b2Math.h:28:31: error: unexpected type name 'int32': expected expression
int32 ix = *reinterpret_cast<int32*>(&x);
Give me a hind that I'm right.
Most probably you are including C++ headers from Objective C file *.m.
For such file C++ standard headers are not reachable that is why type int32 is not recognized.
Like I've wrote at begging. When you are writing a Objective C wrapper around C++, includes of C++ headers from public headers are forbidden.
You can do it only form *.mm file for from internal headers which are only used by *.mm.
This way wrappers are doing their job and handing C++ from user of wrapper.
Example
Public header KXSomeClass.h:
#interface KXSomeClass : NSObject
#property (nonatomic, readonly) BOOL allowed;
- (NSUInteger)someAction:(NSString *)s;
#end
Private header KXSomeClass+Internal.h
// this header is used only by wrappers
#import "KXSomeClass.h"
#include <memory>
#interface KXSomeClass ()
- (instancetype)initWithNativeSomeClass:(const std::shared_ptr<SomeClass>&)nativeObject;
#end
Implementation KXSomeClass.mm
#import "KXSomeClass+Internal.h"
#interface KXSomeClass ()
#property (assign, nonatomic) std::shared_ptr<SomeClass> native;
#end
#import "KXSomeClass+Internal.h"
#include "cpp/SomeClass.h"
#implementation CSCapability
- (instancetype)initWithNativeSomeClass:(const std::shared_ptr<SomeClass>&)nativeObject
{
if (self = [super init]) {
_native = nativeObject;
}
return self;
}
- (NSUInteger)someAction:(NSString *)s
{
return _native->SomeAction(s.UTF8String);
}
- (BOOL)allowed
{
return _native->Allowed();
}
#end
Related
I'm porting a game written in C++ and OpenGL to run on iOS and OpenGL ES. The original version uses libpng and jpeglib for loading image data as sprites, and I want to replace these with CoreGraphics functions.
At the top of the C++ source file which contains the image loading functions, I've added the following:
#ifdef TOUCH_VERSION
#include <Foundation/Foundation.h>
#include <CoreGraphics/CoreGraphics.h>
#else
#include <png.h>
#include <jpeglib.h>
#endif
The TOUCH_VERSION compiler flag is defined (and is working, since it's not complaining about missing png.h and jpeglib.h). The problem I'm having is that it's not recognising any CGImage functions. For example:
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename(path);
results in the error ImageBuffer.cpp:166:42: No matching function for call to 'CGDataProviderCreateWithFilename'. Initially when I added the CF and CG includes, it autocompleted the CoreGraphics type and function names so I presumed the header import had worked, but when I built I got errors that NSString and other Objective C types were not defined. I added -x objective-c to the C flags, and -x objective-c++ to the C++ flags and it resolved this error, but then the error above appeared.
Thanks in advance for any help!
Ahh, sorted. I realised that the C++ function was using std::string as the CGDataProviderCreateWithFilename is expecting const char * as the filename. When I changed this to CGDataProviderCreateWithFilename(path.c_str()) it stopped complaining about the lack of a matching function.
I am working on adding code to an existing iphone app (written by someone else) that uses the card.io project. This is the first change i've attempted. The app compiles and runs fine with no changes but then when I try to add an empty .cpp and .h file to my xcode project I start getting syntax errors in an unrelated obj-c header file called CardIOMacros.h. I am using xcode 7.2 and compiling for an iphone 4s device.
The process I went through to add the .cpp and .h file was
right click on the project node in the project navigator
click new file
click c++ icon
type name of file and check create header file option
Select the subdirectory within my project directory.
press the build and run button in the main menu
Below is the file where I am getting errors. The errors are shown below the code.
//
// CardIOMacros.h
// See the file "LICENSE.md" for the full license governing this code.
//
// CardIOLog is a replacement for NSLog that logs iff CARDIO_DEBUG is set.
#if CARDIO_DEBUG
#define CardIOLog(format, args...) NSLog(format, ## args)
#else
#define CardIOLog(format, args...)
#endif
#interface CardIOMacros : NSObject
+ (id)localSettingForKey:(NSString *)key defaultValue:(NSString *)defaultValue productionValue:(NSString *)productionValue;
+ (NSUInteger)deviceSystemMajorVersion;
+ (BOOL)appHasViewControllerBasedStatusBar;
#end
#define iOS_MAJOR_VERSION [CardIOMacros deviceSystemMajorVersion]
#define iOS_8_PLUS (iOS_MAJOR_VERSION >= 8)
#define iOS_7_PLUS (iOS_MAJOR_VERSION >= 7)
#define iOS_6 (iOS_MAJOR_VERSION == 6)
#define iOS_5 (iOS_MAJOR_VERSION == 5)
Compliler Errors
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:14:1: Expected unqualified-id
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:18:1: Expected external declaration
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:18:4: C++ requires a type specifier for all declarations
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:18:15: Expected ';' after top level declarator
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:20:1: Expected external declaration
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:20:4: C++ requires a type specifier for all declarations
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:20:9: Expected ';' after top level declarator
/Users/michael/sdev/projectname/ios/card.io-iOS-20151210/Classes/CardIOMacros.h:22:1: Expected unqualified-id
The .h and .cpp file are empty and I dont even #include the new c++ header file in any other file. Any help would be appreciated.
Make sure you don't have said header included in ...-Prefix.pch.
I know, it may seem strange, but my goal is to undefine a class in C++. The root of the problem is in combining TinyXML2 and Boost unit tests.
Contents of the header file (Configuration.h) which is being tested:
...
#include <tinyxml2.h>
...
And this is the contents of my configurationTests.h file:
#include "unitTests.h"
#include "Configuration.h"
BOOST_AUTO_TEST_SUITE(configuration_test)
BOOST_AUTO_TEST_CASE(basic) {
...
}
BOOST_AUTO_TEST_SUITE_END( )
When I try to compile my tests, I'm getting an error:
error C2371: 'XMLDocument' : redefinition; different basic
types c:\program files (x86)\windows kits\8.0\include\um\msxml.h 10085
Inside this file (msxml.h) on line 10085 we have this class definition:
class DECLSPEC_UUID("CFC399AF-D876-11d0-9C10-00C04FC99C8E")
XMLDocument;
When I remove those two lines, my tests do compile and everything seems fine. Of course, this is not a solution, but that fact prooves that something inside Boost unit tests library includes msxml.h and somehow leads to conflict with TinyXML2 library.
I tried different solutions found in Google (like writing "#define WIN32_LEAN_AND_MEAN"), removing "using namespace tinyxml2" and making changes inside tinyxml2.cpp - nothing actually helps.
So, my question is simple: can I undefine (unload?) previously defined class in compile time in some tricky way? I tried "#undef XMLDocument", "#define XMLDocument 1" + "#undef XMLDocument" - nothing works.
Update: Actually, I kinda solved the problem by writing "#define MSXML_LIBRARY_DEFINED" on the first line of configurationTests.h. But still, I would love to know an answer to this topic question.
I think you have used default namespace for tinyxml2.
Try to delete using namespace tinyxml2 and then use it like in this example:
tinyxml2::XMLDocument xDoc;
try this:
namespace your_name_space
{
#include <tinyxml2.h>
}
From now all classes inside the tinyxml2 are hidden by your namespace.
The namespece must be declared also for the tinyxml2.cpp file.
I have the following code:
#interface Model ()
{
//...
std::function<bool(CGFloat, CGFloat)> greaterThan;
std::function<bool(CGFloat, CGFloat)> lesserThan;
//...
}
#end
Everything worked fine in my original project.
I just created a new project, and dragged and dropped the files between the two, and in the new project I have the following errors for the above two lines:
No type named 'function' in namespace 'std'
I don't know what the problem is - The files are .mm , why can't it find function in the names space std ?
Add #include <functional> to the top of your code.
Also remember to use -std=c++0x (or equivalent) in your compiler parameters; this will enable C++11 standard which is required for std::function.
I'm trying to use C++ code in my ios app (I really don't like objective C, I'm going to use it only when necessary [view control, etc]) and while everything seems to be working I get an error in the following test file.
#ifndef prueba3_GlobalStatic_h
#define prueba3_GlobalStatic_h
#include <string>
using namespace std;
class GlobalStatic
{
public:
GlobalStatic();
~GlobalStatic();
string foo();
private:
int integerValue;
};
#endif
When I try to build the project the IDE gives me the following error:
" 'string' file not found"
I've looked around but cannot find a conclusive answer; any help would be appreciated. In essence, how do I get the standard library working?
One cause of missing c++ headers is including them from an objective-c context as opposed to from objective-c++ -- and you can't use the c++ stl from c! The easier solution is to simply change all your .m files to .mm, .mm will send them to the objective-c++ compiler.