bytedeco / javacpp

The missing bridge between Java and native C++
Other
4.46k stars 582 forks source link

Cppbuild Control Callback Error #771

Open lfoland opened 1 month ago

lfoland commented 1 month ago

We are trying to wrap Franka Emika's libfranka library, but are getting this issue when defining a class called ControlCallback in our libfrankaConfig.java file. We have the following code:

`public static class ControlCallback extends FunctionPointer {
        static { Loader.load(); }
        public    ControlCallback(Pointer p) { super(p); }
        protected ControlCallback() { allocate(); }
        private native void allocate();
        public native Torques call(@ByRef @Const RobotState robotState, Duration duration);
    }`

In libfranka, ControlCallback represents an argument in the Robot class's control method. It should be of type std::function<franka::Torques(const franka::RobotState&, franka::Duration)>. We get the following error during runs of cppbuild.bash: In function ‘void Java_us_ihmc_libfranka_Robot_control__Lus_ihmc_libfranka_libfrankaConfig_00024ControlCallback_2(JNIEnv*, jobject, jobject)’: error: no matching function for call to ‘franka::Robot::control(JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback&)’ 5293 | ptr->control(*ptr0); | ^ In file included from /home/franka/IdeaProjects/repository-group/libfranka-java/cppbuild/include/franka/model.h:8, note: candidate: ‘void franka::Robot::control(std::function<franka::Torques(const franka::RobotState&, franka::Duration)>, bool, double)’ 172 | void control(std::function<Torques(const RobotState&, franka::Duration)> control_callback, | ^~~~~~~ no known conversion for argument 1 from ‘JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback’ to ‘std::function<franka::Torques(const franka::RobotState&, franka::Duration)>’ 172 | void control(std::function<Torques(const RobotState&, franka::Duration)> control_callback,

lfoland commented 1 month ago

I think the issue may be that libfrankaConfig adds the following methods to Robot.java: public native void control(@ByVal ControlCallback control_callback, @Cast("bool") boolean limit_rate/*=true*/, double cutoff_frequency/*=franka::kDefaultCutoffFrequency*/); public native void control(@ByVal ControlCallback control_callback);

But according to my research, this method is defined where ControlCallback is passed by reference in jnilibfranka.cpp:

JNIEXPORT void JNICALL Java_us_ihmc_libfranka_Robot_control__Lus_ihmc_libfranka_libfrankaConfig_00024ControlCallback_2ZD(JNIEnv* env, jobject obj, jobject arg0, jboolean arg1, jdouble arg2) {
    franka::Robot* ptr = (franka::Robot*)jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));
    if (ptr == NULL) {
        env->ThrowNew(JavaCPP_getJNIEXPORT void JNICALL Java_us_ihmc_libfranka_Robot_control__Lus_ihmc_libfranka_libfrankaConfig_00024ControlCallback_2ZD(JNIEnv* env, jobject obj, jobject arg0, jboolean arg1, jdouble arg2) {
    franka::Robot* ptr = (franka::Robot*)jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));
    if (ptr == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 7), "This pointer address is NULL.");
        return;
    }
    jlong position = env->GetLongField(obj, JavaCPP_positionFID);
    ptr += position;
    JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback* ptr0 = arg0 == NULL ? NULL : (JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback*)jlong_to_ptr(env->GetLongField(arg0, JavaCPP_addressFID));
    if (ptr0 == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 7), "Pointer address of argument 0 is NULL.");
        return;
    }
    jlong position0 = arg0 == NULL ? 0 : env->GetLongField(arg0, JavaCPP_positionFID);
    ptr0 += position0;
    jthrowable exc = NULL;
    try {
        ptr->control(*ptr0, (bool)arg1, arg2);
    } catch (...) {
        exc = JavaCPP_handleException(env, 9);
    }

    if (exc != NULL) {
        env->Throw(exc);
    }
}
JNIEXPORT void JNICALL Java_us_ihmc_libfranka_Robot_control__Lus_ihmc_libfranka_libfrankaConfig_00024ControlCallback_2(JNIEnv* env, jobject obj, jobject arg0) {
    franka::Robot* ptr = (franka::Robot*)jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));
    if (ptr == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 7), "This pointer address is NULL.");
        return;
    }
    jlong position = env->GetLongField(obj, JavaCPP_positionFID);
    ptr += position;
    JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback* ptr0 = arg0 == NULL ? NULL : (JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback*)jlong_to_ptr(env->GetLongField(arg0, JavaCPP_addressFID));
    if (ptr0 == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 7), "Pointer address of argument 0 is NULL.");
        return;
    }
    jlong position0 = arg0 == NULL ? 0 : env->GetLongField(arg0, JavaCPP_positionFID);
    ptr0 += position0;
    jthrowable exc = NULL;
    try {
        ptr->control(*ptr0);
    } catch (...) {
        exc = JavaCPP_handleException(env, 9);
    }

    if (exc != NULL) {
        env->Throw(exc);
    }
}`Class(env, 7), "This pointer address is NULL.");
        return;
    }
    jlong position = env->GetLongField(obj, JavaCPP_positionFID);
    ptr += position;
    JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback* ptr0 = arg0 == NULL ? NULL : (JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback*)jlong_to_ptr(env->GetLongField(arg0, JavaCPP_addressFID));
    if (ptr0 == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 7), "Pointer address of argument 0 is NULL.");
        return;
    }
    jlong position0 = arg0 == NULL ? 0 : env->GetLongField(arg0, JavaCPP_positionFID);
    ptr0 += position0;
    jthrowable exc = NULL;
    try {
        ptr->control(*ptr0, (bool)arg1, arg2);
    } catch (...) {
        exc = JavaCPP_handleException(env, 9);
    }

    if (exc != NULL) {
        env->Throw(exc);
    }
}
JNIEXPORT void JNICALL Java_us_ihmc_libfranka_Robot_control__Lus_ihmc_libfranka_libfrankaConfig_00024ControlCallback_2(JNIEnv* env, jobject obj, jobject arg0) {
    franka::Robot* ptr = (franka::Robot*)jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));
    if (ptr == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 7), "This pointer address is NULL.");
        return;
    }
    jlong position = env->GetLongField(obj, JavaCPP_positionFID);
    ptr += position;
    JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback* ptr0 = arg0 == NULL ? NULL : (JavaCPP_us_ihmc_libfranka_libfrankaConfig_00024ControlCallback*)jlong_to_ptr(env->GetLongField(arg0, JavaCPP_addressFID));
    if (ptr0 == NULL) {
        env->ThrowNew(JavaCPP_getClass(env, 7), "Pointer address of argument 0 is NULL.");
        return;
    }
    jlong position0 = arg0 == NULL ? 0 : env->GetLongField(arg0, JavaCPP_positionFID);
    ptr0 += position0;
    jthrowable exc = NULL;
    try {
        ptr->control(*ptr0);
    } catch (...) {
        exc = JavaCPP_handleException(env, 9);
    }

    if (exc != NULL) {
        env->Throw(exc);
    }
}`

but I don't know how to fix that.

saudet commented 1 month ago

Please try to use the Parser to see how it maps it

saudet commented 3 weeks ago

To map an instance of std::function, please try something like https://github.com/bytedeco/javacpp-presets/issues/1051#issuecomment-1129941479