hxcpp icon indicating copy to clipboard operation
hxcpp copied to clipboard

@:include meta, accept multiple headers

Open posxposy opened this issue 5 years ago • 4 comments

Hi!

Sometimes, extern classes need to include more than one header. The current solution will be to create a separate header that will contain all required headers and then include it into Haxe extern class. Like this: @:include('./Headers.h') which is contain HedaerA.h and HedaerB.h

But, it would be nice if @:include will accept multiple headers out of the box, something like:

@:include('HedaerA.h', 'HedaerB.h')
extern class Native {}

or

@:include('HedaerA.h')
@:include('HedaerB.h')
extern class Native {}

Thank you!

posxposy avatar Feb 18 '20 17:02 posxposy

I agree, being able to specify multiple @:includes would be the best solution. But note that creating a separate header is not the only way to make this work. The better workaround is: @:headerCode('#include "a.h"\n#include "b.h"').

Aurel300 avatar Feb 18 '20 18:02 Aurel300

@Aurel300

The better workaround is: @:headerCode('#include "a.h"\n#include "b.h"')

Yeah... But @:headerCode will not work for extern class, isn't it? It is only for regular Haxe classes. So you need to add it into every class where you use your extern. Something like:

@:headerCode('
#include<HeadrA.h>
#include<HeadrB.h>
')
class Some {
  var native:Native;
}

//this extern requires NativeA.h and NativeB.h
extern class Native {}

Correct me if I'm wrong.

posxposy avatar Feb 18 '20 19:02 posxposy

You may be right, it is only a workaround for some situations.

Aurel300 avatar Feb 18 '20 21:02 Aurel300

@Aurel300 @dmitryhryppa So I've arrived at this problem recently, and I workaround by writing an extern interface that includes the second header. i.e.

@:include("HeaderB.h")
@:noCompletion @:noDoc extern interface IncludeHeaderB {}

@:include("HeaderA.h")
extern class Native implements IncludeHeaderB {}

I also ended up writing a helper generic class like so:

#if !macro
@:genericBuild(physx.hx.IncludeHelper.IncludeHelperBuilder.build())
extern interface IncludeHelper<@:const T:String> {}
#else
import haxe.macro.Context;
import haxe.macro.Type;
import haxe.macro.Expr;
using StringTools;

class IncludeHelperBuilder
{
    public static function build()
    {
        var includeExpr:Expr = switch (Context.getLocalType())
        {
            case TInst(_, [ TInst(_.get().kind => KExpr(e), _) ]): e;
            default: null;
        }
        var include:String = haxe.macro.ExprTools.getValue(includeExpr);

        var className = "IncludeHelper_" + include.replace(".", "_").replace("/", "_").replace("\\", "_");

        try
        {
            return Context.toComplexType(Context.getType(className));
        }
        catch(e:String) 
        {
        }

        var c = macro interface $className {};
        c.isExtern = true;
        c.meta.push({ name: ":include", params: [ includeExpr ], pos: Context.currentPos() });

        Context.defineType(c);
        return Context.toComplexType(Context.getType(className));
    }
}
#end

Usage:

@:include("HeaderA.h")
extern class Native implements IncludeHelper<"HeaderB.h"> {}

undefinist avatar Aug 01 '20 08:08 undefinist