N久之前的一个坑——用 Node.js 来重构 NBUT 的 Online Judge,包括评测端也得重构一遍。(至于什么时候完成大家就不要关心了,(/‵Д′)/~ ╧╧
总之我们现在要做的其实简而言之就是——用C/C++来实现 Node.js 的模块。
准备工作
工欲善其事,必先~~耍流氓~~利其器。
node-gyp
首先你需要一个 node-gyp 模块。
在任意角落,执行:
$ npm install node-gyp -g
在进行一系列的 blahblah 之后,你就安装好了。
Python
然后你需要有个 python 环境。
自己去官网搞一个来。
注意: 根据 node-gyp 的GitHub显示,请务必保证你的 python 版本介于 2.5.0 和 3.0.0 之间。
编译环境
嘛嘛,我就偷懒点不细写了,还请自己移步到 node-gyp 去看编译器的需求。并且倒腾好。
入门
我就拿官网的入门 Hello World说事儿了。
Hello World
请准备一个 C++ 文件,比如就叫 ~~sb.cc~~ hello.cc。
然后我们一步步来,先往里面搞出头文件和定义好命名空间:
#include
#include
using namespace v8;
主要函数
接下去我们写一个函数,其返回值是 Handle
Handle
{
//... 嗷嗷待写
}
然后我来粗粗解析一下这些东西:
Handle
做人要有节操,我事先申明我是从这里(@fool)参考的。
V8 里使用 Handle 类型来托管 JavaScript 对象,与 C++ 的 std::sharedpointer 类似,Handle 类型间的赋值均是直接传递对象引用,但不同的是,V8 使用自己的 GC 来管理对象生命周期,而不是智能指针常用的引用计数。
JavaScript 类型在 C++ 中均有对应的自定义类型,如 String 、 Integer 、 Object 、 Date 、 Array 等,严格遵守在 JavaScript 中的继承关系。 C++ 中使用这些类型时,必须使用 Handle 托管,以使用 GC 来管理它们的生命周期,而不使用原生栈和堆。
而这个所谓的 Value ,从 V8 引擎的头文件 v8.h 中的各种继承关系中可以看出来,其实就是 JavaScript 中各种对象的基类。
在了解了这件事之后,我们大致能明白上面那段函数的申明的意思就是说,我们写一个 Hello 函数,其返回的是一个不定类型的值。
注意: 我们只能返回特定的类型,即在 Handle 托管下的 String 啊 Integer 啊等等等等。
Arguments
这个就是传入这个函数的参数了。我们都知道在 Node.js 中,参数个数是乱来的。而这些参数传进去到 C++ 中的时候,就转变成了这个 Arguments 类型的对象了。
具体的用法我们在后面再说,在这里只需要明白这个是个什么东西就好。(为毛要卖关子?因为 Node.js 官方文档中的例子就是分开来讲的,我现在只是讲第一个 Hello World 的例子而已( ´థ౪థ)σ
添砖加瓦
接下去我们就开始添砖加瓦了。就最简单的两句话:
Handle
{
HandleScope scope;
return scope.Close(String::New("world"));
}
这两句话是什么意思呢?大致的意思就是返回一个 Node.js 中的字符串 "world"。
HandleScope
同参考自这里。
Handle 的生命周期和 C++ 智能指针不同,并不是在 C++ 语义的 scope 内生存(即{} 包围的部分),而需要通过 HandleScope 手动指定。HandleScope 只能分配在栈上,HandleScope 对象声明后,其后建立的 Handle 都由 HandleScope 来管理生命周期,HandleScope 对象析构后,其管理的 Handle 将由 GC 判断是否回收。
所以呢,我们得在需要管理他的生命周期的时候申明这个 Scope 。好的,那么为什么我们的代码不这么写呢?
Handle
{
HandleScope scope;
return String::New("world");
}
因为当函数返回时,scope 会被析构,其管理的Handle也都将被回收,所以这个 String 就会变得没有意义。
所以呢 V8 就想出了个神奇的点子——HandleScope::Close(Handle
于是就有了我们之前的代码 scope.Close(String::New("world"));。
String::New
这个 String 类所对应的就是 Node.js 中原生的字符串类。继承自 Value 类。与此类似,还有:
•Array
•Integer
•Boolean
•Object
•Date
•Number
•Function
•...
这些东西有些是继承自 Value,有些是二次继承。我们这里就不多做研究,自己可以看看 V8 的代码(至少是头文件)研究研究或者看看这个手册。
而这个 New 呢?这里可以看的。就是新建一个 String 对象。
至此,这个主要函数我们就解析完毕了。
导出对象
我们来温习一下,如果是在 Node.js 里面写的话,我们怎么导出函数或者对象什么的呢?
exports.hello = function() {}
那么,在 C++ 中我们该如何做到这一步呢?
初始化函数
首先,我们写个初始化函数:
void init(Handle
这是龟腚!函数名什么的无所谓,但是传入的参数一定是一个 Handle
然后,我们就在这里面写上导出的东西了:
void init(Handle
大致的意思就是说,为这个 exports 对象添加一个字段叫 hello,所对应的东西是一个函数,而这个函数就是我们亲爱的 Hello 函数了。
用伪代码写直白点就是:
void init(Handle
大功告成!
(大功告成你妹啊!闭嘴( ‘д‘⊂彡☆))Д´)
真·导出
这才是最后一步,我们最后要申明,这个就是导出的入口,所以我们在代码的末尾加上这一行:
NODE_MODULE(hello, init)
纳了个尼?!这又是什么东西?
别着急,这个 NODE_MODULE 是一个宏,它的意思呢就是说我们采用 init 这个初始化函数来把要导出的东西导出到 hello 中。那么这个 hello 哪来呢?
它来自文件名!对,没错,它来自文件名。你并不需要事先申明它,你也不必担心不能用,总之你的这个最终编译好的二进制文件名叫什么,这里的 hello 你就填什么,当然要除去后缀名了。
详见官方文档。
Note that all Node addons must export an initialization function:
void Initialize (Handle
There is no semi-colon after NODE_MODULE as it's not a function (see node.h).
The module_name needs to match the filename of the final binary (minus the .node suffix).
编译 (๑•́ ₃ •̀๑)
来吧,让我们一起编译吧!
我们再新建一个类似于 Makefile 的归档文件吧——binding.gyp。
并且在里面添加这样的代码:
{
"targets": [
{
"target_name": "hello",
"sources": [ "hello.cc" ]
}
]
}
为什么这么写呢?可以参考 node-gyp 的官方文档。
configure
在文件搞好之后,我们要在这个目录下面执行这个命令了:
$ node-gyp configure
如果一切正常的话,应该会生成一个 build 的目录,然后里面有相关文件,也许是 M$ Visual Studio 的 vcxproj 文件等,也许是 Makefile ,视平台而定。
build
Makefile 也生成好之后,我们就开始构造编译了:
$ node-gyp build
等到一切编译完成,才算是真正的大功告成了!不信你去看看 build/Release 目录,下面是不是有一个 hello.node 文件了?没错,这个就是 C++ 等下要给 Node.js 捡的肥皂!
搞基吧!Node ヽ(✿゚▽゚)ノ C++
我们在刚才那个目录下新建一个文件 jianfeizao.js:
var addon = require("./build/Release/hello");
console.log(addon.hello());
看到没!看到没!出来了出来了!Node.js 和 C++ 搞基的结果!这个 addon.hello() 就是我们之前在 C++ 代码中写的 Handle
洗洗睡吧,下节更深入
时间不早了,今天就写到这里了,至此为止大家都能搞出最基础的 Hello world 的 C++ 扩展了吧。下一次写的应该会更深入一点,至于下一次是什么时候,我也不知道啦其实。
(喂喂喂,撸主怎么可以这么不负责!(o゚ロ゚)┌┛Σ(ノ´ω`)ノ

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。

Python和JavaScript的未来趋势包括:1.Python将巩固在科学计算和AI领域的地位,2.JavaScript将推动Web技术发展,3.跨平台开发将成为热门,4.性能优化将是重点。两者都将继续在各自领域扩展应用场景,并在性能上有更多突破。

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。

是的,JavaScript的引擎核心是用C语言编写的。1)C语言提供了高效性能和底层控制,适合JavaScript引擎的开发。2)以V8引擎为例,其核心用C 编写,结合了C的效率和面向对象特性。3)JavaScript引擎的工作原理包括解析、编译和执行,C语言在这些过程中发挥关键作用。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

Atom编辑器mac版下载
最流行的的开源编辑器

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3 英文版
推荐:为Win版本,支持代码提示!