I trying to use va_start and va_end functions in my project, but eclipse don't want to resolve it as functions. gcc compiles whole project without errors...
[myfile.cpp]
#include <stdio.h>
#include <stdarg.h>
[...]
inline void ShowDbgMsg( const char* str, ... )
{
va_list argptr;
va_start(argptr, str);
vprintf(str, argptr);
va_end(argptr);
}
[...]
[Android.mk]
[...]
LOCAL_C_INCLUDES := jni/pvrTools/ jni/igel/ $(STLPORT_BASE)/stlport
[...]
Eclipse says:
[...]
Description Resource Path Location Type
Function 'va_start' could not be resolved igel.comdef.h /NativeProject/jni/igel line 195 Semantic Error
Function 'va_end' could not be resolved igel.comdef.h /NativeProject/jni/igel line 203 Semantic Error
Function 'va_start' could not be resolved igel.string.h /NativeProject/jni/igel line 341 Semantic Error
Function 'va_end' could not be resolved igel.string.h /NativeProject/jni/igel line 351 Semantic Error
[...]
So, it looks like Eclipse unable to locate something... How to solve this issue?
Thanks in advance!
P.S.> Project->Index->Rebuild didn't help. :(
My solution is also not pretty. But after you've deleted the error markers 100 times, try putting this code somewhere before you include stdlib.h. Then define ECLIPSEBUILD=1 in Project::Properties::C++ General::Paths and Symbols.
#if ECLIPSEBUILD // this part is just to fix spurious Eclipse errors
typedef __builtin_va_list va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#define va_copy(d,s) __builtin_va_copy(d,s)
#endif
#define __va_copy(d,s) __builtin_va_copy(d,s)
typedef __builtin_va_list __gnuc_va_list;
typedef __gnuc_va_list va_list;
typedef va_list __va_list;
#endif
I solve this issue by replacing my va_* code with embedded compiler features:
#ifdef IGEL_PLATFORM_ANDROID
# define ShowDbgMsg(...) ((void)__android_log_print(ANDROID_LOG_INFO, "igel-debug", __VA_ARGS__))
#else
inline void ShowDbgMsg( const char* str, ... )
{
va_list argptr;
va_start(argptr, str);
vprintf(str, argptr);
va_end(argptr);
}
#endif // IGEL_PLATFORM_ANDROID
I know it's not a good solution, but it works.
#include <stdarg.h> // includes va_list
inline void ShowDbgMsg(char* format, ...)
{
va_list ap;
va_start( ap, format );
// replace vfprintf( stderr, format, ap ) with:
__android_log_vprint(0, __FILE__, format, ap);
va_end( ap );
}
Related
I created C/C++ project in android studio and I want to use NDK camera.
I wrote in my cpp file
#include <camera/NdkCameraMetadata.h>
#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraDevice.h>
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_test_MainActivity_listDevices(JNIEnv* env, jobject)
{
std::string text;
ACameraIdList *camList;
ACameraManager *camManager;
camManager = ACameraManager_create();
camera_status_t result = ACameraManager_getCameraIdList(camManager, &camList);
if (result == ACAMERA_OK)
{
text = "Error List devices";
}
else
{
text = "Device listed";
}
return env->NewStringUTF(text.c_str());;
}
but Android studio is writing
"Can't resolve type ACameraIdList"
What I'm doing wrong? I just added this code into .cpp file, nothing else. Idid not changed any other files.
As mentioned in the comments, you need to set the minSDK to 24 or higher.
The NdkCameraDevice.h header files detects the minSDK using the __ANDROID_API__ identifier:
#if __ANDROID_API__ >= 24
...
typedef struct ACameraIdList {
int numCameras; ///< Number of camera device Ids
const char** cameraIds; ///< list of camera device Ids
} ACameraIdList;
...
#endif
This means that if the minSDK is below 24 the C preprocessor will omit the declaration of ACameraIdList and other related structures and functions. This leads to the "Can't resolve type ACameraIdList" error.
I have Java classes being translated to Objective C (J2Objc using the cradle plugin). The simple Android app and Unit tests work fine. The same simple Objective C iOS app also works perfectly. However, when I try to write similar code in a Swift project I cannot access instance variables, find methods, etc. This is relatively new to me so I may be missing something basic.
Here's the code in Objective C. Works perfectly:
SHRRefreshAppointments *mTest = [[SHRRefreshAppointments alloc] initWithId:nil withBoolean:true];
[mTest run];
SHREventListResp *mResp = [SHREventListResp parseFromWithByteArray:mTest->mResponseData_];
NSLog(#"%#", mResp.description);
Same code in Swift - I cannot find the instance variable mResponseData which is readily available in Objective C:
let mTest : SHRRefreshAppointments = SHRRefreshAppointments(id: nil, withBoolean: true)
mTest.run()
var mResp : SHREventListResp = SHREventListResp.parseFromWithByteArray(mTest.)
Here are the contents of the bridging header:
#include "JreEmulation.h"
#include "J2ObjC_header.h"
#import "com/gcatconsult/shared/remote/AppConstants.h"
#import "com/gcatconsult/shared/remote/AppUtils.h"
#import "com/gcatconsult/shared/messages/nano/Resp.h"
#import "com/gcatconsult/shared/messages/nano//Req.h"
#import "com/gcatconsult/shared/messages/nano/EventListResp.h"
#import "com/gcatconsult/shared/messages/nano/EventListReq.h"
#import "com/gcatconsult/shared/messages/nano/Event.h"
#import "com/gcatconsult/shared/remote/RefreshAppointments.h"
#import "com/gcatconsult/shared/remote/NetworkBase.h"
SHRRefreshAppointments header:
//
// Generated by the J2ObjC translator. DO NOT EDIT!
// source: /Users/gabrielchoza/AndroidStudioProjects/GcatMobile/shared/src/main/java/com/gcatconsult/shared/remote/RefreshAppointments.java
//
#include "J2ObjC_header.h"
#pragma push_macro("INCLUDE_ALL_ComGcatconsultSharedRemoteRefreshAppointments")
#ifdef RESTRICT_ComGcatconsultSharedRemoteRefreshAppointments
#define INCLUDE_ALL_ComGcatconsultSharedRemoteRefreshAppointments 0
#else
#define INCLUDE_ALL_ComGcatconsultSharedRemoteRefreshAppointments 1
#endif
#undef RESTRICT_ComGcatconsultSharedRemoteRefreshAppointments
#if !defined (SHRRefreshAppointments_) && (INCLUDE_ALL_ComGcatconsultSharedRemoteRefreshAppointments || defined(INCLUDE_SHRRefreshAppointments))
#define SHRRefreshAppointments_
#define RESTRICT_ComGcatconsultSharedRemoteNetworkBase 1
#define INCLUDE_SHRNetworkBase 1
#include "com/gcatconsult/shared/remote/NetworkBase.h"
#define RESTRICT_JavaLangRunnable 1
#define INCLUDE_JavaLangRunnable 1
#include "java/lang/Runnable.h"
#interface SHRRefreshAppointments : SHRNetworkBase < JavaLangRunnable >
#pragma mark Public
- (instancetype)initWithId:(id)requestData
withBoolean:(jboolean)asyncCall;
#pragma mark Protected
- (void)postProcessExcecute;
#end
J2OBJC_EMPTY_STATIC_INIT(SHRRefreshAppointments)
FOUNDATION_EXPORT void SHRRefreshAppointments_initWithId_withBoolean_(SHRRefreshAppointments *self, id requestData, jboolean asyncCall);
FOUNDATION_EXPORT SHRRefreshAppointments *new_SHRRefreshAppointments_initWithId_withBoolean_(id requestData, jboolean asyncCall) NS_RETURNS_RETAINED;
FOUNDATION_EXPORT SHRRefreshAppointments *create_SHRRefreshAppointments_initWithId_withBoolean_(id requestData, jboolean asyncCall);
J2OBJC_TYPE_LITERAL_HEADER(SHRRefreshAppointments)
#compatibility_alias ComGcatconsultSharedRemoteRefreshAppointments SHRRefreshAppointments;
#endif
#pragma pop_macro("INCLUDE_ALL_ComGcatconsultSharedRemoteRefreshAppointments")
The SHRNetworkBase superclass:
//
// Generated by the J2ObjC translator. DO NOT EDIT!
// source: /Users/gabrielchoza/AndroidStudioProjects/GcatMobile/shared/src/main/java/com/gcatconsult/shared/remote/NetworkBase.java
//
#include "J2ObjC_header.h"
#pragma push_macro("INCLUDE_ALL_ComGcatconsultSharedRemoteNetworkBase")
#ifdef RESTRICT_ComGcatconsultSharedRemoteNetworkBase
#define INCLUDE_ALL_ComGcatconsultSharedRemoteNetworkBase 0
#else
#define INCLUDE_ALL_ComGcatconsultSharedRemoteNetworkBase 1
#endif
#undef RESTRICT_ComGcatconsultSharedRemoteNetworkBase
#if !defined (SHRNetworkBase_) && (INCLUDE_ALL_ComGcatconsultSharedRemoteNetworkBase || defined(INCLUDE_SHRNetworkBase))
#define SHRNetworkBase_
#define RESTRICT_JavaLangRunnable 1
#define INCLUDE_JavaLangRunnable 1
#include "java/lang/Runnable.h"
#class IOSByteArray;
#class JavaLangInteger;
#interface SHRNetworkBase : NSObject < JavaLangRunnable > {
#public
NSString *mGetPatientPath_;
NSString *mStringURL_;
IOSByteArray *mRequestData_;
IOSByteArray *mResponseData_;
jboolean mShouldCompress_;
jint mCurrentCall_;
jboolean mAsyncCall_;
}
#pragma mark Public
- (instancetype)initWithNSString:(NSString *)callPath
withBoolean:(jboolean)shouldCompress
withJavaLangInteger:(JavaLangInteger *)currentCall
withBoolean:(jboolean)async;
- (void)run;
#pragma mark Protected
- (void)postProcessExcecute;
- (id)sendAsyncServerRequestWithNSString:(NSString *)stringURL
withId:(id)requestData
withBoolean:(jboolean)shouldCompress
withJavaLangInteger:(JavaLangInteger *)currentCall;
#end
J2OBJC_EMPTY_STATIC_INIT(SHRNetworkBase)
J2OBJC_FIELD_SETTER(SHRNetworkBase, mGetPatientPath_, NSString *)
J2OBJC_FIELD_SETTER(SHRNetworkBase, mStringURL_, NSString *)
J2OBJC_FIELD_SETTER(SHRNetworkBase, mRequestData_, IOSByteArray *)
J2OBJC_FIELD_SETTER(SHRNetworkBase, mResponseData_, IOSByteArray *)
FOUNDATION_EXPORT void SHRNetworkBase_initWithNSString_withBoolean_withJavaLangInteger_withBoolean_(SHRNetworkBase *self, NSString *callPath, jboolean shouldCompress, JavaLangInteger *currentCall, jboolean async);
FOUNDATION_EXPORT SHRNetworkBase *new_SHRNetworkBase_initWithNSString_withBoolean_withJavaLangInteger_withBoolean_(NSString *callPath, jboolean shouldCompress, JavaLangInteger *currentCall, jboolean async) NS_RETURNS_RETAINED;
FOUNDATION_EXPORT SHRNetworkBase *create_SHRNetworkBase_initWithNSString_withBoolean_withJavaLangInteger_withBoolean_(NSString *callPath, jboolean shouldCompress, JavaLangInteger *currentCall, jboolean async);
J2OBJC_TYPE_LITERAL_HEADER(SHRNetworkBase)
#compatibility_alias ComGcatconsultSharedRemoteNetworkBase SHRNetworkBase;
#endif
#pragma pop_macro("INCLUDE_ALL_ComGcatconsultSharedRemoteNetworkBase")
Any help will be appreciated.
My limited understanding is that Swift imports Objective C properties as fields, not the fields themselves. You'll therefore need an accessor method for mResponseData.
The good news is that j2objc has a Property annotation, which you can add to the mResponseDate field so an equivalent Objective C property is generated during translation. That property should be imported later in Swift.
The Property annotation will also generate default accessors (like #synthesize does in Objective C), so if your Java class already has accessors, specify them using the getter= and setter= #property attributes. The translator's testProperties() test demonstrates a complex property annotation example.
mResponseData_ is an ivar and Swift can only access objective-c properties or functions. Alternative you can use mTest.valueForKey("mResponseData_") and mTest.setValue(someValue, forKey: "mResponseData_") or edit the generated class and transform the ivar in a property or method.
Not that you can create extension files with computed get and set to encapsulate the valueForKey implementation.
You can refer to this question for more details.
I'm using Eclipse ADT with: CDT. Along with NDK interfacing with JNI, to c/c++, compiling c/c++ with Cygwin through Eclipse. Everything should be running the latest versions as this was just setup over the last two weeks.
When Building I get the following.
jni/testSocketClass.hpp:33:1: error: unknown type name 'class'
jni/testSocketClass.hpp:33:17: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
jni/ndkfoo.c:13:1: error: unknown type name 'mYNewClass'
JNI C file
#include <string.h>
#include <jni.h>
#include "testSocketClassWrapper.hpp"
void *m_GBLpmyCSocket;
ndkfoo.c
jstring Java_com_example_hydrobedcontrol1_MainActivity_inintNativeClass(JNIEnv * env, jobject object){
m_GBLpmyCSocket = MyClass_create();
MyClass_sendCommandToSerialDevice(m_GBLpmyCSocket, 0, 0, 0);
return (*env)->NewStringUTF(env, "started");
}
Class Wrapper .hpp
//file testSocketClassWrapper.hpp
#ifndef _MY_SOCKETCLASS_WRAPPER_H
#define _MY_SOCKETCLASS_WRAPPER_H
#include"testSocketClass.hpp"//<<<<<<<<<<<<<<<<<<<<<Wrong inclusion
#ifdef __cplusplus
extern "C" void* MyClass_create() {
return new mYNewClass;
}
extern "C" void MyClass_release(void* myclass) {
delete static_cast<mYNewClass*>(myclass);
}
extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) {
static_cast<mYNewClass*>(myclass)->sendCommandToSerialDevice(cmd,params,id);
}
#endif
#endif /* _MY_SOCKETCLASS_WRAPPER_H_INCLUDED */
Class wrapper .cpp
//file testSocketClassWrapper.cpp
#include "testSocketClassWrapper.hpp"
Class .h
// file testSocketClass.hpp
class mYNewClass{///////////////////////ERROR HERE////////////////////////////////
//public:
void sendCommandToSerialDevice(int Command, int Parameters, int DeviceID);
//int sockfd;
};
Class .cpp
// file testSocketClass.cpp
#include "testSocketClass.hpp"
void mYNewClass::sendCommandToSerialDevice(int Command, int Parameters, int DeviceID){
char testc[100];
sprintf(testc, "%d, %d, %d", Command, Parameters, DeviceID);
}
I've read countless questions on this topic and have had quite a few issues getting this far with Eclipse configurations too. But from what I've pulled together from other questions on this topic, I have hit a wall and do not know how to proceed at this point. Suggestions?
EDIT BELOW - ANSWER
After review with a colleague(sometimes a second pair of eyes helps bring things out), we located my error. See the line labeled improper inclusion in the Class wrapper .hpp. That header should be relocated as follows in the Class wrapper .cpp NOTE: the functions where also moved to the .cpp and the .hpp is now empty.
//file testSocketClassWrapper.cpp
#include "testSocketClassWrapper.hpp"
#include "testSocketClass.hpp"
extern "C" void* MyClass_create() {
return new mYNewClass;
}
extern "C" void MyClass_release(void* myclass) {
delete static_cast<mYNewClass*>(myclass);
}
extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) {
static_cast<mYNewClass*>(myclass)->sendCommandToSerialDevice(cmd,params,id);
}
Also for completeness as this has been no walk in the park, are the MK files.
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and source file(s)
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.c testSocketClassWrapper.cpp testSocketClass.cpp
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL:=stlport_static
Thank you for the prompt reply krsteeve. And yet another way to do this. Will keep it in mind.
testSockedClass.hpp is being included from a .c file, so it's being compiled with a C-compiler. class doesn't exist in C. Change ndkfoo.c to a .cpp file.
You will have to format things a bit differently in C++:
extern "C"
{
jstring Java_com_example_hydrobedcontrol1_MainActivity_inintNativeClass(JNIEnv * env, jobject object);
}
jstring Java_com_example_hydrobedcontrol1_MainActivity_inintNativeClass(JNIEnv * env, jobject object){
m_GBLpmyCSocket = MyClass_create();
MyClass_sendCommandToSerialDevice(m_GBLpmyCSocket, 0, 0, 0);
return env->NewStringUTF("started");
}
Note the form of the NewStringUTF call in C++ vs C.
I set up logging with C++ in Android NDK.
I can print a message to logcat like this:
__android_log_write(ANDROID_LOG_INFO, "tag here", "message here");
Now let's say I have an integer called testint. How can I print the value of this int?
Something like this prints the address, but I want the value. I haven't found anything in C++ on how to do this. Thanks for any help!
__android_log_print(ANDROID_LOG_INFO, "sometag", "%p", *test);
Here's the most concise way I've seen:
#include <android/log.h>
#define LOG_TAG "someTag"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
...
// Now you can log very simply like this:
int foo = 42;
LOGD( "This is a number from JNI: %d", foo );
Also, make sure you link to the log library in your Android.mk:
LOCAL_LDLIBS := -llog
You could use __android_log_print which uses a sprintf-like syntax that formats your data into a string.
__android_log_print(ANDROID_LOG_INFO, "sometag", "test int = %d", testInt);
Take advantage of the variadic log print function you have available. For my own code, I provide a LogInfo() function to make it simple. Of course there are several options available to you here.
void LogInfo(const char *sTag, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__android_log_vprint(ANDROID_LOG_INFO, sTag, fmt, ap);
va_end(ap);
}
__android_log_print() takes a format string and a variable argument list. The format specifier you're looking for to print out a signed integer is "%d". So something like this is what you want:
int foo = 42;
__android_log_print(ANDROID_LOG_INFO, "SomeTag", "foo is %d", foo);
For more information on format strings, you can see the sprintf manual.
I am not able to call a function in cpp file from c file and also a function in c file from a cpp file in the ndk itself.
I tried using extern "C" {} as well.
Pasting the code i tried here for reference.
CFileCallingCpp.c:
#include "CFileCallingCpp.h"
//#include "custom_debug.h"
#include "CppFile.h"
void tempFunc() {
}
void printTheLogs() {
//Its not possible to make use of the CPP class in c file
// CCustomDebug cls;
// cls.printErrorLog("This is the error log %d %s", 54321, "aaaaaaaaaaaaaaaaaa");
// cls.printErrorLog("EXAMPLE", "This is the error log %d %s", 54321, "aaaaaaaaaaaaaaaaaa");
printTheLogs1();
// tempFunc();
}
CFileCallingCpp.h:
#ifndef _CFILECALLINGCPP_H_
#define _CFILECALLINGCPP_H_
void printTheLogs();
#endif
CppFile.cpp:
#include "CppFile.h"
#include "custom_debug.h"
#include "CFileCallingCpp.h"
void printTheLogs1() {
CCustomDebug::printErrorLog("This is the error log %d %s", 54321, "aaaaaaaaaaaaaaaaaa");
CCustomDebug::printErrorLog("EXAMPLE", "This is the error log %d %s", 54321, "aaaaaaaaaaaaaaaaaa");
}
#if defined(__cplusplus)
extern "C" {
#endif
void callCFileFunc() {
printTheLogs();
// printTheLogs1();
}
#if defined(__cplusplus)
}
#endif
CppFile.h:
#ifndef _CPPFILE_H_
#define _CPPFILE_H_
void printTheLogs1();
#endif
Errors i am getting:
sh-4.1$ /cygdrive/c/Android/android-ndk/ndk-build
SharedLibrary : libJNIExInterface.so
D:/EclipseWorkspace/NativeExample/obj/local/armeabi/objs-debug/JNIExInterface/CppFile.o: In function `callCFileFunc':
D:/EclipseWorkspace/NativeExample/jni/CppFile.cpp:15: undefined reference to `printTheLogs()'
D:/EclipseWorkspace/NativeExample/obj/local/armeabi/objs-debug/JNIExInterface/CFileCallingCpp.o: In function `printTheLogs':
D:/EclipseWorkspace/NativeExample/jni/CFileCallingCpp.c:18: undefined reference to `printTheLogs1'
collect2: ld returned 1 exit status
make: *** [/cygdrive/d/EclipseWorkspace/NativeExample/obj/local/armeabi/libJNIExInterface.so] Error 1
sh-4.1$
Please let me know if anyone knows how to call a cpp code from the c code in ANDROID-NDK.
Regards,
SSuman185
If you call a function from a cpp file that is defined in a c file, you can just use
extern "C" void c_func(); // definition
// from a cpp file
c_func();
You can do the other way around, call a function imlpemented in a cpp file from a c file
// implemnatation in cpp file
extern "C" void cpp_func()
{
// c++ code allowed here
}
// declaration in .h file
#ifdef _CPLUSPLUS
extern "C" void cpp_func();
#else
extern void cpp_func();
#endif
// from the c file
....
cpp_func();
.....
The extern "C" should be in the header file included by the C source, not in the C++ source file. The same for the C header file included by the C++ source file.