I am trying running c++ file on plugin IOS (not ios app). First I create cpp file
Greeting.cpp
#include "Greeting.hpp"
Greeting::Greeting() {
greeting = "Hello C++!";
}
std::string Greeting::greet() {
return greeting;
}
Then I create Greeting.hpp
#ifndef Greeting_hpp
#define Greeting_hpp
#include <stdio.h>
#include <string>
class Greeting {
std::string greeting;
public:
Greeting();
std::string greet();
};
#endif /* Greeting_hpp */
Then I import it into object c file
AgoraRtcEnginePlugin.m
#import "Greeting.hpp"
NSString* newTitle = [NSString stringWithCString:greeting.greet().c_str() encoding:[NSString defaultCStringEncoding]];
result(newTitle);
But when I complile It always throws errors
/agora-flutter-sdk/ios/Classes/Greeting.hpp:13:10: fatal error: 'string' file not found
#include <string>
The problem you have is that you're including C++ in your Objective-C (AgoraRtcEnginePlugin.m = .m extension is Objective-C) file. Objective-C is a layer on top of C and Objective-C is a strict superset of C.
You can't do this unless you use extern "C", etc. There are questions about this:
How to call C++ function from C?
Calling āC++ā class member function from āCā code
etc.
You're not forced to create an C API for you class, because there's also Objective-C++ (.mm extension) and you can use C++ directly in these files.
Related
I am trying to compile C++ code to a DLL file to use with Lua. To do this, I am using Visual Studio 2022 with Windows 10. My goal is to use the Lua require(modname) function to require my DLL and use the C++ methods in Lua. For now the DLL and the main.lua files are in the same directory. What is actually happening is that I get an error message saying:
error loading module 'lgf' from file 'lgf.dll': The specified module could not be found.
with the Lua code:
package.cpath = "?.dll;"..package.cpath
create = require("lgf")
My main.cpp file contains the following:
#include <iostream>
#include <string>
#include <window/include/window.hpp>
#include <font/include/font.hpp>
#include <image/include/image.hpp>
#include <keyboard/include/keyboard.hpp>
#include <mouse/include/mouse.hpp>
#include <rectangle/include/rectangle.hpp>
#include <lua/lua.hpp>
#define LIB
SDL_Window* sdlWin;
SDL_Renderer* sdlRen;
window win(sdlWin, sdlRen);
static const luaL_Reg lib[] = {
{"create", window::create},
{"isCloseRequested", window::isCloseRequested},
{"sync", window::sync},
{"update", window::update},
{"setVSync", window::setVSync},
{"setIcon", window::setIcon},
{"clearScreen", window::clearScreen},
{"render", window::render},
{"windowChangeColor", window::changeColorRGB},
{"close", window::close},
{"createRectangle", rectangle::create},
{"changeRectangleColor", rectangle::changeColor},
{"drawRectangle", rectangle::draw},
{"mouseButtonUp", Mouse::mouseButtonUp},
{"mouseButtonDown", Mouse::mouseButtonDown},
{"keyup", Keyboard::keyup},
{"keydown", Keyboard::keydown},
{"loadImage", ImageLoader::loadImage},
{"drawImage", ImageLoader::drawImage},
{"loadFont", FontLoader::loadFont},
{"loadText", FontLoader::loadText},
{"renderText", FontLoader::renderText},
{NULL, NULL}
};
extern "C" __declspec(dllexport) int luaopen_lgf(lua_State* L) {
luaL_newlib(L, lib);
return 22;
}
I am creating a simple graphics library. My dependencies are SDL2 and (of course) Lua.
I have tried creating an entry point (main) for the file, and I still get the same message. Let me know if I should include my other .cpp files in here.
Is it possible to use [[NSProcessInfo processInfo] operatingSystemVersion] from C++ or C and how do I do that?
In XCode and Objective-C, files with extension .mm are treated as "mixed" in the sense that one single file can contain C++/C notion as well as Objective-C code, and that even C++/C function implementations can access Objective-C classes and send messages to them.
Such a .mm-files can then provide a trampoline function, i.e. a C-style function that is exposed and can then be used in pure C++/C-files (extension .cpp, where Objective-C code must not occur).
Let's consider the following setting:
A mixed file ProcessInfoProvider.mm, which calls [[NSProcessInfo processInfo] operatingSystemVersion] and provides the result in a C-style function std::string getProcessInfoVersion_C(),
A Pure cpp-file and a corresponding hpp-file UseProcessInfoInC.cpp/hpp defining a class MyCppProcessInfo, which provides a printVersion()-member function and which uses getProcessInfoVersion_C,
Some other file that instantiates MyCppProcessInfo and calls member function printVersion()
Let's start with ProcessInfoProvider.mm:
#import <Foundation/Foundation.h>
#import <Foundation/NSProcessInfo.h>
#include <string.h>
#include <iostream>
std::string getProcessInfoVersion_C (void) {
NSProcessInfo *processInfo = [[NSProcessInfo alloc] init];
// check avaiability of the property operatingSystemVersion (10.10+) at runtime
if ([processInfo respondsToSelector:#selector(operatingSystemVersion)])
{
NSOperatingSystemVersion versionObj = [processInfo operatingSystemVersion];
char version[500];
snprintf(version, 500, "Version %ld.%ld.%ld",
(long)versionObj.majorVersion,
(long)versionObj.minorVersion,
(long)versionObj.patchVersion);
return version;
}
else
{
// Implement fallback for OSX 10.9 and below
return "?";
}
}
Note that getProcessInfoVersion_C is a C-style function but contains objective-C code in it's implementation.
Then, pure C++ files UseProcessInfoInC.cpp/hpp implement class MyCppProcessInfo:
// UseProcessInfoInC.hpp:
#ifndef UseProcessInfoInC_hpp
#define UseProcessInfoInC_hpp
class MyCppProcessInfo {
public:
void printVersion(void);
};
#endif /* UseProcessInfoInC_hpp */
and
// UseProcessInfoInC.cpp:
#include "UseProcessInfoInC.hpp"
#include <iostream>
extern std::string getProcessInfoVersion_C (void);
void MyCppProcessInfo::printVersion(void)
{
std::string version = getProcessInfoVersion_C();
std::cout << version;
}
Note that these two files do not contain any Objective-C-stuff.
Finally, let's try out MyCppProcessInfo, e.g. in a function main():
// File main.mm
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#include "UseProcessInfoInC.hpp"
int main(int argc, char * argv[]) {
#autoreleasepool {
MyCppProcessInfo pi;
pi.printVersion();
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
In the project .ino file this works:
void loop()
{
String stringOne = "Hello String";
}
However, in a class I get these errors:
// MenuItem.h
//#include "String.h" ====> Makes no difference if not commented
class MenuItem {
public:
MenuItem();
private:
String stringTwo; ====> 'String' does not name a type
};
// MenuItem.cpp
//#include "String.h" ====> Makes no difference if not commented
MenuItem::MenuItem() {
stringTwo = "Goodbye String"; ===> 'stringTwo' was not declared in this scope
}
I've tried different option for the #include with <> instead of quotes and with without the .h. I'm totally confused. Thanks.
The String class for Arduino is held in the WString.h and WString.cpp files.
You should just include WString.h in your .h file. The Arduino IDE automatically does this for your .ino files.
I'm trying to use a C++ library in my Swift project and until now, it works fine, except that I have a little problem when I'm trying to include a .h that contains C++ code in a .h of one of my Objective-C++ .h file.
Here is the situation in picture :
Here is the .h of my Objective-C++ class. As you can see, the init method take in parameter a SuperpoweredAdvancedAudioPlayerCallback, this type is declared in the file SuperpoweredAdvancedAudioPlayer.h that is a file of the lib written in C++, so I include it.
But the problem is that I cannot include C++ code except in .mm file, otherwise, Xcode won't compile and says:
So I tried to move all the #interface block and the #import "SuperpoweredAdvancedAudioPlayer.h" of my SuperpoweredAdvancedAudioPlayerWrapped.h file in my .mm file but with that my SuperpoweredAdvancedAudioPlayerWrapped is not exposed to my Swift file, logic, the SuperpoweredAdvancedAudioPlayerWrapped.h file (that I include in file Bridging-Header) is now empty.
And if I only move the #import "SuperpoweredAdvancedAudioPlayer.h" in my .mm file, Xcode will not compile and says that SuperpoweredAdvancedAudioPlayerCallback is not a type, logic too...
So I'm stuck with that, as I'm not an Objective-C++ expert.
Any idea to solve this ?
The problem is that C++ types, such as SuperpoweredAdvancedAudioPlayer, cannot be exposed to Objective-C or Swift, but only to Objective-C++. Thus your wrapper, since it uses C++ classes, needs to be implemented in Objective-C++. The wrapper's header(s), i.e. the .h file(s), should not reference any C++ code.
I've seen a few uses of callbacks in the examples that come with Superpowered, and they typically implement the callbacks in Objective-C++ (.mm) files. You can search the code yourself, since it would not be very informative for the community to look at the product-specific examples.
What I might do in this case is
Not include the SuperpoweredAdvancedAudioPlayer.h header into the
header that declares the SuperpoweredAdvancedAudioPlayerWrapped
interface.
Express the interface in ..Wrapped.h in terms of custom data types
that will be implemented in .mm files, and that's where C++ code
will be referenced.
For example, you could introduce a SuperpoweredAdvancedAudioPlayerCallbackWrapped type that will be passed to the ..Wrapped init method.
The following is a mock-up example of how something like this could be done. First, here is some C++ code that we want to call from Swift (mylib.cpp):
#include "mylib.hpp"
MyCpp::MyCpp(MyCppCallback cb, int i) : m_CB(cb), m_Int(i) {}
int MyCpp::f(int i)
{
return m_CB(i + m_Int);
}
and the corresponding header file (mylib.hpp):
#ifndef mylib_hpp
#define mylib_hpp
/**
* Callback type used by the C++ code.
*/
typedef int (*MyCppCallback) (int);
/**
* A simple C++ class.
*/
class MyCpp
{
public:
MyCpp(MyCppCallback, int);
int f(int);
private:
MyCppCallback m_CB;
int m_Int;
};
#endif /* mylib_hpp */
The header, mylib.hpp, cannot be included in a Swift bridging header directly or indirectly, so we need a wrapper. BTW, the extension could be .h instead of .hpp, it doesn't really matter.
The wrapper code has to be Objective-C++ because it utilizes a C++ type (MyCpp), here it is (wrapper.mm):
#import "mylib.hpp"
#import "wrapper.h"
#implementation MyWrapper
{
MyCpp * pMyCpp;
}
-(id)init: (wrapper_cb_t)cb withInt: (int)i
{
pMyCpp = new MyCpp( cb, i );
return self;
}
-(int)f: (int)i
{
return pMyCpp->f(i);
}
#end
And here is the corresponding header, wrapper.h, that can be included in a Swift bridging header because it is free of any C++ stuff:
#ifndef wrapper_h
#define wrapper_h
#import <Foundation/Foundation.h>
/**
* Here we just repeat the callback typedef from mylib.hpp. We can do this because
* it does not depend on C++ types. If it did, we could come up with some
* "glue" code in wrapper.mm.
*/
typedef int (*wrapper_cb_t) (int);
/**
* This is the wrapper interface. It doesn't depend on any C++ types.
*/
#interface MyWrapper : NSObject
-(id)init: (wrapper_cb_t)cb withInt: (int)i;
-(int)f: (int)i;
#end
#endif /* wrapper_h */
The bridging header looks like this:
#import "wrapper.h"
and here is sample Swift code using the C++ code via the wrapper:
/**
* This is a Swift callback function of type wrapper_cb_t.
* To figure out how the wrapper's signature is imported into Swift,
* just type "wrapper_cb_t" somewhere in the code, click on it, and
* Xcode Quick Help should show you the signature.
*/
func swift_cb(i: Int32) -> Int32
{
return i + 111
}
/**
* Now create an instance of MyWrapper...
*/
let w : MyWrapper = MyWrapper(swift_cb, withInt: 3)
/**
* ... and use it:
*/
print("f() in the wrapper returned \(w.f(4))")
This sample is a very simplified piece of code and doesn't claim to be production quality. E.g., memory management is not covered.
Please note that once you start dealing with callbacks, things get a lot more complicated than just having Swift call Objective-C/C++ code. Now you have to write code that will be called by C and/or C++. You will find a lot of interesting info on that if you search for "Swift callback c" in this forum or Google.
I've compiled a dylib in Qt/C++. I created a simple class method called test() that reads a string input and returns a string output with "-response" back. Now how do I load that inside Objective C in XCode 7 (a default Cocoa application) and make it emit test() via NSLog()?
This is what my build folder looks like in Qt/C++.
You need to use an Objective-C++ class, which is a hybrid of Objective-C and C++.
The greatest challenge using one or more Objective-C++ classes in a largely Objective-C project is avoiding exposing C++ classes to the Objective-C classes. Therefore you need to avoid C++ in the Objective-C++ header file and just include the C++ in the implementation file.
For example:
CppWrapper.h:
#import <Foundation/Foundation.h>
#interface CppWrapper : NSObject
- (BOOL)callCppMethodA:(int)param;
#end
CppWrapper.mm:
#import "CppWrapper.h"
#import "cppclass.h" // C++
#interface CppWrapper()
{
cppclass *_cppclass; // C++
}
#end
#implementation CppWrapper
- (id)init
{
self = [super init];
if (self) {
_cppclass = new cppclass(); // C++
}
return self;
}
- (void)dealloc
{
delete _cppclass; // C++
}
- (BOOL)callCppMethodA:(int)param
{
return _cppclass->methodA(param); // C++
}
#end
Use it like this:
CppWrapper *cppWrapper = [CppWrapper new];
[cppWrapper callCppMethodA:123];
Another approach would be to not use Qt/C++, but create C++ classes inside of Objective C and avoid Qt altogether, opting for these includes to make life a whole lot easier in C++:
#include <string>
#include <stdio.h>
#include <sqlite3.h>
#include <Foundation/Foundation.h>
string docs
stdio docs
stdio notes
sqlite3 docs
Apple Foundation Class docs
Also, one can (and actually must) mix a little Objective C in their C++ code in order to make life easier. Here's a sample .mm file, which is the file type that lets you mix C++ and Objective C:
#include <string>
#include <stdio.h>
#include <sqlite3.h>
#include <Foundation/Foundation.h>
class Testlib {
public:
std::string test(std::string sIn) {
sIn = sIn.append("-response");
return sIn;
}
NS_RETURNS_RETAINED NSString *test2(NSString *sIn) {
// note [[funky Objective C syntax]]
NSString *sOut = [[NSString alloc] init];
sOut = [NSString stringWithFormat:#"%#-response", sIn];
return sOut;
}
};
In order for me to call this from my main.m file, I had to rename it to main.mm and then do something like:
#import <Cocoa/Cocoa.h>
#import "testlib.mm"
int main(int argc, const char * argv[]) {
// demo Testlib out to the debug log
Testlib *o = new Testlib();
std::string s = "";
s = o->test("request");
NSLog(#"Result=%s",s.c_str());
NSLog(#"Result2=%#",o->test2(#"request"));
// load our GUI
return NSApplicationMain(argc, argv);
}
So, for the most part, it gives the ease of use of C++, but makes it powerful with the SQLite3 and Apple Foundation Class stuff to do pretty much what one would have used Qt for (without having to include very large Qt runtime framework libraries). However, for the GUI -- Cocoa is pretty sparse on options (dare I say fascist) compared to Qt, which is why I opt to use Mac native WebKit inside Cocoa, which opens up a vast array of GUI styling. Also, by using Mac native WebKit instead of Qt's embedded WebKit, you can decrease the .app size by about 30MB.