Call main function and pass in command line arguments

1,455 views
Skip to first unread message

Bryan Duggan

unread,
Jul 12, 2015, 7:07:13 PM7/12/15
to emscripte...@googlegroups.com
Hey

I presume this is standard enough usage for emscripten, but I cant figure out how to do it. I am trying to port a command line C program called abc2midi to emscripten.

Everything compiles fine and I can get both the javascript to generate and run in node and the HTML to generate and run in the browser. 

Now I want to do the following:

1 Write a text file to the virtual file system. This is how Im doing it:

var Module = {
  'print': function(text){ 
console.log(text) 
  },
  'printErr': function(text){ 
console.log(text) 
  },
  'preRun' : function(){
console.log('prerun');
//FS is not defined
FS.createDataFile("/", "in.abc", abcContents, true, true);  },
  'noInitialRun': true,
};

2. Call the main method and pass in some command line arguments including the file name. I cant find an example of how to do this and everything Ive tried has not worked

3. Read back the generated file from the file system

Surprisingly hard to find an example of this pretty straightforward scenario! Any help would be much appreciated

Bryan

chronotext

unread,
Jul 13, 2015, 5:52:54 AM7/13/15
to emscripte...@googlegroups.com
Hi there,

I think Module.arguments is what you're looking for:


HTH,
Ariel

Bryan Duggan

unread,
Jul 13, 2015, 7:41:55 AM7/13/15
to emscripte...@googlegroups.com
Thanks

Here is my problem though. If I compile like this:

emcc genmidi.c midifile.c parseabc.c parser2.c queues.c store.c -o abc2midi.js -s EXPORTED_FUNCTIONS="['_main', '_abc2midi']" 

Even if I set noInitialRun: true in Module like this:

var argv = [ "in.abc", "1", "-o", "out.mid"];
var Module = {
   arguments: argv,
   print: function(text){ 
    console.log('print');
console.log(text) 
  },
  printErr: function(text){ 
console.log(text) 
  },
  preRun : function(){
console.log('prerun');
FS.createDataFile("/", "in.abc", abcContents, true, true);  
  },
  noInitialRun: true,
};

The C program runs, but does not take the command line arguments!! I can see the output on the Javascript console. Also preRun is never called

If I compile like this:

emcc genmidi.c midifile.c parseabc.c parser2.c queues.c store.c -o abc2midi.js -s EXPORTED_FUNCTIONS="['_main', '_abc2midi']" -s INVOKE_RUN=0

And try this in my HTML page:

var argv = [ "in.abc", "1", "-o", "out.mid"];

var Module = {
   arguments: argv,
   print: function(text){ 
    console.log('print');
console.log(text) 
  },
  printErr: function(text){ 
console.log(text) 
  },
  preRun : function(){
console.log('prerun');
FS.createDataFile("/", "in.abc", abcContents, true, true);  
  },
  noInitialRun: false, // Makes no difference
};
run();

preRun gets called but the C program doesnt run

Whats going on!?

Bryan

chronotext

unread,
Jul 13, 2015, 8:23:39 AM7/13/15
to emscripte...@googlegroups.com
It looks like you work with Module as if you were still in Node mode.

But when working in HTML mode, Module has already been defined, as explained here:

Bryan Duggan

unread,
Jul 13, 2015, 9:51:17 AM7/13/15
to emscripte...@googlegroups.com
Really sorry

I read that and I dont understand your answer at all...

Here is what I want to do:

Create a file (this should be in preRun?)
Execute abc2midi - I want this to be triggered not run when the page loads
Get the generated midi file (this should be in postRun?)

Can emscriptren be made to do this? Are there any simple examples of how to set this up?

WRT To your answer. I am not generating HTML, just JavaScript. Here is my full HTML page:

<html>
<head>
<script src = "abc2midi.js"></script>
</head>
<body>
<script>
var abcContents = "X:1\nT:Jimmy Ward's Jig\nR:jig\nD:Matt Molloy: Heathery Breeze\nZ:id:hn-jig-103\nM:6/8\nK:G\n~G3 GAB|AGE GED|~G3 AGE|GED DEF|~G3 GAB|AGE GAB|cBA BGE|1 DED DEF:|2 DED D2B||\n|:cBA BAG|~A3 AGE|BcA BGE|EDE GAB|c2c BAG|ABA ABc|dcA AGE|1 GED D2B:|2 GED DEF||\n\n"
var argv = [ "in.abc", "1", "-o", "out.mid"];

