Graham's Flex & Flash Blog

April 3, 2010

Adobe Alchemy: Compiling a C library to run in Flex/Flash

Filed under: Alchemy — admin @ 8:18 am

When Alchemy launched in late 2008, I downloaded the files from Adobe Labs, followed the instructions, compiled the simple stringecho example and voila! Alchemy nirvana! But then what? I had a C library I wanted to port, but started coming up against problems. Unfamiliarity with Cygwin and the Unix C tool chain (I used Borland Turbo C on DOS back in the early 90s) didn’t help. I had problems compiling the more complicated examples. Looking at the Alchemy forum on Labs it seemed that some people had a great headstart, while others could get as far as stringecho, but then like me were struggling where to go next. The documentation is terse and the examples go from Hello World to a full library port with very little explanation. I forgot about Alchemy for a while but then decided to try again and crack it. So the purpose of this post is to try and unstick people like me who got stuck. I’m still very much in the beginner camp – I’ve no idea how to write a .gg Gluegen file yet (anyone care to write an explanation?!) – but I have managed to compile a library and use its functionality.

So the C library I’m going to use is Mike Cowlishaw’s decNumber, a library that provides facilities for decimal arithmetic. If you are looking for a solution to Flash’s lack of a decimal data type however, I would advise using a port of Java’s BigDecimal and related classes. This was a side-project I intended to do last year, but luckily a kind person has spared us that particular task, and has shared it with the community here: http://code.google.com/p/bigdecimal/

I’m assuming you’ve got as far as running stringecho, so you are comfortable compiling with gcc, and using the resultant swc in your Flash project. If you are having trouble getting up and running, there’s the Adobe Labs documentation, and this article may help. And if things get messy when you get to the advanced stuff, remember Alchemy is a buggy beta.

