mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
476 lines
19 KiB
476 lines
19 KiB
<h1 id="gettingstarted">Getting started</h1>
|
|
|
|
<h2>Downloading</h2>
|
|
|
|
<p>Download the source distributable from the
|
|
<a href="download.html">Download</a> page.</p>
|
|
|
|
<h2>Command line tool</h2>
|
|
|
|
<p>Unpack the distributable:</p>
|
|
<pre>
|
|
$ cd /tmp
|
|
$ tar xvfJ duktape-<version>.tar.xz
|
|
</pre>
|
|
|
|
<p>Compile the command line tool using the provided Makefile:</p>
|
|
<pre>
|
|
$ cd /tmp/duktape-<version>/
|
|
$ make -f Makefile.cmdline
|
|
</pre>
|
|
|
|
<p>The Makefile assumes you have <code>gcc</code> installed. If you don't,
|
|
you can just edit the Makefile to match your compiler (the Makefile is
|
|
quite simple).</p>
|
|
|
|
<div class="note">
|
|
Duktape doesn't provide built-in bindings for file or console I/O to avoid
|
|
portability issues (for example, some platforms don't have I/O APIs at all).
|
|
The command line utility provides <code>print()</code> and <code>alert()</code>
|
|
bindings using <a href="https://github.com/svaarala/duktape/blob/master/extras/print-alert">extras/print-alert</a>
|
|
to make it easier to play with. There are useful "extras" in the distributable
|
|
providing useful (optional) bindings such as:
|
|
<ul>
|
|
<li><a href="https://github.com/svaarala/duktape/blob/master/extras/print-alert">print() and alert()</a></li>
|
|
<li><a href="https://github.com/svaarala/duktape/blob/master/extras/console">console object, e.g. console.log()</a></li>
|
|
</ul>
|
|
<b>Throughout the guide examples will assume a <code>print()</code> binding for
|
|
illustration.</b>
|
|
</div>
|
|
|
|
<div class="note">
|
|
The command line tool avoids platform dependencies by default. You can add
|
|
line editing support via <a href="https://github.com/antirez/linenoise">linenoise</a>
|
|
by editing the Makefile:
|
|
<ul>
|
|
<li>Add <code class="nobreak">-DDUK_CMDLINE_FANCY</code></li>
|
|
<li>Add <code>-Ipath/to/linenoise</code> for the <code>linenoise.h</code> header</li>
|
|
<li>Add <code>path/to/linenoise.c</code> to the source list</li>
|
|
<li>Linenoise only works in POSIX environments and requires a C compiler (not C++)</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<p>You can now run Ecmascript code interactively:</p>
|
|
<pre>
|
|
$ ./duk
|
|
((o) Duktape 1.5.0 (v1.5.0)
|
|
duk> print('Hello world!')
|
|
Hello world!
|
|
= undefined
|
|
</pre>
|
|
|
|
<p>You can also run Ecmascript code from a file which is useful for playing with
|
|
features and algorithms. As an example, create <code>fib.js</code>:</p>
|
|
<pre class="ecmascript-code" include="fib.js"></pre>
|
|
|
|
<p>Test the script from the command line:</p>
|
|
<pre>
|
|
$ ./duk fib.js
|
|
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
|
|
</pre>
|
|
|
|
<h2>Integrating Duktape into your program</h2>
|
|
|
|
<p>The command line tool is simply an example of a program which embeds
|
|
Duktape. Embedding Duktape into your program is very simple:</p>
|
|
|
|
<ul>
|
|
<li>Run <code>duktape-N.N.N/tools/configure.py</code> to configure Duktape
|
|
for build. The result is a directory containing <code>duktape.c</code>,
|
|
<code>duktape.h</code>, and <code>duk_config.h</code>.</li>
|
|
<li>Add <code>duktape.c</code>, <code>duktape.h</code>, and <code>duk_config.h</code>
|
|
to your build, and call the Duktape API from elsewhere in your program.</li>
|
|
</ul>
|
|
|
|
<p>The Duktape distributable (duktape-N.N.N.tar.xz) <code>src/</code> directory
|
|
contains preconfigured header and source files for the Duktape default configuration
|
|
which can usually be used as is. If needed, the configuration tool allows you to customize
|
|
Duktape options, such as optimizing Duktape for low memory targets and
|
|
enable/disable features. See <a href="#compiling">Compiling</a> and
|
|
<a href="http://wiki.duktape.org/Configuring.html">Configuring Duktape for build</a>
|
|
for more details and examples.</p>
|
|
|
|
<p>The distributable contains a very simple example program, <code>hello.c</code>,
|
|
which illustrates this process. Compile the test program with the preconfigured
|
|
Duktape header and source files e.g. as follows:</p>
|
|
<pre>
|
|
$ cd /tmp/duktape-<version>/
|
|
$ gcc -std=c99 -o hello -Isrc src/duktape.c examples/hello/hello.c -lm
|
|
</pre>
|
|
|
|
<p>To customize Duktape configuration use <code>configure.py</code>:</p>
|
|
<pre>
|
|
$ cd /tmp/duktape-<version>/
|
|
# Here we disable Ecmascript 6 Proxy object support
|
|
$ python2 tools/configure.py --output-directory duktape-src -UDUK_USE_ES6_PROXY
|
|
$ gcc -std=c99 -o hello -Iduktape-src duktape-src/duktape.c examples/hello/hello.c -lm
|
|
</pre>
|
|
|
|
<p>The test program creates a Duktape context and uses it to run some
|
|
Ecmascript code:</p>
|
|
<pre>
|
|
$ ./hello
|
|
Hello world!
|
|
2+3=5
|
|
</pre>
|
|
|
|
<p>Because Duktape is an embeddable engine, you don't need to change
|
|
the basic control flow of your program. The basic approach is:</p>
|
|
<ul>
|
|
<li>Create a Duktape context e.g. in program initialization
|
|
(or even on-demand when scripting is needed). Usually you
|
|
would also load your scripts during initialization, though
|
|
that can also be done on-demand.</li>
|
|
<li>Identify points in your code where you would like to use scripting
|
|
and insert calls to script functions there.</li>
|
|
<li>To make a script function call, first push call arguments to the
|
|
Duktape context's <i>value stack</i> using the Duktape API.
|
|
Then, use another Duktape API call to initiate the actual call.</li>
|
|
<li>Once script execution is finished, control is returned to your
|
|
program (the API call returns) and a return value is left on the
|
|
Duktape context's value stack. C code can then access the return
|
|
value using the Duktape API.</li>
|
|
</ul>
|
|
|
|
<p>Let's look at a simple example program. The program reads in a line from
|
|
<code>stdin</code> using a C mainloop, calls an Ecmascript helper to transform
|
|
the line, and prints out the result. The line processing function can take
|
|
advantage of Ecmascript goodies like regular expressions, and can be easily
|
|
modified without recompiling the C program.</p>
|
|
|
|
<p>The script code will be placed in <code>process.js</code>. The example
|
|
line processing function converts a plain text line into HTML, and
|
|
automatically bolds text between stars:</p>
|
|
|
|
<pre class="ecmascript-code" include="process.js"></pre>
|
|
|
|
<p>The C code, <code>processlines.c</code> initializes a Duktape context,
|
|
evaluates the script, then proceeds to process lines from <code>stdin</code>,
|
|
calling <code>processLine()</code> for every line:</p>
|
|
<pre class="c-code" include="processlines.c"></pre>
|
|
|
|
<p>Let's look at the Duktape specific parts of the example code piece by piece.
|
|
Here we need to gloss over some details for brevity, see
|
|
<a href="#programming">Programming model</a> for a detailed discussion:</p>
|
|
<ul class="breakdown"> <!-- breakdown -->
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
/* For brevity assumes a maximum file length of 16kB. */
|
|
static void push_file_as_string(duk_context *ctx, const char *filename) {
|
|
FILE *f;
|
|
size_t len;
|
|
char buf[16384];
|
|
|
|
f = fopen(filename, "rb");
|
|
if (f) {
|
|
len = fread((void *) buf, 1, sizeof(buf), f);
|
|
fclose(f);
|
|
duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
|
|
} else {
|
|
duk_push_undefined(ctx);
|
|
}
|
|
}
|
|
</pre>
|
|
<p>Because Duktape is an embeddable engine and makes minimal assumptions
|
|
there are no file I/O bindings in the default C or Ecmascript API. The
|
|
above helper is an example of how to push the contents of a file as a
|
|
string; the example uses a fixed read buffer for brevity, a better
|
|
implementation would first check the file size and then allocate a buffer
|
|
for it. The Duktape distributable includes "extras" which provide, among
|
|
other things, useful C and Ecmascript helpers, including file I/O helpers.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
ctx = duk_create_heap_default();
|
|
if (!ctx) {
|
|
printf("Failed to create a Duktape heap.\n");
|
|
exit(1);
|
|
}
|
|
</pre>
|
|
<p>First we create a Duktape context. A context allows us to exchange values
|
|
with Ecmascript code by pushing and popping values to the <b>value stack</b>.
|
|
Most calls in the Duktape API operate with the value stack, pushing, popping,
|
|
and examining values on the stack. For production code you should use
|
|
<a href="api.html#duk_create_heap">duk_create_heap()</a> so that you can set
|
|
a <b>fatal error handler</b>. See <a href="#error-handling">Error handling</a>
|
|
for discussion of error handling best practices.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
push_file_as_string(ctx, "process.js");
|
|
if (duk_peval(ctx) != 0) {
|
|
printf("Error: %s\n", duk_safe_to_string(ctx, -1));
|
|
goto finished;
|
|
}
|
|
duk_pop(ctx); /* ignore result */
|
|
</pre>
|
|
<p>First we use our file helper to push <code>process.js</code> onto the value
|
|
stack as a string. Then we use <code>duk_peval()</code> to compile and run the
|
|
script. The script registers <code>processLine()</code> into the Ecmascript
|
|
global object for later use. A <b>protected call, duk_peval(),</b> is used for
|
|
running the script so that any script errors, such as syntax errors, are caught
|
|
and handled without causing a fatal error. If an error occurs, the error message
|
|
is coerced safely using <a href="api.html#duk_safe_to_string">duk_safe_to_string()</a>
|
|
which is guaranteed not to throw a further error. The result of the string coercion
|
|
is a <code>const char *</code> pointing to a read-only, NUL-terminated, UTF-8
|
|
encoded string, which can be used directly with <code>printf</code>.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_global_object(ctx);
|
|
duk_get_prop_string(ctx, -1 /*index*/, "processLine");
|
|
</pre>
|
|
<p>The first call pushes the Ecmascript global object to the value stack.
|
|
The second call looks up <code>processLine</code> property of the global object
|
|
(which the script in <code>process.js</code> has defined). The <code>-1</code>
|
|
argument is an index to the value stack; negative values refer to stack
|
|
elements starting from the top, so <code>-1</code> refers to the topmost
|
|
element of the stack, the global object.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_string(ctx, line);
|
|
</pre>
|
|
<p>Pushes the string pointed to by <code>line</code> to the value stack. The
|
|
string length is automatically determined by scanning for a NUL terminator
|
|
(same as <code>strlen()</code>). Duktape makes a copy of the string when it is
|
|
pushed to the stack, so the <code>line</code> buffer can be freely modified when
|
|
the call returns.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
if (duk_pcall(ctx, 1 /*nargs*/) != 0) {
|
|
printf("Error: %s\n", duk_safe_to_string(ctx, -1));
|
|
} else {
|
|
printf("%s\n", duk_safe_to_string(ctx, -1));
|
|
}
|
|
duk_pop(ctx); /* pop result/error */
|
|
</pre>
|
|
<p>At this point the value stack contains: the global object, the processLine
|
|
function, and the <code>line</code> string. The
|
|
<a href="api.html#duk_pcall">duk_pcall()</a> method calls a function with a
|
|
specified number of arguments given on the value stack, and replaces both the
|
|
function and the argument values with the function's return value.
|
|
Here the resulting value stack contains: the global object and the call result.
|
|
The call is protected so that errors can be caught and printed. The
|
|
<a href="api.html#duk_safe_to_string">duk_safe_to_string()</a> API call is
|
|
again used to print errors safely. Finally, the result (or error) is popped
|
|
off the value stack.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_destroy_heap(ctx);
|
|
</pre>
|
|
<p>Destroy the Duktape context, freeing all resources held by the context.
|
|
This call will free the value stack and all references on the value stack.
|
|
In our example we left the global object on the value stack on purpose.
|
|
This is not a problem: no memory leaks will occur even if the value stack
|
|
is not empty when the heap is destroyed.</p>
|
|
</li>
|
|
|
|
</ul> <!-- breakdown -->
|
|
|
|
<p>Compile like above:</p>
|
|
<pre>
|
|
$ gcc -std=c99 -o processlines -Isrc/ src/duktape.c processlines.c -lm
|
|
</pre>
|
|
|
|
<p>Test run (ensure that <code>process.js</code> is in the current directory):</p>
|
|
<pre>
|
|
$ echo "I like *Sam & Max*." | ./processlines
|
|
I like <b>Sam &<!-- avoiding double decode is tricky -->#38; Max</b>.
|
|
</pre>
|
|
|
|
<h2>Calling C code from Ecmascript (Duktape/C bindings)</h2>
|
|
|
|
<p>The integration example illustrated how C code can call into Ecmascript
|
|
to do things which are easy in Ecmascript but difficult in C.</p>
|
|
|
|
<p>Ecmascript also often needs to call into C when the situation is
|
|
reversed. For instance, while scripting is useful for many things, it is
|
|
not optimal for low level byte or character processing. Being able to
|
|
call optimized C helpers allows you to write most of your script logic in
|
|
nice Ecmascript but call into C for the performance critical parts.
|
|
Another reason for using native functions is to provide access to native
|
|
libraries.</p>
|
|
|
|
<p>To implement a native function you write an ordinary C function which
|
|
conforms to a special calling convention, the Duktape/C binding. Duktape/C
|
|
functions take a single argument, a Duktape context, and return a single
|
|
value indicating either error or number of return values. The function
|
|
accesses call arguments and places return values through the Duktape context's
|
|
<i>value stack</i>, manipulated with the Duktape API. We'll go deeper into
|
|
Duktape/C binding and the Duktape API later on. Example:</p>
|
|
<pre class="c-code">
|
|
duk_ret_t my_native_func(duk_context *ctx) {
|
|
double arg = duk_require_number(ctx, 0 /*index*/);
|
|
duk_push_number(ctx, arg * arg);
|
|
return 1;
|
|
}
|
|
</pre>
|
|
|
|
<p>Let's look at this example line by line:</p>
|
|
<ul class="breakdown"> <!-- breakdown -->
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
double arg = duk_require_number(ctx, 0 /*index*/);
|
|
</pre>
|
|
<p>Check that the number at value stack index 0 (bottom of the stack, first
|
|
argument to function call) is a number; if not, throws an error and never
|
|
returns. If the value is a number, return it as a <code>double</code>.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_number(ctx, arg * arg);
|
|
</pre>
|
|
<p>Compute square of argument and push it to the value stack.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
return 1;
|
|
</pre>
|
|
<p>Return from the function call, indicating that there is a (single) return
|
|
value on top of the value stack. You could also return <code>0</code> to indicate
|
|
that no return value is given (in which case Duktape defaults to Ecmascript
|
|
<code>undefined</code>). A negative return value which causes an error to be
|
|
automatically thrown: this is a shorthand for throwing errors conveniently.
|
|
Note that you don't need to pop any values off the stack, Duktape will do that
|
|
for you automatically when the function returns.
|
|
See <a href="#programming">Programming model</a> for more details.</p>
|
|
</li>
|
|
|
|
</ul> <!-- breakdown -->
|
|
|
|
<p>We'll use a primality test as an example for using native code to speed
|
|
up Ecmascript algorithms. More specifically, our test program searches for
|
|
primes under 1000000 which end with the digits '9999'. The Ecmascript
|
|
version of the program is:</p>
|
|
<pre class="ecmascript-code" include="prime.js"></pre>
|
|
|
|
<p>Note that the program uses the native helper if it's available but falls
|
|
back to an Ecmascript version if it's not. This allows the Ecmascript code
|
|
to be used in other containing programs. Also, if the prime check program
|
|
is ported to another platform where the native version does not compile
|
|
without changes, the program remains functional (though slower) until the
|
|
helper is ported. In this case the native helper detection happens when the
|
|
script is loaded. You can also detect it when the code is actually called
|
|
which is more flexible.</p>
|
|
|
|
<p>A native helper with functionality equivalent to <code>primeCheckEcmascript</code>
|
|
is quite straightforward to implement. Adding a program main and a simple
|
|
<code>print()</code> binding into the Ecmascript global object, we get
|
|
<code>primecheck.c</code>:</p>
|
|
<pre class="c-code" include="primecheck.c"></pre>
|
|
|
|
<p>The new calls here are, line by line:</p>
|
|
<ul class="breakdown"> <!-- breakdown -->
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
int val = duk_require_int(ctx, 0);
|
|
int lim = duk_require_int(ctx, 1);
|
|
</pre>
|
|
<p>These two calls check the two argument values given to the native helper.
|
|
If the values are not of the Ecmascript number type, an error is thrown.
|
|
If they are numbers, their value is converted to an integer and assigned to
|
|
the <code>val</code> and <code>lim</code> locals. The index 0 refers to the first
|
|
function argument and index 1 to the second.</p>
|
|
<p>
|
|
Technically <code>duk_require_int()</code> returns a <code>duk_int_t</code>; this
|
|
indirect type is always mapped to an <code>int</code> except on obscure platforms
|
|
where an <code>int</code> is only 16 bits wide. In ordinary application code you
|
|
don't need to worry about this, see <a href="#ctypes">C types</a> for more discussion.</p>
|
|
</li>
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_false(ctx);
|
|
return 1;
|
|
</pre>
|
|
<p>Pushes an Ecmascript <code>false</code> to the value stack. The C return value
|
|
1 indicates that the <code>false</code> value is returned to the Ecmascript caller.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_push_global_object(ctx);
|
|
duk_push_c_function(ctx, native_prime_check, 2 /*nargs*/);
|
|
duk_put_prop_string(ctx, -2, "primeCheckNative");
|
|
</pre>
|
|
<p>The first call, like before, pushes the Ecmascript global object to the
|
|
value stack. The second call creates an Ecmascript <code>Function</code> object
|
|
and pushes it to the value stack. The function object is bound to the
|
|
Duktape/C function <code>native_prime_check</code>: when the Ecmascript function
|
|
created here is called from Ecmascript, the C function gets invoked.
|
|
The second argument (<code>2</code>) to the call indicates how many arguments
|
|
the C function gets on the value stack. If the caller gives fewer arguments,
|
|
the missing arguments are padded with <code>undefined</code>; if the caller gives
|
|
more arguments, the extra arguments are dropped automatically. Finally, the
|
|
third call registers the function object into the global object with the
|
|
name <code>primeCheckNative</code> and pops the function value off the stack.
|
|
</p>
|
|
</li>
|
|
|
|
<li>
|
|
<pre class="c-code">
|
|
duk_get_prop_string(ctx, -1, "primeTest");
|
|
if (duk_pcall(ctx, 0) != 0) {
|
|
printf("Error: %s\n", duk_safe_to_string(ctx, -1));
|
|
}
|
|
duk_pop(ctx); /* ignore result */
|
|
</pre>
|
|
<p>When we come here the value stack already contains the global object
|
|
at the stack top. Line 1 looks up the <code>primeTest</code> function
|
|
from the global object (which was defined by the loaded script). Lines
|
|
2-4 call the <code>primeTest</code> function with zero arguments, and
|
|
prints out an error safely if one occurs. Line 5 pops the call result
|
|
off the stack; we don't need the return value here.</p>
|
|
</li>
|
|
|
|
</ul> <!-- breakdown -->
|
|
|
|
<p>Compile like above:</p>
|
|
<pre>
|
|
$ gcc -std=c99 -o primecheck -Isrc/ src/duktape.c primecheck.c -lm
|
|
</pre>
|
|
|
|
<p>Test run (ensure that <code>prime.js</code> is in the current directory):</p>
|
|
<pre>
|
|
$ time ./primecheck
|
|
Have native helper: true
|
|
49999 59999 79999 139999 179999 199999 239999 289999 329999 379999 389999
|
|
409999 419999 529999 599999 619999 659999 679999 769999 799999 839999 989999
|
|
|
|
real 0m2.985s
|
|
user 0m2.976s
|
|
sys 0m0.000s
|
|
</pre>
|
|
|
|
<p>Because most execution time is spent in the prime check, the speed-up
|
|
compared to plain Ecmascript is significant. You can check this by editing
|
|
<code>prime.js</code> and disabling the use of the native helper:</p>
|
|
<pre class="ecmascript-code">
|
|
// Select available helper at load time
|
|
var primeCheckHelper = primeCheckEcmascript;
|
|
</pre>
|
|
|
|
<p>Re-compiling and re-running the test:</p>
|
|
<pre>
|
|
$ time ./primecheck
|
|
Have native helper: false
|
|
49999 59999 79999 139999 179999 199999 239999 289999 329999 379999 389999
|
|
409999 419999 529999 599999 619999 659999 679999 769999 799999 839999 989999
|
|
|
|
real 0m23.609s
|
|
user 0m23.573s
|
|
sys 0m0.000s
|
|
</pre>
|
|
|