How to manually create jsb in cocos2dx 3.0

I’m trying to bind my own c++ class to javascript:

void register_all_mp(JSContext* cx, JSObject* obj){
    JS::Rooted<JS::Value> nsval(cx);
	JS::RootedObject ns(cx);
	JS_GetProperty(cx, obj, "mp", &nsval);
	if (nsval == JSVAL_VOID) {
		ns = JS_NewObject(cx, NULL, NULL, NULL);
		nsval = OBJECT_TO_JSVAL(ns);
		JS_SetProperty(cx, obj, "mp", nsval);
	} else {
		JS_ValueToObject(cx, nsval, &ns);
	}
	obj = ns;
}

Then I get the following errors:

Undefined symbols for architecture i386:
“js::IsInRequest(JSContext*)”, referenced from:
JS::Rooted<JSObject*>::Rooted(JSContext*, mozilla::detail::GuardObjectNotifier const&) in jsb_mp_auto.o
JS::RootedJS::Value::Rooted(JSContext*, mozilla::detail::GuardObjectNotifier const&) in jsb_mp_auto.o
ld: symbol(s) not found for architecture i386

I don’t know what’s wrong. Plz help!

I facing the same issue with the cocos2d-x-3.0rc0

Hi, @dunadain

I don’t know exactly why you are getting this error, but I didn’t see any usage of js::IsInRequest in your code, so if you can post the code where triggered the error, it may be easier to track down the reason.

If you need some more info about auto binding and manual binding, you can take a look at this wiki: http://www.cocos2d-x.org/wiki/How_to_bind_C++_to_Javascript

Huabin

I don’t think this will work with 3.0, because JSBool etc have been replaced with bool and I guess there are other changes too. This is happening with both auto and manual custom bindings. For example, i tried to create the following manual bindings.

void register_test_manual_functions(JSContext *cx, JSObject *obj) {
    JS::RootedValue  nsval(cx);
    JS::RootedObject ns(cx);
    JS_GetProperty(cx, obj, "ek", &nsval);
    if (nsval == JSVAL_VOID) {
        ns = JS_NewObject(cx, NULL, NULL, NULL);
        nsval = OBJECT_TO_JSVAL(ns);
        JS_SetProperty(cx, obj, "ek", nsval);
    } else {
        JS_ValueToObject(cx, nsval, &ns);
    }
    JS_DefineFunction(cx, ns, "_doesObjectExist", JSB_ekDoesObjectExist, 1, JSPROP_READONLY | JSPROP_PERMANENT );
}

and the error is

Undefined symbols for architecture i386:
  "js::IsInRequest(JSContext*)", referenced from:
      JS::Rooted<JSObject*>::Rooted(JSContext*, mozilla::detail::GuardObjectNotifier const&) in eureekah.o
      JS::Rooted<JS::Value>::Rooted(JSContext*, mozilla::detail::GuardObjectNotifier const&) in eureekah.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I have following paths in the xcode build settings

Framework search paths
$(SRCROOT)/…/…/cocos2d-js/frameworks/js-bindings/external/spidermonkey/prebuilt/ios

Header search paths
$(SRCROOT)/…/…/cocos2d-js/frameworks/js-bindings/external/spidermonkey/include/ios

Library search paths
$(SRCROOT)/…/…/cocos2d-js/frameworks/js-bindings/external/spidermonkey/prebuilt/ios

User header search paths
$(SRCROOT)/…/…/cocos2d-js/frameworks/js-bindings/external/spidermonkey/include/ios
$(SRCROOT)/…/…/cocos2d-js/frameworks/js-bindings/cocos2d-x/cocos/2d/platform/ios

I have also added libjs_static.a under “Link binary with libraries”

What else should I do to compile the bindings in my project?

@smshuja

Sorry, it’s true that this document must be updated, I will do it very soon.

For your issue, can you try to do this:

void register_test_manual_functions(JSContext *cx, JSObject *obj) {
    JS::RootedValue  nsval(cx);
    JS::RootedObject ns(cx);
    JS_GetProperty(cx, obj, "ek", &nsval);
    if (nsval == JSVAL_VOID) {
        ns = JS_NewObject(cx, NULL, NULL, NULL);
        nsval = OBJECT_TO_JSVAL(ns);
        JS_SetProperty(cx, obj, "ek", nsval);
    } else {
        JS_ValueToObject(cx, nsval, &ns);
    }
    // Pass the RootedObject to JSObject
    obj = ns;
    JS_DefineFunction(cx, obj, "_doesObjectExist", JSB_ekDoesObjectExist, 1, JSPROP_READONLY | JSPROP_PERMANENT );
}

Huabin

@pandamicro I didn’t add extra code. Just add this single line:
JS::Rooted nsval(cx);
in debug mode and it will report linking error.
BTW, I’ve got it through in release mode. As cocos2d-js 3.0 doesn’t support 64bit release mode, I have to switch to 32bit mode and release it.
And it works!
The strange thing is, if I write the same code and do the binding in the jsb library it will not report error. But if I write code and do the binding in the project’s folder(e.g… classes folder), it will report error if I don’t use release mode.

js::IsInRequest is only available in release mode, that’s why you don’t get any error in release mode.
Our spider monkey have been compiled in release mode, but it defined an DEBUG preprocessor macro, you need to remove it from the project settings.

Find preprocessor macro in the build settings of your project, if you find a macro named DEBUG, you should remove it.
Try to test if it works for you, if not, please keep us noticed.

Can you check this

on Oct 31, 2013
js::IsInRequest is defined in RELEASE mode as well

Feb 06, 2014
the change is reversed when spidermonkey from firefox v27 was updated.

I think this is the reason why it works in release mode only

@pandamicro thx! It worked!

@pandamicro one more question: do I still have to retain and release to do the memory management with the js binding I created?

@dunadain

Retain is necessary only when you create an object for future usage. And if you call retain of an object, you must release it yourself.

Huabin

I have the same question about how to manually create usb in cocos2dx 3.0. I don’t know how to update the JSB_AUTO.cpp for cocos2d-js version 3.0. Is there any template or example to demonstrate how to work?

AppDelegate.cpp:106:25: error:
cannot initialize a parameter of type ‘sc_register_sth’ (aka ‘void
(*)(JSContext *, Handle<JSObject *>)’) with an lvalue of type ‘void
(JSContext *, JSObject *)’: type mismatch at 2nd parameter
(‘JS::HandleObject’ (aka ‘Handle<JSObject *>’) vs ‘JSObject *’)
sc->addRegisterCallback(register_all);
i have this error !!
Can u help me please

A demo may help you

It’s expecting Handle<JSObject*>, not JSObject*.

Use the official way to use a HandleObject and register your callbacks.

void register_my_funcs(JSContext* cx, JS::HandleObject obj) {
JSFunctionSpec js_my_functions[] = {
JS_FS(“myFunc1”, myFunc1, 1, 0),
JS_FS_END
};

JS_DefineFunctions(cx, obj, js_my_functions);

}

And then in the AppDelegate::applicationDidFinishLaunching, do the official registration:

sc->addRegisterCallback(register_my_funcs);

Hope this is helpful to you guys.