var Module = {
   "arguments": argv,
   "print": function(text){ 
    console.log('print');
console.log(text) 
  },
  "printErr": function(text){ 
console.log(text) 
  },
  "preRun" : function(){
console.log('prerun');
FS.createDataFile("/", "in.abc", abcContents, true, true);  
  },
  "setStatus": function(text){ 
    console.log('setStatus');
console.log(text)
},
  "noInitialRun": true,
};
run(); // This does not run abc2midi though preRun gets called
</script>
</body>
</html>`

And here is how I am compiling:

emcc genmidi.c midifile.c parseabc.c parser2.c queues.c store.c -o abc2midi.js -s EXPORTED_FUNCTIONS="['_main', '_abc2midi']"

Im at a loss as to what to try next

Bryan

Alon Zakai

unread,
Jul 13, 2015, 2:23:38 PM7/13/15
to emscripte...@googlegroups.com
If you hit something annoying like that (preRun is not called, or arguments are ignored, or your main() is not called), the best thing is to reduce this to as simple a standalone testcase as possible. Often in my experience the problem shows itself while doing the reduction (might be a typo somewhere, for example), but if it does not, then the standalone testcase is easy for us to run and investigate in order to help you.

--
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.

Stefan Meier

unread,
Jul 15, 2015, 3:44:29 AM7/15/15
to emscripte...@googlegroups.com
Hi Bryan,

actually your solution should work, I think. That is what I am doing and it looks like your way:
var Module = {
        arguments: [gametag,idxdb],
        preRun: [],
        postRun: [],
        print: (function() {
            if (debug==1)
            {...

Can you perhaps try to create javascript and html output, add the arguments to the generated html and see if it works?

Bryan Duggan

unread,
Jul 15, 2015, 6:13:13 PM7/15/15
to emscripte...@googlegroups.com
Ok

Ive made a minimal example to show whats happening:


I left everything in the repo

The program test.c just takes the first file passed on the command line and copies it to the next file on the command line.
The batch file build.bat will compile the test program using VC command line (just to prove the program compiles and works ok. If you dont have Visual Studio installed, this bit wont work, but its not necessary. It then builds 2 versions of test.c using emcc. One html version and one javascript version. The HTML version runs the compiled c program and if I modify the HTML to include the command line parameters, they get passed into the exe
Ive included a file emstest_mod.html where I have done this. noInitialRun is set to true in the file and indeed it doesnt run initially. In this version I get the error run is undefined though

If you take a look at the file test.html you will see what I am trying to do. Ive copied over the Module code from the HTML file and modified it a little. In this version, preRun is not called, arguments are ignored as is noInitialRun:true. The program just runs. If you comment out the last line in build.bat, it compiles with the flag INVOKE_RUN=0. 

In this build, running test.html, preRun is called, but the compiled C program is never called!

So I can get the C program to run with no parameters (the Module definition is ignored) and only on page load, not triggered or I can get the module definition to be recognised (as preRun gets called) but the compiled C program wont run

Hope all this makes sense! I must be doing something wrong as I guess this is a standard use case. I have a load of C code I want to call repeatedly to convert some files as part of of bigger web app.

Bryan

Alon Zakai

unread,
Jul 15, 2015, 6:20:18 PM7/15/15
to emscripte...@googlegroups.com
I'm confused by the build. It's creating both *.html and *.js, but the first command also emits a js file, so the two commands overwrite each other? Is that perhaps part of the problem?


--

Bryan Duggan

unread,
Jul 15, 2015, 6:36:23 PM7/15/15
to emscripte...@googlegroups.com
Ok just comment out the first compile then. It's not relevant. Just do the second compile to Javascript and look at test.html. If you load it in Chrome you will see straight away what is happening

The Module definition in test.html is ignored

Bryan

Bryan Duggan

unread,
Jul 15, 2015, 6:37:47 PM7/15/15
to emscripte...@googlegroups.com
Unless you compile with -s INVOKE_RUN=0 in which case the Module definition seems to be used but then the program wont run

Alon Zakai

unread,
Jul 15, 2015, 8:04:43 PM7/15/15
to emscripte...@googlegroups.com
Ok, so test.html is the one to run? Then I think the problem is that you have

<script src = "emstest.js"></script>

and later down you define Module. So your Module does not exist when the program emstest.js executes. You need to reverse the order.

Bryan Duggan

unread,
Jul 16, 2015, 4:18:51 AM7/16/15
to emscripte...@googlegroups.com
Thanks

That makes a lot of sense. Ive changed that but it still does not work, unless I am misunderstanding something. Here is what I am doing now:

Compiling with -s INVOKE_RUN=0
In test.html:
Defining Module 
Including the compiled js
Calling run

And here is what is happening:

preRun always gets called regardless or whether I use -s INVOKE_RUN=0 or ever call run. Commenting out run() makes no difference. Surely this should only happen when I run the program?
run() does nothing. If I debug it, I see that doRun has already been called and the flag Module['calledRun'] has been set to true and hence the run() exits early. If I set it to be false in MY code, then in the method doRun, the flag shouldRunNow is set to be false and therefore the method exits.

What I want to happen:

Nothing to happen when the page loads
On some event, copy the file (in preRun), run the program get the file generated by the program (in postRun)

Thanks for your help so far. Ive checked in my changes to 


Bryan

Alon Zakai

unread,
Jul 16, 2015, 2:25:08 PM7/16/15
to emscripte...@googlegroups.com
It sounds like you want more control over things than the default behavior. I would avoid preRun and postRun, then. Just call your own JS (to set up files, etc.) directly when you want, consider avoiding a main() method (which would invoke some default behavior for when to call it), and instead call your compiled methods when you want (using one of the methods on http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html ).

Bryan Duggan

unread,
Jul 17, 2015, 4:43:24 PM7/17/15
to emscripte...@googlegroups.com
Alon

Of course! You are right. Its all working now. For some reason I thought that the FS calls were asynchronous and that you had to use the framework in order to make sure the file was written before main was called. I'll write a blog post about it as soon as I get a chance.

Here is the code I am using now:

var abcContents = "X:1\nT:Jimmy Ward's Jig\nR:jig\nD:Matt Molloy: Heathery Breeze\nZ:id:hn-jig-103\nM:6/8\nK:G\n~G3 GAB|AGE GED|~G3 AGE|GED DEF|~G3 GAB|AGE GAB|cBA BGE|1 DED DEF:|2 DED D2B||\n|:cBA BAG|~A3 AGE|BcA BGE|EDE GAB|c2c BAG|ABA ABc|dcA AGE|1 GED D2B:|2 GED DEF||\n\n"

FS.createDataFile("/", "in.abc", abcContents, true, true);
var result = Module.ccall('test', // name of C function
  'number', // return type
  [], // argument types
  []); // arguments

And Ive updated the example on the git


Thanks so much for your time! Emscripten is an amazing project and it is going to solve lots of problems for me

Bryan
Reply all
Reply to author
Forward
0 new messages