Tuesday, July 9, 2013

PEBL in a browser: 2. Getting PEBL to compile.

This is second in a series of blog posts describing the issues involved in compiling PEBL via emscripten so it can run within a web browser.  It is probably mostly of interest to developers who are trying to port their own applications via emscripten.

I usually use the GNU gcc/g++ compiler to compile PEBL, but have also tried the clang/llvm option as it is available under xcode on OSX.  For the most part, they are interchangeable, but because of different warning levels, some of the code that might have only given a deprecated warning under GCC gives a fatal compile-time error under CLANG.  So the first step was to fix any of these.    The goal here was simply to compile PEBL to native code under a new compiler, and not worry yet about emscripten.

This all worked fairly easily.  I forget all the things I needed to do, but many of them silenced warnings I had received as compilers and standards became more strict.  There were a few times when I had to redefine char * to const char * to avoid a string literal warning,  but it was mostly innocuous.

Next, I wanted to get rid of a lot of code that probably wouldn't work in emscripten (or if it would, it might be hard to handle and I'd want to take care of that some other time).  The simplest way to do this was to define a c preprocessor symbol and have it cull out any classes and code that shouldn't be required.   I also created a new Makefile and removed some of the class files from the compile list.

 The list includes:

  • Parallel port access code
  • Serial port access code
  • Movie playback (supported via waave)
  • Networking code supporting TCP/IP (this will probably be turned back on later to support remove data saving)
  • Sound recording support
This is a bit messy because it requires going through class after class adding #ifdef emscripten, but it means that we avoid compiling a lot of code that we won't ever be able to use anyway. 

With a bunch more banging, I was eventually able to compile into a version that ran natively--so far so good.  The next step was to try compiling via emscripten.

The basic process here is in two stages.  Now, I first needed to just run a special-purpose emscripten make command on my Makefile to produce the llvm bytecode, and then a special command to translate that bytecode to javascript and/or html. The first command is:
~/src/emscripten-incoming/emmake make -f Makefile.em -j 6

This is all on linux.  Note that I am using the '-incoming' branch of emscripten, and I have it saved in ~/src.  Also, I'm pleased that the -j argument works, which allows compiling multiple files simultaneously.  Within the Makefile, the only thing I really had to change (aside from defining -DPEBL_EMSCRIPTEN) was to change the target name specified with the -o option from -o bin/pebl to -o bin/pebl.bc  I did this so that I could have a parallel binary and bytecode living in the same development branch.  So, when the above command completed, I was left with a file called bin/pebl.bc that emscripten can deal with.

Next, you need to let emscripten compile to either javascript or a html page.  With any reasonably complex app (i.e., if it starts SDL up), you really need the html container, so this is the command I run:

~/src/emscripten-incoming/emcc -O2 --closure 0 bin/pebl.bc  --embed-file test.pbl --preload-file pebl.bmp --preload-file DejaVuSans.ttf --embed
-file pebl-lib  -o bin/pebl.html

I'll explain the --embed-file stuff in the next blog post.  This eventually worked,  insofar as it created a pebl.html page that would often run within my browser.  But unless the script was VERY simple, it would quickly get off-track and do strange things.  After some painful debugging within the javascript window, I isolated this to a problem with how emscripten handled PEBL's Variant class-it's all-in-one data class.  Eventually, I filed a bug on this, which after a few back-and-forths kripken thought it might be fixed in the -incoming branch (as opposed to the -master branch), which is why I'm using the -incoming above.

Finally, there were a few workarounds I needed to do regarding unimplemented SDL functions. These mainly involved the SDL_TTF library.  In my default branch, I used the following SDL_TTF functions, which were not available:


I changed my code to (for the time being) not use these.  I suspect that TTF_WasInit() is really not relevant--this is a double-checker to ensure that a library was properly loaded, but for emscripten we can probably assume it was.  I'm not as sure about the other two--I changed them to use the non-UTF8 versions, but this might cause problems when trying to read translations--something to deal with down the road.

Stay tuned for future updates.  The next post will describe steps I took to conform to emscripten file system limitations, which explains most of the long line above.

Post a Comment