emscripten-core / emscripten-core/emscripten

Problems calling main / imported functions with Node environment [EAGAIN exception]

Open
#21,313 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

Hello,

I am trying to build a [wasm version of the cvc5 application](https://github.com/netolcc06/cvc5/tree/wasm-build) using Emscripten 3.1.18. I have two main objectives:
- To generate a web page that uses the wasm and Javascript files generated by Emscripten
- To create a TypeScript API using functions exported by Emscripten

Currently I am trying to export the main function only, but I am having issues to call it implicitly passing arguments to the Module or calling cwrap/ccall. The flags I used:

`-s MODULARIZE -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -s ENVIRONMENT=node -s EXPORTED_FUNCTIONS=_main -s INVOKE_RUN=1 -s EXIT_RUNTIME=0 -s INCOMING_MODULE_JS_API=arguments'`

For comparison purposes, if I generate a html page without the `-s MODULARIZE`, I can see that the input I am passing to the page is being used by the `get_char` function and the application works as intended. For instance, in the end you can see the sat/unsat result for the operation (check-sat).

![cvc5_web_call](https://github.com/emscripten-core/emscripten/assets/4164822/e3f55688-a341-429e-98f4-a2456b970114)
![cvc5_web_call_result](https://github.com/emscripten-core/emscripten/assets/4164822/9e43fe59-478a-4421-ae36-3b387535bd81)

However, I couldn't make it to work with the Node version. Things I've tried:

- Passing the input to the module with something like:

index.js
```
var m = require('../cvc5.js')

let input = '(set-logic QF_LRA)\
(declare-fun x () Real)\
(declare-fun y () Real)\
(declare-fun z () Real)\
(assert (= z 0))\
(assert (= (* 3 x) y))\
(assert (= (+ 1 (* 5 x)) y))\
(assert (= (+ 7 (* 4 x)) y))\
(check-sat)';

m({
"input": input
})

```
cvc5.js
```
var TTY = {
ttys: [],
init: function () {},
shutdown: function () {},
register: function (dev, ops) {
TTY.ttys[dev] = {
input: [Module["input"]],
output: [],
ops: ops
};
FS.registerDevice(dev, TTY.stream_ops)
},
...
```
or directly in the get_char

```
default_tty_ops: {
get_char: function (tty) {
if (!tty.input.length) {
var result = Module["input"];
if (ENVIRONMENT_IS_NODE) {
console.log("input 1")
var BUFSIZE = 256;
...
```

In both cases I get the exception `EAGAIN: resource temporarily unavailable, read` which is thrown and caught at the `get_char` function. Program still exits with 0.

- Calling `ccall` and `cwrap` function, which leads me to have the same exception being thrown (for the ccall it throws another exception in the end: RuntimeError: memory access out of bounds):

```
var m = require('../cvc5.js')

// argc = 2
// argv = path to a file containing the content I was passing directly as input in the previous method.
m().then((instance) => {
instance.cwrap('main', 'number', [2, arg])
instance.ccall('main', 'number' , ['number', 'string'], [2, arg])
})

```

I also tried:

```
f = instance.cwrap('main', 'number', ['number', 'array'])
f([3, ['node', 'index.js', input]])
```

With that said, my questions are:

- What is the proper way of calling main?
- Why do I get the EAGAIN exception? What is the proper way of passing input/arguments with those approaches (importing the Module or calling `ccall`/`cwrap`)?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.