Calling C from JS with Emscripten, minimal examples
There are a few ways of doing this, this is the simplest, but also slowest. The options are listed on the Emscripten wiki here.
Return an int, complete example
Sample C file (I called it call.c):
1 2 3 4 5 6 7 8 9 | #include <math.h> int test1( int x) { return sqrt (x); } int test2( int x) { return sqrt (x)+1; } |
Compile as follows:
emcc call.c -o call.js -s EXPORTED_FUNCTIONS="['_test1','_test2']"
You can then create a html file which calls this JS code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <! DOCTYPE html> < html > < body > < script src = "call.js" ></ script > < script > var result = Module.ccall( 'test1', // name of C function 'number', // return type ['number'], // argument types [28]); // arguments document.write(result); </ script > </ body > </ html > |
Passing and returning an array of ints
This is a little harder, Emscripten doesn’t really help you out, you have to format the arrays in memory manually.
Sample C program two functions, one passing and returning a char *, the other int *s.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <math.h> #include <stdlib.h> #include <string.h> char *test1( char *instr) { char *array = malloc ( sizeof ( char )* strlen (instr)); strcpy (array,instr); // the horror!! int size = strlen (array); for ( int n=0;n<size;n++) { if ((array[n] >= 'a' ) && (array[n] <= 'z' )) array[n] -= 'a' - 'A' ; } return array; } int *test2( int *in, int size) { int *array = malloc ( sizeof ( int )*size); for ( int n=0;n<size;n++) { array[n] = in[n]*2; } return array; } |
emcc call.c -o call.js -s EXPORTED_FUNCTIONS="['_test1','_test2']"
The JS can then be called from html as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <! DOCTYPE html> < html > < body > < script src = "call.js" ></ script > < script > function write_1d_int32_array(ptr,array) { for(i=0;i< array.length ;i++) { Module.setValue(ptr,array[i],'i32'); ptr += 4; } } function read_1d_int32_array(ptr,length) { var array = []; for( i = 0 ;i<length;i++) { var value = Module .getValue(ptr+(i*4),'i32'); array.push(value); } return array; } // test1 - a C function that takes, and returns a C style string (char *) var mystring = "test" ; var strptr = Module ._malloc(mystring.length); Module.writeAsciiToMemory(mystring, strptr); var retstrptr = Module .ccall('test1', // name of C function 'number', // return type ['number'], // argument types [strptr]); // arguments // Convert the resulting string to a JS string var retstr = Pointer_stringify (retstrptr); document.write(retstr); // test2 - a C function that takes, and returns a C style int array (int *) var myarray = [10,20,30,40,50]; var arrayptr = Module ._malloc(myarray.length*4); write_1d_int32_array(arrayptr,myarray); var retarrayptr = Module .ccall('test2', // name of C function 'number', // return type ['number'], // argument types [arrayptr,myarray.length]); // arguments // Convert the resulting pointer to a JS array var retarray = read_1d_int32_array (retarrayptr,myarray.length); document.write(retarray); </script> </ body > </ html > |