c++ - 如何在 spidermonkey 嵌入中提供 js-ctypes?

标签 c++ c gcc spidermonkey jsctypes

总结

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


疯狂的方法

Mozilla 开发人员的这个 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' 中被声明为外部,但该函数驻留在 'ctypes/CTypes.cpp' 中,它包含它自己的头文件 'CTypes.h' 并在某些时候由某些命令编译'make' 生成 './CTypes.o'。正如我之前所说,我不是 C 代码的新手,我真的不知道该做什么。

请给出或给出使 js-ctypes 对象在嵌入中起作用的通用示例的方向。

最佳答案

黑客攻击

我已经想到链接失败是因为头文件中的条件定义以及分散的库和头文件位置。好吧...我尝试在命令行上定义 JS_HAS_CTYPES,但如果它能正常工作,那肯定是不够的。

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

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


汇编

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

虽然以下命令似乎呈现可操作的二进制文件,但作者无法证明此 list 的正确性或完整性。

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。您可能需要也可能不需要按顺序重新创建这些步骤,但从我目前的角度来看,强烈建议这样做。

关于c++ - 如何在 spidermonkey 嵌入中提供 js-ctypes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9457648/

相关文章:

c++ - 成员 "extra qualification ‘student::’ [-fpermissive] 上的错误 ‘student’ “

c++ - 为什么这个 cin 不能正常工作?

c++ - char 输入使循环在 C++ 中不停止

c++ - 从堆栈地址形成指针范围是未定义的行为吗?

c++ - 有没有办法在 AVX 上模拟 _m256 类型的整数按位运算?

c++ - 在 GCC 中将 C++ 链接到 C

c++ - 无法在 C++ OpenCV HSV 图像分离中分离对象

在 Linux 上使用 AMD APP SDK 编译/构建 OpenCL 程序

c - 是否可以从 gcc 的 C 源代码中链接到数学库?

c++ - 为什么在 GCC 4.4.1 中我不能在函数模板中声明默认参数?