Compiler Configuration with Macros

Macros can be used during the compilation process to generate custom code. Macros can also be used to perform some pre-compilation tasks.

These compiler configuration macros can be used with the haxe --macro commandline parameter.

An example is to force the inclusion of all the files defined in a given package and its sub packages :

haxe --macro include('my.package') ....

Please use single-quotes for string constants since some OS (such as Windows) remove double-quotes.

The previous example is actually a shortcut for the following :

haxe --macro haxe.macro.Compiler.include('my.package') ....

And here's the code for the actual method :

/**
    Include for compilation all classes defined in the given package excluding the ones referenced in the ignore list.
**/
public static function include( pack : String, ?rec = true, ?ignore : Array<String>, ?classPaths : Array<String> ) {
    var skip = if(null == ignore) {
        function(c) return false;
    } else {
        function(c) return Lambda.has(ignore, c);
    }
    if(null == classPaths)
        classPaths = Context.getClassPath();
    // normalize class path
    for( i in 0...classPaths.length ) {
        var cp = StringTools.replace(classPaths[i], "\\", "/");
        if(StringTools.endsWith(cp, "/"))
            cp = cp.substr(0, -1);
        classPaths[i] = cp;
    }
    var prefix = pack == '' ? '' : pack + '.';
    for( cp in classPaths ) {
        var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/");
        if( !sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path) )
            continue;
        for( file in sys.FileSystem.readDirectory(path) ) {
            if( StringTools.endsWith(file, ".hx") ) {
                var cl = prefix + file.substr(0, file.length - 3);
                if( skip(cl) )
                    continue;
                Context.getModule(cl);
            } else if( rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file) )
                include(prefix + file, true, ignore, classPaths);
        }
    }
}

As you can see, there's no black magic going here. You can use any of the haxe.macro.Compiler methods or write your own custom versions.

So far the possibilities include :

  • including files to make sure they are compiled
  • excluding some classes from being generated
  • patching types by removing some declared fields or changing their type
  • adding metadata either before/class is defined or at end of compilation (with Context onGenerate method)
  • defining a custom Javascript code generator (see below)

Much more possibilities will be added when there is a need for it.

Custom JS Generator

You can write your own custom JS generator in Haxe : the generator will take care of creating the .js file(s) and generating the class structure/registration. You cannot however customize the way the Haxe expressions are generated.

See 'haxe/std/haxe/macro/ExampleJSGenerator.hx' for a reference implementation.

In order to use it, simply add the following commandline parameter to haxe compilation :

--macro haxe.macro.DefaultJSGenerator.use()
version #19446, modified 2013-06-13 15:57:21 by justsee