|
Hi,
I have been doing a bit of work on native code access from within hxcpp. You will need the latest svn haxe and hxcpp versions to try this out. This is done with class & function meta-data to inject code into the generated source files. For a class, there is @:headerCode("code") // Inject code into class header file - eg for types of injected members @:headerClassCode("code") // Inject code into header class definition - eg member variables/functions @:cppFileCode("code") // Inject code into top of cpp file - eg local includes, local functions, static variables for functions: @:functionCode("code") // Inject code into top of function - eg, whole implementation @:functionTailCode("code") // Inject code into end of function - eg, close functionCode, or continue processing In addition, you can inject code into the bottom of the build.xml code via the class meta-data: @:buildXml('xml fragment') The whole process can be made to work, but there may be a little bit of pain involved. One problem you will come across is dealing with the hxcpp types - mostly these are obvious, but you may need to study a bit of generated code to find out the details. eg, using the ".__s" member of a string to access the const char *pointer. You also need to consider the compiler environment of other peoples computers, and the compiling dependencies (eg, headers/libraries) when designing a system. Garbage collection is also an important consideration - I will present here two possible ways of handling this. // This is so the "FILE *" type is known to the compiler. Other libraries may require other includes. @:headerCode("#include <stdio.h>") // Define the GC finalizer for method 1 - code goes in the cpp file ..... @:cppFileCode('void staticClose(MyStdio_obj *inObj) { if (inObj->mFile) fclose(inObj->mFile); printf("CLOSED!\\n"); }\n') // Put a "FILE *" member in the class, as well as an inline function. // All members get "memset" to 0 on construction - no automatic destructor will get called... @:headerClassCode('FILE *mFile;\ninline static void Print() { printf("PRINT!\\n"); }') class MyStdio { public function new() { // You can sometimes call/use the native members directly if the usage matches standard // haxe usage. Use the 'untyped' keyword so that the compiler does not check // that MyStdio has a "Print" function. untyped MyStdio.Print(); // Can't do code-injection on constructor - must use separate function setFinalizer(); } @:functionCode("hx::GCSetFinalizer(this, (hx::finalizer)staticClose);") function setFinalizer() { } @:functionCode('mFile=::fopen(filename.__s, mode.__s); return mFile!=0;') public function fopen(filename:String, mode:String) { return false; } @:functionCode('return fwrite(inString.__s, inString.length, 1, mFile);') public function writeString(inString:String) { return 0; } @:functionCode('if (mFile) fclose(mFile); mFile=0;') public function close() { // Ok to do memory operations here (not a native finalizer) trace("Closed!"); } } class Test { // This is put in a separate function to ensure the stack is clean of // stray references to the 'file'. public static function testFile() { var file = new MyStdio(); file.fopen("test.txt", "wb"); file.writeString("Hello, World!\n"); file = null; } public static function main() { testFile(); cpp.vm.Gc.run(true); trace("Done."); } } This uses native code for the "worker" functions, and an external finalizer, which closes any file left open. You have to be careful in the finalizer method to not perform and hxcpp memory allocations. You also have to be careful to to the "minimum amount" because the function could be called from a different thread, and this can cause problems for quite a few systems (eg, opengl). An alternate way to manage collected objects is to use the "zombie" method. Here, you use haxe, rather than native, code to create the finalizer, ie, replace: setFinalizer(); With: cpp.vm.Gc.doNotKill(this); This means the GC will not collect this object, but instead place it in limbo on the "zombie list", which you can access any time with something like this: while(true) { var zombie = cpp.vm.Gc.getNextZombie(); if (zombie==null) break; var close = zombie.close; if (close!=null) close(); } There is nothing special about the "close" name - each object can be treated separately. The advantage of this is that you process the zombies whenever you want, using the correct thread and not having to worry about memory allocations. You can even reanimate the zombie by recording a reference to it - but you will need to call doNotKill if you do not want it to die next time its collected. This can be performed, say, once per frame in an NME-style application. If you have a library with include files and libraries, you can add xml to the end of the build.xml file by using meta data on one of your classes like this: @:buildXml('<include name="${haxelib:yourLib}/native.xml"/>') And then include a "native.xml" file in your haxelib. This can add "-Iinclude" and "-lib:abc" to the build system. You could list out the xml directly, or use "${MY_XML}" or something else. In general, I think is is probably best to put as much as possible in external files, rather than trying to inline too much ascii. Hugh -- haXe - an open source web programming language http://haxe.org |
|
Le 06/11/2011 17:33, Gamehaxe a écrit :
> Hi, > I have been doing a bit of work on native code access from within hxcpp. > You will need the latest svn haxe and hxcpp versions to try this out. > > This is done with class & function meta-data to inject code into the > generated source files. > > For a class, there is > > @:headerCode("code") Could you document these here (in a cpp-specific section) : http://haxe.org/manual/tips_and_tricks Best, Nicolas -- haXe - an open source web programming language http://haxe.org |
|
Wow, Hugh!
That's great news! I was actually creating a library to do something like that here : you can see some examples here:
auto cffi wrapper creation - http://code.google.com/p/native-gateway/source/browse/trunk/test/comtacti/native/tests/TestBasicCffi.hx
it involved running a custom build tool - forked from nme's - that added the possibility of having pre-build and post-build scripts running. It also looked on all -lib projects for include .xml files so you could use e.g. a library that needed some postbuild/prebuild script
Anyway, I really like your way much better (of course), though I'd request a __cpp__() access also, specially with the syntax (which you can see at the second link), so we can interoperate more easily with hand-written vs hxcpp code
Also in the future I plan to add dll importing with hxffi just like C# does. : ) What do you think about this? Thanks for everything! This is awesome! Caue 2011/11/6 Nicolas Cannasse <[hidden email]> Le 06/11/2011 17:33, Gamehaxe a écrit : -- haXe - an open source web programming language http://haxe.org |
| Powered by Nabble | See how NAML generates this page |
