COMMUNITY

Weird behaviour of hxcpp with libtcod (probably bug)

haxe-cpp

#1

hxlibtcod.cpp


    #include <libtcod.h>
    //#define NO_UNICODE

#define IMPLEMENT_API
#if defined(HX_WINDOWS) || defined(HX_MACOS) || defined(HX_LINUX)
    #define NEKO_COMPATIBLE
#endif
#include <hx/CFFIPrime.h>

void console_init_root( int w, int h, const char * title, bool fullscreen, int renderer ) {
   gc_enter_blocking();
   TCOD_console_init_root( w, h, title, fullscreen, (TCOD_renderer_t) renderer );
   gc_exit_blocking();
}
DEFINE_PRIME5v( console_init_root );

void console_wait_for_keypress( bool flush, value k ) {
        gc_enter_blocking();
        TCOD_key_t kt = TCOD_console_wait_for_keypress( flush );
        puts( "HERE" );
        gc_exit_blocking();
}
DEFINE_PRIME2v( console_wait_for_keypress );

build.xml

<xml>
                <include name="${HXCPP}/build-tool/BuildCommon.xml"/>
                <include name="toolchain/common-defines.xml" />

                <files id="hxlibtcod">
                    <compilervalue name="-I" value="CHANGE_ME/libtcod-1.5.1/include"/>
                    <addTwice/>
                    <file name="hxlibtcod.cpp" />
                </files>

                <target id="default" output="hxlibtcod" tool="linker" toolid="${STD_MODULE_LINK}">
                    <outdir name="test" />
                    <files id="hxlibtcod"/>
                    <libpath name="CHANGE_ME/libtcod-1.5.1/lib"/>
                    <lib name="/defaultlib:tcod-gui-mingw.lib" if="windows" unless="mingw || cygwin"/>
                    <lib name="-ltcod-gui-mingw" if="mingw || linux || cygwin"/>
                    <lib name="/defaultlib:tcod-mingw.lib" if="windows" unless="mingw || cygwin"/>
                    <lib name="-ltcod-mingw" if="mingw || linux || cygwin"/>
                </target>                
            </xml>

Test.hx

@:enum abstract Renderer( Int ) {
    var GLSL = 0;
    var OPENGL = 1;
    var SDL = 2;
}

class Tcod {
    // ( w:Int, h:Int, title:String, fullscreen:Bool, renderer:Renderer_t ):Void;
    public static var console_init_root:Int->Int->String->Bool->Renderer->Void = cpp.Lib.load( 'hxlibtcod', 'console_init_root', 5 );
    // ( flush:Bool, k:Key ):Void;
    public static var console_wait_for_keypress:Bool->Dynamic->Void = cpp.Lib.load( 'hxlibtcod', 'console_wait_for_keypress', 2 );
}

class Test {
    public static function main() {
        Tcod.console_init_root( 80, 50, 'HELLO TCOD', false, Renderer.SDL );
        
        while ( true ) {
            Tcod.console_wait_for_keypress( true, null );
            trace( '123' );
        }
    }
}

Compile with

haxelib run hxcpp build.xml
haxe -cpp test -main Test

You’ll need libtcod 1.5.1 to compile and run. Not sure about newer versions.
If you run it and then press anything it outputs “HERE” and then silently exits. It does not trace “123”. And you can move puts at the very end and it will work, so it’s not gc_exit_blocking call, but something happens in the cffi glue layer. If you do not call TCOD_console_wait_for_keypress, but any(?) other function then it (presumably) works fine. You can even Sleep() for ten seconds and everything will be ok. Same thing happens with native externs (except I didn’t try calling other functions). I cannot even debug it, because if I install breakpoint anywhere inside this function, then when it hits the breakpoint, debugger will stop responding to step over/run etc buttons and the program will just kind of sit there, frozen.
Works fine with hl and python (with original libtcod wrapper), so it’s not a libtcod issue.

Edit.
Well, if function is defined with @:native then there is no ffi glue code, but it does not work anyway, so I take it back. Also, things are already screwed if I only enter the function without executing a single instruction, so something goes wrong much earlier.
It’s not a __cdecl, because I can call printf just fine.
Looks like it’s not about function doing blocking io, because I can call Sleep just fine.
It’s not about returning struct by value, because I just did that and it works (even in combination with Sleep).
It’s not a mingw issue because it works in plain C test case.
It’s not HX_STACKFRAME because it fails even with -D no-debug

There is something magical about TCOD_console_wait_for_keypress itself. It’s not a name. Just checked that.