hxcpp native access

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

hxcpp native access

Gamehaxe
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
Reply | Threaded
Open this post in threaded view
|

Re: hxcpp native access

Nicolas Cannasse
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
Reply | Threaded
Open this post in threaded view
|

Re: hxcpp native access

Cauê W.
Wow, Hugh!

That's great news! I was actually creating a library to do something like that here :


you can see some examples here:

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 :

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


--
haXe - an open source web programming language
http://haxe.org