343 lines
18 KiB
HTML
343 lines
18 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width">
|
|
<meta name="nodejs.org:node-version" content="v12.22.12">
|
|
<title>C++ Embedder API | Node.js v12.22.12 Documentation</title>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic&display=fallback">
|
|
<link rel="stylesheet" href="assets/style.css">
|
|
<link rel="stylesheet" href="assets/hljs.css">
|
|
<link rel="canonical" href="https://nodejs.org/api/embedding.html">
|
|
</head>
|
|
<body class="alt apidoc" id="api-section-embedding">
|
|
<div id="content" class="clearfix">
|
|
<div id="column2" class="interior">
|
|
<div id="intro" class="interior">
|
|
<a href="/" title="Go back to the home page">
|
|
Node.js
|
|
</a>
|
|
</div>
|
|
<ul>
|
|
<li><a href="documentation.html" class="nav-documentation">About this documentation</a></li>
|
|
<li><a href="synopsis.html" class="nav-synopsis">Usage and example</a></li>
|
|
</ul>
|
|
<hr class="line">
|
|
<ul>
|
|
<li><a href="assert.html" class="nav-assert">Assertion testing</a></li>
|
|
<li><a href="async_hooks.html" class="nav-async_hooks">Async hooks</a></li>
|
|
<li><a href="buffer.html" class="nav-buffer">Buffer</a></li>
|
|
<li><a href="addons.html" class="nav-addons">C++ Addons</a></li>
|
|
<li><a href="n-api.html" class="nav-n-api">C/C++ Addons with N-API</a></li>
|
|
<li><a href="embedding.html" class="nav-embedding active">C++ Embedder API</a></li>
|
|
<li><a href="child_process.html" class="nav-child_process">Child Processes</a></li>
|
|
<li><a href="cluster.html" class="nav-cluster">Cluster</a></li>
|
|
<li><a href="cli.html" class="nav-cli">Command line options</a></li>
|
|
<li><a href="console.html" class="nav-console">Console</a></li>
|
|
<li><a href="crypto.html" class="nav-crypto">Crypto</a></li>
|
|
<li><a href="debugger.html" class="nav-debugger">Debugger</a></li>
|
|
<li><a href="deprecations.html" class="nav-deprecations">Deprecated APIs</a></li>
|
|
<li><a href="dns.html" class="nav-dns">DNS</a></li>
|
|
<li><a href="domain.html" class="nav-domain">Domain</a></li>
|
|
<li><a href="errors.html" class="nav-errors">Errors</a></li>
|
|
<li><a href="events.html" class="nav-events">Events</a></li>
|
|
<li><a href="fs.html" class="nav-fs">File system</a></li>
|
|
<li><a href="globals.html" class="nav-globals">Globals</a></li>
|
|
<li><a href="http.html" class="nav-http">HTTP</a></li>
|
|
<li><a href="http2.html" class="nav-http2">HTTP/2</a></li>
|
|
<li><a href="https.html" class="nav-https">HTTPS</a></li>
|
|
<li><a href="inspector.html" class="nav-inspector">Inspector</a></li>
|
|
<li><a href="intl.html" class="nav-intl">Internationalization</a></li>
|
|
<li><a href="modules.html" class="nav-modules">Modules: CommonJS modules</a></li>
|
|
<li><a href="esm.html" class="nav-esm">Modules: ECMAScript modules</a></li>
|
|
<li><a href="module.html" class="nav-module">Modules: <code>module</code> API</a></li>
|
|
<li><a href="packages.html" class="nav-packages">Modules: Packages</a></li>
|
|
<li><a href="net.html" class="nav-net">Net</a></li>
|
|
<li><a href="os.html" class="nav-os">OS</a></li>
|
|
<li><a href="path.html" class="nav-path">Path</a></li>
|
|
<li><a href="perf_hooks.html" class="nav-perf_hooks">Performance hooks</a></li>
|
|
<li><a href="policy.html" class="nav-policy">Policies</a></li>
|
|
<li><a href="process.html" class="nav-process">Process</a></li>
|
|
<li><a href="punycode.html" class="nav-punycode">Punycode</a></li>
|
|
<li><a href="querystring.html" class="nav-querystring">Query strings</a></li>
|
|
<li><a href="readline.html" class="nav-readline">Readline</a></li>
|
|
<li><a href="repl.html" class="nav-repl">REPL</a></li>
|
|
<li><a href="report.html" class="nav-report">Report</a></li>
|
|
<li><a href="stream.html" class="nav-stream">Stream</a></li>
|
|
<li><a href="string_decoder.html" class="nav-string_decoder">String decoder</a></li>
|
|
<li><a href="timers.html" class="nav-timers">Timers</a></li>
|
|
<li><a href="tls.html" class="nav-tls">TLS/SSL</a></li>
|
|
<li><a href="tracing.html" class="nav-tracing">Trace events</a></li>
|
|
<li><a href="tty.html" class="nav-tty">TTY</a></li>
|
|
<li><a href="dgram.html" class="nav-dgram">UDP/datagram</a></li>
|
|
<li><a href="url.html" class="nav-url">URL</a></li>
|
|
<li><a href="util.html" class="nav-util">Utilities</a></li>
|
|
<li><a href="v8.html" class="nav-v8">V8</a></li>
|
|
<li><a href="vm.html" class="nav-vm">VM</a></li>
|
|
<li><a href="wasi.html" class="nav-wasi">WASI</a></li>
|
|
<li><a href="worker_threads.html" class="nav-worker_threads">Worker threads</a></li>
|
|
<li><a href="zlib.html" class="nav-zlib">Zlib</a></li>
|
|
</ul>
|
|
<hr class="line">
|
|
<ul>
|
|
<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">Code repository and issue tracker</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="column1" data-id="embedding" class="interior">
|
|
<header>
|
|
<h1>Node.js v12.22.12 Documentation</h1>
|
|
<div id="gtoc">
|
|
<ul>
|
|
<li>
|
|
<a href="index.html">Index</a>
|
|
</li>
|
|
<li>
|
|
<a href="all.html">View on single page</a>
|
|
</li>
|
|
<li>
|
|
<a href="embedding.json">View as JSON</a>
|
|
</li>
|
|
|
|
<li class="version-picker">
|
|
<a href="#">View another version <span>▼</span></a>
|
|
<ol class="version-picker"><li><a href="https://nodejs.org/docs/latest-v17.x/api/embedding.html">17.x</a></li>
|
|
<li><a href="https://nodejs.org/docs/latest-v16.x/api/embedding.html">16.x <b>LTS</b></a></li>
|
|
<li><a href="https://nodejs.org/docs/latest-v15.x/api/embedding.html">15.x</a></li>
|
|
<li><a href="https://nodejs.org/docs/latest-v14.x/api/embedding.html">14.x <b>LTS</b></a></li>
|
|
<li><a href="https://nodejs.org/docs/latest-v13.x/api/embedding.html">13.x</a></li>
|
|
<li><a href="https://nodejs.org/docs/latest-v12.x/api/embedding.html">12.x <b>LTS</b></a></li></ol>
|
|
</li>
|
|
|
|
<li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/master/doc/api/embedding.md"><span class="github_icon"><svg height="16" width="16" viewBox="0 0 16.1 16.1" fill="currentColor"><path d="M8 0a8 8 0 0 0-2.5 15.6c.4 0 .5-.2.5-.4v-1.5c-2 .4-2.5-.5-2.7-1 0-.1-.5-.9-.8-1-.3-.2-.7-.6 0-.6.6 0 1 .6 1.2.8.7 1.2 1.9 1 2.4.7 0-.5.2-.9.5-1-1.8-.3-3.7-1-3.7-4 0-.9.3-1.6.8-2.2 0-.2-.3-1 .1-2 0 0 .7-.3 2.2.7a7.4 7.4 0 0 1 4 0c1.5-1 2.2-.8 2.2-.8.5 1.1.2 2 .1 2.1.5.6.8 1.3.8 2.2 0 3-1.9 3.7-3.6 4 .3.2.5.7.5 1.4v2.2c0 .2.1.5.5.4A8 8 0 0 0 16 8a8 8 0 0 0-8-8z"/></svg></span>Edit on GitHub</a></li>
|
|
</ul>
|
|
</div>
|
|
<hr>
|
|
</header>
|
|
|
|
<div id="toc">
|
|
<h2>Table of Contents</h2>
|
|
<ul>
|
|
<li><a href="#embedding_c_embedder_api">C++ Embedder API</a>
|
|
<ul>
|
|
<li><a href="#embedding_example_embedding_application">Example embedding application</a>
|
|
<ul>
|
|
<li><a href="#embedding_setting_up_per_process_state">Setting up per-process state</a></li>
|
|
<li><a href="#embedding_per_instance_state">Per-instance state</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="apicontent">
|
|
<h1>C++ Embedder API<span><a class="mark" href="#embedding_c_embedder_api" id="embedding_c_embedder_api">#</a></span></h1>
|
|
|
|
<p>Node.js provides a number of C++ APIs that can be used to execute JavaScript
|
|
in a Node.js environment from other C++ software.</p>
|
|
<p>The documentation for these APIs can be found in <a href="https://github.com/nodejs/node/blob/master/src/node.h">src/node.h</a> in the Node.js
|
|
source tree. In addition to the APIs exposed by Node.js, some required concepts
|
|
are provided by the V8 embedder API.</p>
|
|
<p>Because using Node.js as an embedded library is different from writing code
|
|
that is executed by Node.js, breaking changes do not follow typical Node.js
|
|
<a href="deprecations.html">deprecation policy</a> and may occur on each semver-major release without prior
|
|
warning.</p>
|
|
<h2>Example embedding application<span><a class="mark" href="#embedding_example_embedding_application" id="embedding_example_embedding_application">#</a></span></h2>
|
|
<p>The following sections will provide an overview over how to use these APIs
|
|
to create an application from scratch that will perform the equivalent of
|
|
<code>node -e <code></code>, i.e. that will take a piece of JavaScript and run it in
|
|
a Node.js-specific environment.</p>
|
|
<p>The full code can be found <a href="https://github.com/nodejs/node/blob/master/test/embedding/embedtest.cc">in the Node.js source tree</a>.</p>
|
|
<h3>Setting up per-process state<span><a class="mark" href="#embedding_setting_up_per_process_state" id="embedding_setting_up_per_process_state">#</a></span></h3>
|
|
<p>Node.js requires some per-process state management in order to run:</p>
|
|
<ul>
|
|
<li>Arguments parsing for Node.js <a href="cli.html">CLI options</a>,</li>
|
|
<li>V8 per-process requirements, such as a <code>v8::Platform</code> instance.</li>
|
|
</ul>
|
|
<p>The following example shows how these can be set up. Some class names are from
|
|
the <code>node</code> and <code>v8</code> C++ namespaces, respectively.</p>
|
|
<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span>** argv)</span> </span>{
|
|
argv = uv_setup_args(argc, argv);
|
|
<span class="hljs-function"><span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span><<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>> <span class="hljs-title">args</span><span class="hljs-params">(argv, argv + argc)</span></span>;
|
|
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span><<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>> exec_args;
|
|
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span><<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>> errors;
|
|
<span class="hljs-comment">// Parse Node.js CLI options, and print any errors that have occurred while</span>
|
|
<span class="hljs-comment">// trying to parse them.</span>
|
|
<span class="hljs-keyword">int</span> exit_code = node::InitializeNodeWithArgs(&args, &exec_args, &errors);
|
|
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>& error : errors)
|
|
<span class="hljs-built_in">fprintf</span>(<span class="hljs-built_in">stderr</span>, <span class="hljs-string">"%s: %s\n"</span>, args[<span class="hljs-number">0</span>].c_str(), error.c_str());
|
|
<span class="hljs-keyword">if</span> (exit_code != <span class="hljs-number">0</span>) {
|
|
<span class="hljs-keyword">return</span> exit_code;
|
|
}
|
|
|
|
<span class="hljs-comment">// Create a v8::Platform instance. `MultiIsolatePlatform::Create()` is a way</span>
|
|
<span class="hljs-comment">// to create a v8::Platform instance that Node.js can use when creating</span>
|
|
<span class="hljs-comment">// Worker threads. When no `MultiIsolatePlatform` instance is present,</span>
|
|
<span class="hljs-comment">// Worker threads are disabled.</span>
|
|
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">unique_ptr</span><MultiIsolatePlatform> platform =
|
|
MultiIsolatePlatform::Create(<span class="hljs-number">4</span>);
|
|
V8::InitializePlatform(platform.get());
|
|
V8::Initialize();
|
|
|
|
<span class="hljs-comment">// See below for the contents of this function.</span>
|
|
<span class="hljs-keyword">int</span> ret = RunNodeInstance(platform.get(), args, exec_args);
|
|
|
|
V8::Dispose();
|
|
V8::ShutdownPlatform();
|
|
<span class="hljs-keyword">return</span> ret;
|
|
}</code></pre>
|
|
<h3>Per-instance state<span><a class="mark" href="#embedding_per_instance_state" id="embedding_per_instance_state">#</a></span></h3>
|
|
<p>Node.js has a concept of a “Node.js instance”, that is commonly being referred
|
|
to as <code>node::Environment</code>. Each <code>node::Environment</code> is associated with:</p>
|
|
<ul>
|
|
<li>Exactly one <code>v8::Isolate</code>, i.e. one JS Engine instance,</li>
|
|
<li>Exactly one <code>uv_loop_t</code>, i.e. one event loop, and</li>
|
|
<li>A number of <code>v8::Context</code>s, but exactly one main <code>v8::Context</code>.</li>
|
|
<li>One <code>node::IsolateData</code> instance that contains information that could be
|
|
shared by multiple <code>node::Environment</code>s that use the same <code>v8::Isolate</code>.
|
|
Currently, no testing if performed for this scenario.</li>
|
|
</ul>
|
|
<p>In order to set up a <code>v8::Isolate</code>, an <code>v8::ArrayBuffer::Allocator</code> needs
|
|
to be provided. One possible choice is the default Node.js allocator, which
|
|
can be created through <code>node::ArrayBufferAllocator::Create()</code>. Using the Node.js
|
|
allocator allows minor performance optimizations when addons use the Node.js
|
|
C++ <code>Buffer</code> API, and is required in order to track <code>ArrayBuffer</code> memory in
|
|
<a href="process.html#process_process_memoryusage"><code>process.memoryUsage()</code></a>.</p>
|
|
<p>Additionally, each <code>v8::Isolate</code> that is used for a Node.js instance needs to
|
|
be registered and unregistered with the <code>MultiIsolatePlatform</code> instance, if one
|
|
is being used, in order for the platform to know which event loop to use
|
|
for tasks scheduled by the <code>v8::Isolate</code>.</p>
|
|
<p>The <code>node::NewIsolate()</code> helper function creates a <code>v8::Isolate</code>,
|
|
sets it up with some Node.js-specific hooks (e.g. the Node.js error handler),
|
|
and registers it with the platform automatically.</p>
|
|
<pre><code class="language-cpp">int RunNodeInstance(MultiIsolatePlatform* platform,
|
|
const std::vector<std::string>& args,
|
|
const std::vector<std::string>& exec_args) {
|
|
int exit_code = 0;
|
|
// Set up a libuv event loop.
|
|
uv_loop_t loop;
|
|
int ret = uv_loop_init(&loop);
|
|
if (ret != 0) {
|
|
fprintf(stderr, "%s: Failed to initialize loop: %s\n",
|
|
args[0].c_str(),
|
|
uv_err_name(ret));
|
|
return 1;
|
|
}
|
|
|
|
std::shared_ptr<ArrayBufferAllocator> allocator =
|
|
ArrayBufferAllocator::Create();
|
|
|
|
Isolate* isolate = NewIsolate(allocator, &loop, platform);
|
|
if (isolate == nullptr) {
|
|
fprintf(stderr, "%s: Failed to initialize V8 Isolate\n", args[0].c_str());
|
|
return 1;
|
|
}
|
|
|
|
{
|
|
Locker locker(isolate);
|
|
Isolate::Scope isolate_scope(isolate);
|
|
|
|
// Create a node::IsolateData instance that will later be released using
|
|
// node::FreeIsolateData().
|
|
std::unique_ptr<IsolateData, decltype(&node::FreeIsolateData)> isolate_data(
|
|
node::CreateIsolateData(isolate, &loop, platform, allocator.get()),
|
|
node::FreeIsolateData);
|
|
|
|
// Set up a new v8::Context.
|
|
HandleScope handle_scope(isolate);
|
|
Local<Context> context = node::NewContext(isolate);
|
|
if (context.IsEmpty()) {
|
|
fprintf(stderr, "%s: Failed to initialize V8 Context\n", args[0].c_str());
|
|
return 1;
|
|
}
|
|
|
|
// The v8::Context needs to be entered when node::CreateEnvironment() and
|
|
// node::LoadEnvironment() are being called.
|
|
Context::Scope context_scope(context);
|
|
|
|
// Create a node::Environment instance that will later be released using
|
|
// node::FreeEnvironment().
|
|
std::unique_ptr<Environment, decltype(&node::FreeEnvironment)> env(
|
|
node::CreateEnvironment(isolate_data.get(), context, args, exec_args),
|
|
node::FreeEnvironment);
|
|
|
|
// Set up the Node.js instance for execution, and run code inside of it.
|
|
// There is also a variant that takes a callback and provides it with
|
|
// the `require` and `process` objects, so that it can manually compile
|
|
// and run scripts as needed.
|
|
// The `require` function inside this script does *not* access the file
|
|
// system, and can only load built-in Node.js modules.
|
|
// `module.createRequire()` is being used to create one that is able to
|
|
// load files from the disk, and uses the standard CommonJS file loader
|
|
// instead of the internal-only `require` function.
|
|
MaybeLocal<Value> loadenv_ret = node::LoadEnvironment(
|
|
env.get(),
|
|
"const publicRequire ="
|
|
" require('module').createRequire(process.cwd() + '/');"
|
|
"globalThis.require = publicRequire;"
|
|
"require('vm').runInThisContext(process.argv[1]);");
|
|
|
|
if (loadenv_ret.IsEmpty()) // There has been a JS exception.
|
|
return 1;
|
|
|
|
{
|
|
// SealHandleScope protects against handle leaks from callbacks.
|
|
SealHandleScope seal(isolate);
|
|
bool more;
|
|
do {
|
|
uv_run(&loop, UV_RUN_DEFAULT);
|
|
|
|
// V8 tasks on background threads may end up scheduling new tasks in the
|
|
// foreground, which in turn can keep the event loop going. For example,
|
|
// WebAssembly.compile() may do so.
|
|
platform->DrainTasks(isolate);
|
|
|
|
// If there are new tasks, continue.
|
|
more = uv_loop_alive(&loop);
|
|
if (more) continue;
|
|
|
|
// node::EmitBeforeExit() is used to emit the 'beforeExit' event on
|
|
// the `process` object.
|
|
node::EmitBeforeExit(env.get());
|
|
|
|
// 'beforeExit' can also schedule new work that keeps the event loop
|
|
// running.
|
|
more = uv_loop_alive(&loop);
|
|
} while (more == true);
|
|
}
|
|
|
|
// node::EmitExit() returns the current exit code.
|
|
exit_code = node::EmitExit(env.get());
|
|
|
|
// node::Stop() can be used to explicitly stop the event loop and keep
|
|
// further JavaScript from running. It can be called from any thread,
|
|
// and will act like worker.terminate() if called from another thread.
|
|
node::Stop(env.get());
|
|
}
|
|
|
|
// Unregister the Isolate with the platform and add a listener that is called
|
|
// when the Platform is done cleaning up any state it had associated with
|
|
// the Isolate.
|
|
bool platform_finished = false;
|
|
platform->AddIsolateFinishedCallback(isolate, [](void* data) {
|
|
*static_cast<bool*>(data) = true;
|
|
}, &platform_finished);
|
|
platform->UnregisterIsolate(isolate);
|
|
isolate->Dispose();
|
|
|
|
// Wait until the platform has cleaned up all relevant resources.
|
|
while (!platform_finished)
|
|
uv_run(&loop, UV_RUN_ONCE);
|
|
int err = uv_loop_close(&loop);
|
|
assert(err == 0);
|
|
|
|
return exit_code;
|
|
}</code></pre>
|
|
<!-- API END -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|