Beginner Needs Help on converting and calling a C function

212 views
Skip to first unread message

HJ

unread,
Apr 13, 2021, 8:43:49 PM4/13/21
to emscripten-discuss
I am a beginner and I'm sure all the information is there, but I am struggling to get even a basic example working. I can run the tutorial example, but I can't get anything for the following:

I have converted some MATLAB .m script files to C (MATLAB can convert to C or CPP. I've tried both C and CPP in the below information.)

MATLAB has 1 function per 1 file, so now I have two .c files with one c function in each.

I've run emcc to convert .c to .js
When I look in the a.out.js and search for "myfunct", all I see for my function is the following and I'm not sure how to call it in my js main program:

/** @type {function(...*):?} */ var _myFunc = Module["_myFunc"] = createExportWrapper("myFunc");

I've played around with many different command line parameters that I've found on various Q&A forums, but still can't figure out how to create such that there is a function called "myFunc" that I can call from my other js files (actually typescript, but just assume js for this.)

This code will be run on the server side, node.js, and not on a browser. Backend code that will call these converted MATLAB functions to generate data.

It would be nice to have an example from beginning to end (I've been searching and searching, but I only find answers that will say things like, "You just need to use the xxxx option", but there is more to the puzzle that I am missing. 

It seems like the examples on emscripten site are all self contained: you build and run them, but no example of how to convert a function and how to integrate it (call it) from other js code. I have read the many options, but again I am not sure exactly what to do. I've also read the comments in the produced js file about creating a module and searched, but I am not sure how to define a module for a function.
  • What are the emcc parameters do I use?
  • Can I convert just this one function or do I need to have a main() that calls it?
  • Once converted, it looks like I need to define a module for "myfunc", but I am not sure how it is defined, when to define, do I add after into the .js?
  • What about using the WASM=0 option to only produce js and no WASM. Maybe that is a route to take? (I tried and it produced some different code in .js, but i'm still stuck on what to do with it.
I created the below simple function that takes a double and returns a double for trying this. If anyone can show me the steps with this or any HelloWorld that takes a parameter and returns it would be greatly appreciated. (or even more complex example.)

Thank helping this newbie! :-)

myFunc.c:

#include "myfunc.h" 
double myfunc(double myInt) {
   return myInt + 50.0; 
}

myFunc.h:

#ifndef MYFUNC_H
#define MYFUNC_H

/* Include Files */
#include "rtwtypes.h"
#include <stddef.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Function Declarations */
extern double myFunc(double myInt);

#ifdef __cplusplus
}
#endif

#endif

Floh

unread,
Apr 14, 2021, 7:43:02 AM4/14/21
to emscripten-discuss
Hi, I quickly cobbled together a "simplest possible sample" for calling a C function from JS here:


This is running in the browser though and it's a bit quick'n'dirty, but it should get you started at least 
for your own experimentations. The important things are the EMSCRIPTEN_KEEPALIVE annotation in the
hello.c file, and the underscore in front of the addc() function call in Javascript in shell.html.

If you cannot annotate the original source files with EMSCRIPTEN_KEEPALIVE, you can also provide the 
C functions names to make visible to Javascript with a compiler option instead, see here:


I prefer to work with simple C-APIs instead of C++ APIs, because with C-APIs you
can (more or less) call the functions directly from Javascript instead of creating a "language binding"
between C++ and Javascript interfaces. For this, emscripten has a tool called "embind" (which adds a whole 
new level of complexity and more things that can break, but I guess that's personal opinion heh). 
There are some caveats with non-trivial function arguments (for instance pointers to data on the WASM heap), 
maybe embind makes this case easier, don't know.

In any case, here's the embind documentation:


Hope this helps!

Geoffrey McVittie

unread,
Apr 14, 2021, 8:13:16 AM4/14/21
to emscripten-discuss
Hello,
You may want to look at:
There is an update to be released soon that will resolve the issues shown in the discussion. The existing add-on should work so long as you install emscripten using the following flag:

./emsdk install 1.38.45

Hope this helps.

HJ

unread,
Apr 14, 2021, 4:21:57 PM4/14/21
to emscripten-discuss
Thank you both for the quick responses.
Floh, I will try this today.
Geoffrey, I have tried your Generate Javascript Using MATLAB Coder add-on in MATLAB, but ran into issues. I posted those issues on the conversation that is on that add-on's page.

HJ

unread,
Apr 15, 2021, 1:15:12 AM4/15/21
to emscripten-discuss
I have not found the answer to life, the universe and everything yet...

I created the hello.js based on Floh's code. I did one change in that I added the "-s WASM=0" to the emcc command line to only produce JS and not any WASM. (I assume that is ok for my goal.)

I added hello.js to my MS Code project and then try calling the "_addc" in hello by adding the following in my main TypeScript file app.ts:

at the top of app.ts:

import {_addc} from './app/util/hello.js';

and in the body of app.ts:

const myResult = _addc(10,20);
console.log('....................................' + myResult + '-------------------------')

======================================
It built, but when I run, I get the following error:  native function `addc` called before runtime initialization
======================================

$ yarn start
yarn run v1.22.10
warning package.json: License should be a valid SPDX license expression
warning ../../package.json: License should be a valid SPDX license expression
warning ../../../../package.json: No license field
$ node dist/index.js
GPProcessAPIService constructor
Assertion failed: native function `addc` called before runtime initialization
/Users/me/Desktop/cg-process-api/src/production/cg-process-api/dist/app/util/hello.js:102
            throw ex;
            ^

Error: abort(Assertion failed: native function `addc` called before runtime initialization) at Error
    at jsStackTrace (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app/util/hello.js:1856:17)
    at stackTrace (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app/util/hello.js:1873:14)
    at abort (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app/util/hello.js:1614:46)
    at assert (/Users/me/Desktop/gp/cg-process-api/gp-process-api/src/production/gp-process-api/dist/app/util/hello.js:856:9)
    at Object._addc (/Users/me/Desktop/gp/gp-process-api/cgps-process-api/src/production/gp-process-api/dist/app/util/hello.js:1671:9)
    at Object.<anonymous> (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app.js:59:29)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at abort (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app/util/hello.js:1619:13)
    at assert (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app/util/hello.js:856:9)
    at Object._addc (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app/util/hello.js:1671:9)
    at Object.<anonymous> (/Users/me/Desktop/gp/gp-process-api/gp-process-api/src/production/gp-process-api/dist/app.js:59:29)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
error Command failed with exit code 7.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.


Floh

unread,
Apr 15, 2021, 7:39:58 AM4/15/21
to emscripten-discuss
Can't help with that sorry, it looks like a problem that the _addc() function is being called before it has been imported (in the example project, a similar problem (but for loading the WASM module) is the reason why all the important JS code is inside that 'onRuntimeInitialized()' callback:


...but without this, I get a simple "_addc() is undefined" error message in the browsers JS console, not the fancy error message you're seeing (that's why my guess is that your error message is coming from the module system via the line "import {_addc}...", which probably also happens asynchronously, but I don't have experience with this new-fangled module stuff ;)

Hacker Shopping

unread,
Apr 15, 2021, 9:36:58 AM4/15/21
to emscripte...@googlegroups.com
Thank you Floh

I'll keep trying. :-)

--
You received this message because you are subscribed to a topic in the Google Groups "emscripten-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/emscripten-discuss/AwqiKUQNGYU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to emscripten-disc...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/emscripten-discuss/9551b416-01da-4405-8a46-b600059fa337n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages