Problems with ccall and cwrap

45 views
Skip to first unread message

mertes...@gmail.com

unread,
Apr 14, 2019, 3:26:38 AM4/14/19
to emscripten-discuss
Hello,
I have problems with emcc and node.js, when I use cwrap or ccall.
My information source is at

https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html

I tried several approaches, but I did not succeed.
The C program with my test follows:

---------- begin test program tst262.c ----------
#include "stdio.h"
#include "string.h"
#include "emscripten.h"


extern void setEnvironmentVar (char *key, char *value)

  { /* setEnvironmentVar */
    printf("setEnvironmentVar(\"%s\", \"%s\")\n", key, value);
  } /* setEnvironmentVar */


int main (int argc, char *argv[])

  { /* main */
    printf("begin main\n");
    setEnvironmentVar("", "");
    EM_ASM(
      // console.log(process.env);
      let setEnvVar = Module.cwrap('setEnvironmentVar', 'number', ['string', 'string']);
      Object.keys(process.env).forEach(function(key) {
        let val = process.env[key];
        console.log(key);
    setEnvVar(key, val);
      });
    );
    printf("end main\n");
  } /* main */
---------- end test program tst262.c ----------

Compiling and starting this program does not work:

  myPrompt> emcc tst262.c -o tst262.js -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
  myPrompt> node tst262.js
  begin main
  setEnvironmentVar("", "")
  SHELL
  Assertion failed: Cannot call unknown function setEnvironmentVar, make sure it is exported
  Assertion failed: Cannot call unknown function setEnvironmentVar, make sure it is exported
  exception thrown: abort("Assertion failed: Cannot call unknown function setEnvironmentVar, make sure it is exported") at Error
      at jsStackTrace (/run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:1152:13)
      at stackTrace (/run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:1169:12)
      at abort (/run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:2338:44)
      at assert (/run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:583:5)
      at getCFunc (/run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:590:3)
      at ccall (/run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:621:14)
      at /run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:644:12
      at /run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:1708:210
      at Array.forEach (<anonymous>)
      at Array.ASM_CONSTS (/run/media/tm/disk2_460GiB/home/tm/seed7_5/src/tst262.js:1708:140)
  myPrompt>

When I export setEnvironmentVar as suggested I get:

  myPrompt> emcc tst262.c -o tst262.js -s EXPORTED_FUNCTIONS='["_setEnvironmentVar"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
  myPrompt> node tst262.js
  myPrompt>

As you can see: The program terminates immediate. If I use ccall
instead of cwrap I get the same error. Allocating pointers for
the strings and calling the function direct from JavaScript,
as suggested by the documentation, fails also. It just cannot
find the function setEnvironmentVar. Using underscore (_) at
various places did also not help.

What is necessary to make ccall and cwrap work?

Many thanks in advance for your help.

Regards,
Thomas Mertes

--
Seed7 Homepage:  http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch, statically typed,
interpreted or compiled, portable, runs under linux/unix/windows.

Floh

unread,
Apr 14, 2019, 11:05:57 AM4/14/19
to emscripten-discuss
I'm not sure what the problems with EXPORTED_FUNCTIONS and EXTRA_EXPORTED_RUNTIME_METHODS is (I'm not using those), instead I'm using an alternative way, maybe that's better suited for your use case too (I think it's much better than relying on the build system / linker options)...

It took me a while to understand all the pieces of the puzzle though:

- instead of EXPORTED_FUNCTIONS, I'm annotating C functions which must be visible from the Javascript side with EMSCRIPTEN_KEEPALIVE like here:


...and for JS code embedded into C code I use EM_JS (similar to EM_ASM, but for whole JS functions):


Now the tricky part: calling the EMSCRIPTEN_KEEPALIVE C function from JS, the details here have been changing recently, and the interaction with emscripten passes like minification through the closure compiler are a bit "non-obvious".

For the simple case where you're just calling back-and-forth from the same C source, it's best to call ccall()/cwrap() as "standalone" functions (without the Module part):


With minification, the function names ccall and cwrap will be minified to something else. But this is fine since the minifier sees and replaces are places (in this case, our embedded EM_JS function).

It only gets ugly when ccall/cwrap needs to be called from somewhere unrelated, for instance a manually written Javascript file, or some Javascript code embedded in a HTML file, like in my drag-n-drop handler code here:


Note how this uses Module['ccall'](...) for invoking the ccall() runtime function, not Module.ccall(...). I don't know why exactly, but Module.ccall() stopped working for me quite recently because it was affected by minification. This is usually where EXTRA_EXPORTED_RUNTIME_METHODS is needed.

In my case I didn't want to depend on build system configuration for my header-only C library, so I'm using a little workaround now: I'm creating a little embedded EM_JS init-function which is called once at startup, and this registers the ccall() function object of on the global variable 'Module', if other headers need to do this too, no harm done, they will simply overwrite the already existing Module['ccall'] item. That way Module['ccall'] points to the right function, even when the name 'ccall' is minified to something else.


Cheers,
-Floh.

Alon Zakai

unread,
Apr 15, 2019, 3:33:59 PM4/15/19
to emscripte...@googlegroups.com
I don't see where setEnvironmentVar is defined in JS? I'd expect something like

var setEnvironmentVar = cwrap('setEnvironmentVar', ..);
setEnvironmentVar(..);

Might be helpful to look at the examples in the test suite (e.g. test_ccall).

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages