使用Haxe宏进行条件编译,而不是#if #end

时间:2014-08-10 03:07:53

标签: macros haxe

假设我们有一个Local类:

class Local {
    static inline public var logLevel:Int = 3;
}

还有一些功能:

Tool.debug(s:String)   // compiled if logLevel >= 0
Tool.moreinfo(s:String)// compiled if logLevel >= 1
Tool.info(s:String)    // compiled if logLevel >= 2
Tool.trace(s:String)   // compiled if logLevel >= 3
Tool.warn(s:String)    // compiled if logLevel >= 4
Tool.err(s:String)     // compiled if logLevel >= 5

我们可以使用-D和代码中的一些#if来实现这一点。

然而,这意味着始终修改hxml文件。即使只是一个值,这对我来说并不理想,因为我的所有配置都在我的Local类中。

如果我们使用简单的if()来测试值,那么代码会随着所有if和字符串变大,即使它从未使用过(因为logLevel意味着'常量')。

是否可以使用宏来克服这两个问题?

3 个答案:

答案 0 :(得分:4)

修改

如果用例如此简单,那么@ stroncium的答案会更容易:使所有内联内联,编译器将进行优化,不需要宏。请参阅http://try.haxe.org/#C44Ec,并查看已编译的JS。


假设Local是普通课程(您手动编写,不用宏或其他任何东西构建),那么您可以在宏调用中访问Local.logLevel

这样的一些代码可以使用

class Tool {
    public static macro function debug( s:ExprOf<String> ):Expr {
        if ( Local.logLevel>=0 ) {
            // Insert a trace statement into our code. 
            // You could insert any other kind of statement or { block; of; statements; } also.
            return macro trace( $s );
        }
        else {
            // You need to return an expression of some kind.
            // This is the equivalent of writing the line "null;" - it does nothing whatsoever.
            return macro null;
        }
    }
}

或者同样的事情,写得更简洁一点,以及所有功能:

class Tool {
    public static macro function debug( s:ExprOf<String> ):Expr {
        return
            if ( Local.logLevel>=0 ) macro trace( "debug: " + $s );
            else return macro null;
    }
    public static macro function moreInfo( s:ExprOf<String> ):Expr {
        return
            if ( Local.logLevel>=1 ) macro trace( "moreInfo: " + $s );
            else return macro null;
    }
    public static macro function info( s:ExprOf<String> ):Expr {
        return
            if ( Local.logLevel>=2 ) macro trace( "info: " + $s );
            else return macro null;
    }
    public static macro function trace( s:ExprOf<String> ):Expr {
        return
            if ( Local.logLevel>=3 ) macro trace( "trace: " + $s );
            else return macro null;
    }
    public static macro function warn( s:ExprOf<String> ):Expr {
        return
            if ( Local.logLevel>=4 ) macro trace( "warn: " + $s );
            else return macro null;
    }
    public static macro function err( s:ExprOf<String> ):Expr {
        return
            if ( Local.logLevel>=5 ) macro trace( "err: " + $s );
            else return macro null;
    }
}

答案 1 :(得分:2)

您可以直接设置日志记录功能。编译器将内联它们并在编译时检查条件,删除无法执行的分支。

答案 2 :(得分:0)

制作源文件或配置文件的风格很差,因此每次编译时都需要编辑。

如果您使用像FlashDevelop这样的IDE,那么问题就会消失,因为您可以在编译时传入参数。毕竟,这就是IDE的用途。

我将在这里使用FD作为示例,但您可以针对您使用的任何IDE进行调整。

FlashDevelop在顶部有两个下拉列表:配置和目标。例如,在我的项目中,我有通常的两个配置(Debug,Release)和三个目标(standalone,webalone,webinline)。您可以拥有“log0”,“log1”等目标。

[不幸的是,FlashDevelop目前有一个错误,它不会在会话之间存储配置名称,所以我经常在编译之前输入我想要的那个。]

在项目属性中 - &gt;预建命令行,我把:

haxe.exe $(BuildConfig).hxml $(TargetBuild).hxml $(ProjectName).hxml

您可以为haxe构建指定多个hxml文件,因此您可以拥有一个名为log1.hxml,log2.hxml等的集合,其中只包含您不断更改的那一行。

可以离开它。它完成了你所要求的一切。您甚至可以将“target”字段用作“loglevel”字段,只需输入一个数字。您的编译命令行可能看起来像:

haxe.exe $(ProjectName).hxml -D loglevel=$(TargetBuild)

就个人而言,为了进行调试,我需要为每个目标使用不同的调试环境(浏览器,flash播放器等),因此我将调试操作作为批处理文件:

  • 项目属性 - &gt;
  • 输出 - &gt;
  • 测试项目 - &gt;
  • 运行自定义命令 - &gt;
  • "D:\svn\src\haxe\debug.bat" $(TargetBuild) "$(OutputFile)"

该批处理文件包含:

@echo off
goto %1%
goto end

:webinline 
start "" "D:\svn\src\haxe\bin\index-flashvar.html"
goto end

:webalone 
start "" "D:\svn\src\haxe\bin\index.html"
goto end

:standalone 
start "" "D:\Program Files (x86)\FlashDevelop\Tools\flexlibs\runtimes\player\11.9\win\FlashPlayerDebugger.exe" %2%
goto end

:end

简而言之:每次编译时,使用IDE的强大功能从简单的下拉列表中执行所需的操作。