OK, so let’s start by downloading decNumber. You can find it on IBM’s Alphaworks site, but that version requires a paid license for commercial use; Mike Cowlishaw has also provided it on his site under an ICU license. Scroll down to the decNumber section and there’s a link under International Components for Unicode (ICU). I’d suggest unzipping it and placing the source in a folder under your alchemy/samples/ folder. There is a PDF which documents the library if you want to understand it in greater depth, and some simple examples. Just to check everything’s OK, let’s compile and run an example… open a Cygwin session and navigate to alchemy/samples/decnumber (note, if your Cygwin window has opened under your user directory in Cygwin, you can navigate up the folder hierarchy and over to alchemy with cd cygdrive/c/alchemy/ assuming you’ve done a plain install (I’m on Windows). Ensure that you’ve got Alchemy off (alc-off) and type:
gcc -o example1 example1.c decNumber.c decContext.c
(instructions are in the readme that comes with decNumber). That should have produced an example1.exe file. To run it, type: ./example1 followed by two decimal numbers you want added.

So now we can start to explore the library and find functions we want to expose to Actionscript. Looking through header files there are many functions, but I’m just interested in the 4 basic arithmetic ones. Starting with add, we need to pass the 2 values through as strings, convert them to decNumbers, add them, convert back and then return the value to Actionscript. Here’s our “wrapper” function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static AS3_Val add(void* self, AS3_Val args)
{
	//vars to hold the parameters from AS
	char* val1 = NULL;
	char* val2 = NULL;
 
	decNumber a, b;
	decContext set;                  // context for decNumber (precision, rounding mode, etc)
	char string[DECNUMDIGITS+14];   // result
	decContextTestEndian(0);
	decContextDefault(&set, DEC_INIT_DECIMAL128); // initialize
 
	// copy the 2 args supplied from Actionscript into our val variables..  no error checking
	AS3_ArrayValue( args, "StrType, StrType", &val1, &val2);
 
	set.traps=0;                            // no traps 
	set.digits=DECNUMDIGITS;         // set precision
	// convert strings to decNumber
	decNumberFromString(&a, val1, &set);
	decNumberFromString(&b, val2, &set);
	// add them
	decNumberAdd(&a, &a, &b, &set);
	// convert back to a string
	decNumberToString(&a, string);
	// return to Actionscript caller
	return AS3_String(string);
}

So let’s go ahead and compile that, and try to get it going in Flash. Download the source here. With Alchemy on, compile add.c, decNumber.c and decContext.c to object files, eg:
gcc -c add.c
gcc -c decNumber.c
gcc -c decContext.c

Now we’re ready to compile our swc. Call gcc to link our object files together:
gcc deccontext.o decnumber.o add.o -O3 -Wall -swc -o add.swc
and we should now have a nice red shiny add.swc ready to drop into our Flash project. (you probably saw something like “WARNING: While resolving call to function ‘main’ arguments were dropped!” or even a message about “MS-DOS style path detected:” while compiling but don’t worry about that, it doesn’t seem to be important).

Here’s a simple Actionscript class that allows us to test the swc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package
{
	import cmodule.add.CLibInit;
 
	public class AddTest 
	{
		public function AddTest()
		{
			var loader:CLibInit = new CLibInit;
			var lib:Object = loader.init();
 
			var a:String = "0.1324918245645645655398134342345645";
			var b:String = "0.0000456456456456400012312313123123";
			var c:Number;
			c = Number(a + b);
			trace("a + b = " + c );
                        c = Number(a) + Number(b);
			trace("a + b = " + c );
			trace(lib.add(String(a), String(b)));
 
		}	
	} 
}

Either use something similar in your project, or here’s a Flash Builder project you can download to test. When you import the project into Flash Builder, note it will be showing 3 compilation errors to do with CLibInit. This is because we haven’t yet provided a swc file to go in the lib folder of the project. Copy the add.swc file from your alchemy/projects/decnumber folder to the lib folder of your Flash project. However, when we run the code (debug in Flash Builder to get a trace), we get a trace for c = Number(a + b) and for the truncated result from Number(a) + Number(b) but then it dies with a stack trace:

a + b = NaN
a + b = 0.13253747021021017
Undefined sym: _decContextTestEndian
at Function/() [...etc]

Ouch. So things aren’t looking so good. Whenever we call a function in the library it cannot find it and stops with a stack trace. There were a few posts in the Labs forum from people with a similar problem, but not always the same cause. After a lot of digging around I came across this forum post which tells us we need to create an archive of our C library files first before doing the final compile/link. I guess that’s common knowledge if you’ve been doing C/C++ on Unix for any amount of time. The steps given in the forum post didn’t quite work for me but after consulting this and doing a bit of googling I found the winning forumla. It was a trial & error process to get this to work, and only by following these steps exactly does it work for me. Your mileage may vary…

Do all steps with alchemy on alc-on
1. gcc all the relevant c files into object files. Important: I had to compile each file one command at a time, eg:
gcc -c decNumber.c
gcc -c decContext.c

If I don’t do that, when I run the archiver in the next step I get this error:
llvm-nm: decNumber.o: unrecognizable file type
llvm-ld: error: Cannot find linker input 'decNumber.o'

2. Create an archive from those object files:
ar rc decNumberLib.a decContext.o decNumber.o
This will produce two files, decNumberLib.a and decNumberLib.l.bc

3. Do this bit of jiggery pokery:
ranlib decNumberLib.a

4. Put the library file (decNumberLib.l.bc) into a folder under your project folder as gcc doesn’t search in the current directory and needs to be given a path. For example, create a folder called lib and move your decNumberLib.l.bc in there (you can move the decNumberLib.a file along with it, but its not necessary). The library folder is supplied to gcc in the -L parameter in the next step:

5. Compile to make the final swc:
gcc -Wall -Llib -ldecNumberLib add.c -swc -O3 -o add.swc

Now drop the resulting swc into your project and run again. I’m hoping that at this point you are getting a clean run and the following trace:
a + b = NaN
a + b = 0.13253747021021017
0.1325374702102102055410446655468768

Flash’s math routines have failed to add the numbers accurately, but decNumber has done it. If you are interested you can also test that it solves the binary-decimal error, and can represent numbers much bigger than Flash’s Number type. You may have to adjust the size of the string[] array and increase the size of set.digits to find the upper limits.
If you are still getting a fail, then try the above steps again. All I can say is it took me several hours of trial and error to arrive at this point, and if its still not working for you then you are probably going to have to go through a similar process.

OK, so now we can flesh out our wrapping of the library a little bit. Lets add functions for subtract, divide and multiply. These all work the same way as add. We also need to change our main() function so that the new functions are registered as shown in the AS3Lib project test.c file (see documentation here). Download the source here.
Compile that with
gcc -Wall -Llib -laddLib decNumberWrapper.c -swc -O3 -o add.swc
and drop the swc into your project. Add some test lines to your TestAdd class:

1
2
3
trace(lib.subtract(String(a), String(b)));
trace(lib.multiply(String(a), String(b)));
trace(lib.divide(String(a), String(b)));

and you should be getting a trace like this:
a + b = NaN
0.1325374702102102055410446655468768
0.1324461789189189255385822029222522
0.000006047674875018415513203106509706779
2902.616946052990529904172826969371

Finally, let’s expose a function of another file in the decNumber library. This time I’ll expose the decQuadAdd function from decQuad.c. I create an addQuad function in our c wrapper file and add it in the main() function. Download the source file here.

With alc-on, let’s compile our source files, create an archive, copy it to the lib folder and then do the final compile:
gcc -c decQuad.c
gcc -c decNumber.c
gcc -c decContext.c
ar rc decNumberLib.a decQuad.o decNumber.o decContext.o
ranlib decNumberLib.a
gcc -Wall -Llib -ldecNumberLib decNumberWrapper2.c -swc -O3 -o decNumberLib.swc

Note, I’ve renamed our final swc to decNumberLib. Drop the swc in your project and change the import line to reflect the name change:

1
import cmodule.decNumberLib.CLibInit;

and add a statement to use our new decQuad function:

1
trace(lib.addQuad(String(a), String(b)));

and voila, you should now be seeing the result of the addQuad operation.

Hopefully this has helped you get going with your C/C++ library port.

12 Comments

  1. I can’t thank you enough for this article! I just managed to compile part of PolarSSL to Flash with your help. It’s really powerful and this opens a new world for online games as I can now use fast hashing algorithms within flash to communicate with a server in an encrypted way.
    Many many many thanks for this!

    Comment by Steven — June 4, 2010 @ 5:24 am

  2. Hi Steven, that’s great, I’m glad this post helped you out. Good luck with getting it all working.

    Comment by admin — June 16, 2010 @ 8:21 pm

  3. Thanks a lot, this will be very helpful in our project. In fact, I am an experienced C developper called in by a Flash team.

    Comment by nalply — November 17, 2010 @ 3:57 pm

  4. Your post has been extremely useful – thanks a bunch!

    That’s fun, this was also to compile a part of PolarSSL…

    Comment by Philippe — December 5, 2010 @ 7:25 pm

  5. I just want to thank you for taking the time to write this article. I have to tell you I spent hours and hours and days learning how to work with Alchemy, scouring forums posting questions and I have gotten more clarification out of this post than anywhere else combined. In fact I got clarification on things no one even mentioned in all my searching ( I even spoke directly to two Adobe Alchemy employees. The best response I got was “gee wiz I dunno, works fine for me”). I have a very ambitious project, to port a light 3D engine over using alchemy and I got so far on it but was always getting screwed over by the error you mentioned:

    “llvm-nm: decNumber.o: unrecognizable file type
    llvm-ld: error: Cannot find linker input ‘decNumber.o’”

    Although I have a lot more to learn not covered in this post, the post contains information essential to even getting started that I can testify, from personal experience, simply isn’t available anywhere else. Thanks!

    Comment by Jesse Nicholson — December 5, 2010 @ 11:33 pm

  6. Hi Jesse, thanks for the comments. Yes, this post was just the result of feeling my way in the dark, so I’m really glad its helped you out. I came across the Alchemy port of Box2D the other day (there is also a straight AS3 port of that library), done by (presumably) another Jesse – http://www.sideroller.com/wck/ the source is available here https://github.com/jesses/wck/wiki/box2d-flash-alchemy-port and he writes about hacking the source, recompiling with Alchemy, etc. I’d suggest taking a look at that as you can play with all the source and see how the Alchemy stuff has been done, and perhaps the guy(s) involved might be able to give you some help. Good luck with the port!

    Comment by admin — December 20, 2010 @ 10:01 am

  7. Hey man, thanks a lot for your great help with alchemy stuff here!
    I want to port the sphelper.h in AS3 using alcemy, you think this is possible to it? That’s a huge load of includes of .h files…
    Thanks a lot!

    Comment by John — December 23, 2010 @ 8:38 am

  8. Thank for this article and your hard work figuring this out!. I have 2 questions:
    I used a make file to generate .o files (without alc-on;)

    1. Will it be ok that my .o files are already generated without alc-on ? – I hope so because there are a lot of em!

    2. My make file also generated .lo and .la files. I assuming I don’t need those?

    thx again

    -Mike

    Comment by Mike — December 26, 2010 @ 10:38 pm

  9. Hi Mike, pretty sure you need alc-on before you Make – I think the AS3Crypto example that comes with Alchemy might show the way, as well as the Alchemy forum. No idea about the .lo and .la files, sorry.

    Comment by admin — December 29, 2010 @ 6:42 am

  10. Hi John – sphelper… only one way to find out! I doubt there’s a practical limit on the number of header files you can include.

    Comment by admin — December 29, 2010 @ 6:47 am

  11. Just found another blog that explains how to use Gluegen, so I’d suggest heading over here http://www.zaalabs.com/2010/04/compiling-with-alchemy-1/ once you are done with this.

    Comment by admin — December 29, 2010 @ 6:58 am

  12. disabling comments as I’m getting about 50 spam comments a day.

    Comment by admin — February 26, 2011 @ 2:04 pm

RSS feed for comments on this post. TrackBack URL

Sorry, the comment form is closed at this time.

Powered by WordPress