Haxe Cppia Notes
Jun 18, 2019
Overview of Cppia
Cppia is an additional target for the Haxe compiler which depends on the Hxcpp runtime. On the Hxcpp side, you have a virtual machine which can interpret Cppia bytecode. Cppia bytecode is generated from standard Haxe code using the Haxe compiler just like any other backend. There isn't really any magic involved here as far as I can tell, it's just different from most other targets because it's tightly coupled to the Hxcpp backend.
One of the coolest benefits of Cppia is that it's a system target (so it has access to the same APIs as the Cpp target), and it compiles extremely quickly. This lets you do rapid iteration on a native target, much like the Neko or Hashlink targets. However, unlike Neko and Hashlink, you can load and execute Cppia code during runtime from your Hxcpp application very easily. This can be used for scripting, for example.
If you were to try to implement scripting like that using Neko or Hashlink, you would need to embed a Neko or Hashlink virtual machine into your program manually, and maybe add a way to load/execute those scripts from your Haxe code. This is a totally viable option of course (and the Hashlink target might even perform better than Cppia [this is unconfirmed]), but it's a lot of work. With Cppia, all you have to do is add the -D scriptable
flag to your host application (which causes the Cppia interpreter to be compiled), and then use the cpp.cppia.*
APIs in the standard library to load/run/reflect on your scripts.
Another benefit is that since Cppia is compiled from standard Haxe code, you could use Cppia during development to iterate rapidly, and then generate C++ code when its time to ship so that you get maximum performance and avoid having to include the Cppia interpreter in your final build.
Using Cppia
Compiling Cppia scripts
To compile Haxe code as Cppia, you use the -cppia
flag. For example:
1 |
|
This will generate myscript.cppia
in a folder called build
. Since this is a standard Haxe program, MyScript
should have a public static function main():Void
function.
Running Cppia scripts
To run a Cppia script, you need a Cppia Host. This is any hxcpp program that includes the Cppia virtual machine. To create one, you just need to add the -D scriptable
definition to the Haxe compiler when using the hxcpp target. Example:
1 |
|
This will compile the program with support for running Cppia scripts, but you still have to run them yourself somehow in your code. Simply adding the scriptable
flag won't automatically turn your program into a command-line script runner. To run a Cppia script, you have to read the contents (as a text file), and use it with the cpp.cppia.*
APIs. For example:
1 2 3 4 5 6 7 8 |
|
And that's all there is to it. If you need more control, like reflection on types in the script, you can use the cpp.cppia.Module
class. See the source for the cpp.cppia.Host.run
function for an example of how to initialize and run a Module instance. It's super simple, and then once you have an instance you can use the function cpp.cppia.Module.resolveClass
to find types defined in the script. Those types can then be used with Haxe's standard Type.createInstance
and similar functions.
Using Libraries in Cppia
Cppia scripts are standard Haxe, so you could probably use any existing Haxe library with it. You could probably even use OpenFL, although OpenFL is a huge library and you'd be better off keeping that in your host rather than distributing it in every single script.
But then this raises the question: how do you use library types in a Cppia script if you don't want to compile that library along with your script?
The answer is that Cppia offers a way to exclude classes that are already in the Host. So you're free to add any haxelib to your cppia script using the standard -lib
flag. This makes those types available to you within the script, but doesn't actually compile them. It will assume that those types are available in the Host, so they will try to be resolved at runtime.
So how does this work? When you compile your host with the -D scriptable
flag, the compiler will generate a file called export_classes.info. This contains a list of every class included in the Host. You can use this file when compiling your Cppia script to inform the compiler as to which classes can be safely excluded from the compilation.
How to exclude classes with export_classes.info
The Cppia backend includes a macro which will automatically search for a file called export_classes.info
in the classpath. That part is in bold because it is important: the file MUST be in your classpath (a folder can be added to the classpath with the -cp
flag)
Don't assume that the Host will generate that file in the correct place, because it probably won't. You need to make sure that you copy that file into the classpath of your Cppia script. You could automate the process of copying export_classes.info
into the correct place if desired.
An alternative method is to not rely on that search function and just manually specify the path to that file. This can be done with the -D dll_import=path/to/file.info
flag. You would need to add that flag to your Cppia compile command.
Fin
If you see any errors here or have comments, feel free to contact me via email or Twitter.
Sources
https://groups.google.com/forum/#!topic/haxelang/yURC8k2fGeg
https://stackoverflow.com/questions/30008574/what-is-cppia-scripting
https://code.haxe.org/category/other/working-with-cppia/index.html
© Alejandro Ramallo 2024