【问题标题】:How to provide js-ctypes in a spidermonkey embedding?如何在蜘蛛猴嵌入中提供 js-ctypes?
【发布时间】:2012-02-26 22:08:45
【问题描述】:

总结

我已经查看了 SpiderMonkey 'shell' 应用程序用来创建 ctypes JavaScript 对象的代码,但我不是一个新手 C 程序员。由于现代构建系统发出的疯狂程度不同,我似乎无法追踪实际将程序与所需功能联系起来的代码或命令。


method.madness

Mozilla Devs 的这个 js-ctypes 实现是一个很棒的补充。从它的概念开始,脚本就主要用于对更严格和更健壮的应用程序进行控制。 SpiderMonkey 项目中 js-ctypes 的出现,使 JavaScript 能够站起来,并被视为一种成熟的面向对象的快速应用程序开发语言,高出各种古老的应用程序开发语言(如 Microsoft 的 VB6)设定的“标准”。


我们开始吧?

我使用以下配置构建了 SpiderMonkey:./configure --enable-ctypes --with-system-nspr

随后成功执行:make && make install

js shell 工作正常,并且已验证全局 ctypes javascript 对象在该 shell 中可操作。

使用来自How to embed the JavaScript Engine -MDN 的第一个源代码列表中的代码,我尝试通过在第 66 行插入以下代码来实例化 JavaScript ctypes 对象:

    /* Populate the global object with the ctypes object. */
    if (!JS_InitCTypesClass(cx, global))
        return NULL;
    /*

我编译时使用:g++ $(./js-config --cflags --libs) hello.cpp -o hello

编译时有一些警告:

hello.cpp: In function ‘int main(int, const char**)’:
hello.cpp:69:16: warning: converting to non-pointer type ‘int’ from NULL [-Wconversion-null]
hello.cpp:80:20: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
hello.cpp:89:17: warning: NULL used in arithmetic [-Wpointer-arith]

但是当你运行应用程序时:

./hello: symbol lookup error: ./hello: undefined symbol: JS_InitCTypesClass

此外

JS_InitCTypesClass 在 'dist/include/jsapi.h' 中声明为 extern,但该函数驻留在 'ctypes/CTypes.cpp' 中,其中包含自己的头文件 'CTypes.h' 并在某个时间点由某些命令编译'make' 产生 './CTypes.o'。正如我之前所说,我对 C 代码还不是新手,我真的不知道在这里做什么。

请给出或指导一个使 js-ctypes 对象在嵌入中起作用的通用示例。

【问题讨论】:

    标签: c++ c gcc spidermonkey jsctypes


    【解决方案1】:

    黑客攻击

    我已经想到,由于头文件中的条件定义以及分散的库和头文件位置,链接失败。好吧...我尝试在命令行上定义 JS_HAS_CTYPES,但如果它确实有效,那肯定是不够的。

    我决定,因为 SpiderMonkey shell 有自己独特的 makefile,并且已经可以访问我试图捕获的功能,只需将 js.cpp 重命名为 js.cpp.tmp 并允许我的代码站在它的位置,几乎成功了。

    文件编译良好,应用程序执行时没有抛出运行时链接错误,但代码('JSNativeObject' ctypes)几乎完全失败了 JS_InitCTypesClass。看到我的链接错误早就被遗忘了,我立即查看了 make 的输出,看看我是否可以“刷”编译代码......我们有一个宾果游戏!


    汇编

    在将 shell/js.cpp 恢复到其原始目标后,我将 hello.cpp 移动到 spidermonkey 的根源目录并开始更正由 makefile 创建的相对路径以及执行删除构造显然与我的申请无关。

    虽然以下命令似乎呈现了一个可操作的二进制文件,但作者无法确定此列表的正确性或完整性。

    c++ -o hello.o -c  -Idist/system_wrappers_js -include config/gcc_hidden.h \
    -DEXPORT_JS_API -DOSTYPE=\"Linux3.2\" -DOSARCH=Linux -I. -Idist/include \
    -Idist/include/nsprpub  -I/usr/include/nspr -fPIC  -fno-rtti \
    -fno-exceptions -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth \
    -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -Wcast-align \
    -Wno-invalid-offsetof -Wno-variadic-macros -Werror=return-type -pedantic \
    -Wno-long-long -fno-strict-aliasing -pthread -pipe  -DNDEBUG -DTRIMMED -Os \
    -freorder-blocks -fomit-frame-pointer -DJS_HAS_CTYPES -DMOZILLA_CLIENT \
    -include js-confdefs.h -MD -MF .deps/hello.pp hello.cpp;
    
    c++ -o hello -fno-rtti -fno-exceptions -Wall -Wpointer-arith \
    -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy \
    -Wno-non-virtual-dtor -Wcast-align -Wno-invalid-offsetof \
    -Wno-variadic-macros -Werror=return-type -pedantic \
    -Wno-long-long -fno-strict-aliasing -pthread -pipe  -DNDEBUG \
    -DTRIMMED -Os -freorder-blocks -fomit-frame-pointer hello.o \
    -lpthread -Wl,-rpath-link,/bin -Wl,-rpath-link,/usr/local/lib \
    -Ldist/bin -Ldist/lib -L/usr/lib -lplds4 -lplc4 -lnspr4 \
    -lpthread -ldl editline/libeditline.a libjs_static.a -ldl;
    

    上面列出的两个命令被放入一个名为“mkhello”的可执行 shell 脚本中,该脚本保存在根源目录中。

    据我所知,这是一种两阶段编译方法。出于什么原因我不确定,但解释似乎很有教育意义。想法?

    编辑请参阅下面的评论以了解“两阶段编译方法”的说明。


    代码:hello.cpp

    /*
     * This define is for Windows only, it is a work-around for bug 661663.
     */
    #ifdef _MSC_VER
    # define XP_WIN
    #endif
    
    /* Include the JSAPI header file to get access to SpiderMonkey. */
    #include "jsapi.h"
    
    
    /* The class of the global object. */
    static JSClass global_class = {
        "global", JSCLASS_GLOBAL_FLAGS,
        JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
        JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
        JSCLASS_NO_OPTIONAL_MEMBERS
    };
    
    /* The error reporter callback. */
    void reportError(JSContext *cx, const char *message, JSErrorReport *report)
    {
        fprintf(stderr, "%s:%u:%s\n",
                report->filename ? report->filename : "<no filename=\"filename\">",
                (unsigned int) report->lineno,
                message);
    }
    
    int main(int argc, const char *argv[])
    {
        /* JSAPI variables. */
        JSRuntime *rt;
        JSContext *cx;
        JSObject  *global;
    
        /* Create a JS runtime. You always need at least one runtime per process. */
        rt = JS_NewRuntime(8 * 1024 * 1024);
        if (rt == NULL)
            return 1;
    
        /* 
         * Create a context. You always need a context per thread.
         * Note that this program is not multi-threaded.
         */
        cx = JS_NewContext(rt, 8192);
        if (cx == NULL)
            return 1;
        JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
        JS_SetVersion(cx, JSVERSION_LATEST);
        JS_SetErrorReporter(cx, reportError);
    
        /*
         * Create the global object in a new compartment.
         * You always need a global object per context.
         */
        global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
        if (global == NULL)
            return 1;
    
        /*
         * Populate the global object with the standard JavaScript
         * function and object classes, such as Object, Array, Date.
         */
        if (!JS_InitStandardClasses(cx, global))
            return 1;
    
        /* Populate the global object with the ctypes object. */
        if (!JS_InitCTypesClass(cx, global))
            return NULL;
        /*
    
        /* Your application code here. This may include JSAPI calls
         * to create your own custom JavaScript objects and to run scripts.
         *
         * The following example code creates a literal JavaScript script,
         * evaluates it, and prints the result to stdout.
         *
         * Errors are conventionally saved in a JSBool variable named ok.
         */
        char *script = "ctypes.open";
        jsval rval;
        JSString *str;
        JSBool ok;
        const char *filename = "noname";
        uintN lineno = 0;
    
        ok = JS_EvaluateScript(cx, global, script, strlen(script),
                               filename, lineno, &rval);
        if (rval == NULL | rval == JS_FALSE)
            return 1;
    
        str = JS_ValueToString(cx, rval);
        printf("%s\n", JS_EncodeString(cx, str));
    
        /* End of your application code */
    
        /* Clean things up and shut down SpiderMonkey. */
        JS_DestroyContext(cx);
        JS_DestroyRuntime(rt);
        JS_ShutDown();
        return 0;
    }
    

    结论

    $ ./mkhello
    # ...
    # error free garbage scrolls....
    $ ./hello
    function open() {
        [native code]
    }
    

    按照此示例为 SpiderMonkey 嵌入提供 js-ctypes。您可能需要也可能不需要按顺序重新创建这些步骤,但从我目前的角度来看,强烈建议您这样做。

    【讨论】:

    • 虽然这是一个答案,但我没有接受它作为最佳答案,以防知道该链接的人会提出正确答案。
    • '两阶段编译方法':一级编译。另一个链接。
    【解决方案2】:

    问题:大多数平台分销商对代码开发人员给出的建议一无所知。因此,在大多数(如果不是所有)托管该库的系统上,都没有为 mozjs185 启用 js-ctypes。这给您留下了一些问题需要解决。

    在您配置了 --enable-ctypes 和 --with-sytem-nspr 后跟 makemake install (可能需要 root 才能执行最后一个命令)

    您的系统上可能有两个版本的 libmozjs185.so。一个启用了 ctypes(位于 /usr/local/lib),一个没有启用 ctypes(位于 /usr/lib)。

    根据问题,您想要链接库 with ctypes。这就是您通过指定:-L/usr/local/lib -lnspr4 -lmozjs185 到您的编译器来执行的操作。它会编译好的。但是当应用程序运行时,os 库加载器将加载它找到的库的第一个实例。不幸的是,这可能是位于 /usr/lib 中的库,并且此版本可能没有启用 ctypes。这就是你会遇到这个 [已解决] 问题的地方:g++ Undefined Symbol Error using shared library

    底线是:同一个库的多个版本正在制造一个地狱般的问题。因此,将 js-ctypes 提供给 spidermonkey 嵌入的最佳方法是将启用 ctypes 的 mozjs185 静态版本链接到您的程序,除非您想编写一个用于处理多个平台库加载器的库,或者创建自己的(mozjs185 的更名版本) 我已经在@SpiderMonkey Build Documentation - MDN 上详细介绍过

    要执行静态链接,您需要在 g++ 中使用这些参数: -lnspr4 -lpthread -lmozjs185-1.0 前提是您已正确构建并安装了开发包。这是为蜘蛛猴嵌入提供 js-ctypes 的“最佳”(平台无关)方式。尽管这确实会使您的应用程序的大小至少增加 3.5 MB。如果您构建了调试版本,它可能会大 15 倍以上。

    【讨论】:

    • -lol 'libary' 我要把那个留在里面!从小就没听说过。
    猜你喜欢
    • 1970-01-01
    • 2011-04-03
    • 2013-12-18
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多