如何将此 MSBuild 脚本转换为 F#/FAKE?

How to translate this MSBuild script to F#/FAKE?

将以下 MSBuild 脚本翻译成 F#/FAKE 是什么?

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <PropertyGroup>
        <CurrentMode>None</CurrentMode>
    </PropertyGroup>

    <Target Name="Compile_A">
        <Message Text="Hello from Compile_A" />

        <CallTarget Targets="SetToA"/>
        <CallTarget Targets="IntermediateStage"/>
    </Target>

    <Target Name="Compile_B">
        <Message Text="Hello from Compile_B" />

        <CallTarget Targets="SetToB"/>
        <CallTarget Targets="IntermediateStage"/>
    </Target>

    <Target Name="IntermediateStage">
        <Message Text="Hello from IntermediateStage" />

        <CallTarget Targets="Compile"/>
    </Target>

    <Target Name="Compile">
        <Message Text="Hello from Compile. I'm using $(CurrentMode)" />
    </Target>

    <!-- The following Targets are only necessary due to a MSBuild bug (CallTarget and CreateProperty cannot be combined) -->
    <Target Name="SetToA">
        <CreateProperty Value="A">
            <Output TaskParameter="Value" PropertyName="CurrentMode" />
        </CreateProperty>
    </Target>

    <Target Name="SetToB">
        <CreateProperty Value="B">
            <Output TaskParameter="Value" PropertyName="CurrentMode" />
        </CreateProperty>
    </Target>
</Project>

我的主要目标是在最上面的目标中设置一个 属性 具有不同的值(CurrentModeAB)并在最深处消耗它目标 (Compile).

最佳答案可能会因您的实际情况而异。特别是,如果您不打算单独 运行 它们,您甚至可能不需要为流程的不同步骤单独设置目标(在这种情况下,只需使用一个将模式作为参数的函数并调用它来自 CompileACompileB 可以正常工作)。

但是,如果您想为所有步骤保留单独的目标,您可以这样做:

#load ".fake/build.fsx/intellisense.fsx"
open Fake.Core
open Fake.Core.TargetOperators

let mutable CurrentMode = "None"

Target.create "SetA" (fun _ ->
  CurrentMode <- "A"
)

Target.create "SetB" (fun _ ->
  CurrentMode <- "B"
)

Target.create "IntermediateStage" (fun _ ->
  printfn "In the intermediate stage"
)

Target.create "Compile" (fun _ ->
  printfn "Compiling using mode %s" CurrentMode
)

Target.create "CompileA" ignore
Target.create "CompileB" ignore

"SetA" ==> "CompileA"
"SetB" ==> "CompileB"
"IntermediateStage" ==> "Compile" ==> "CompileA"
"IntermediateStage" ==> "Compile" ==> "CompileB"
"SetA" ?=> "IntermediateStage"
"SetB" ?=> "IntermediateStage"

Target.runOrDefault "CompileA"

这使用由 SetASetB 目标设置的可变变量 CurrentMode(可以说,不是很实用,但它捕获了你正在做的事情)。

目标之间的依赖关系使用==>指定。请注意,SetA 必须在 CompileA 之前发生(B 也类似)并且 IntermediateStage 需要在 Compile 之前发生,这是两种编译的先决条件。

有一个巧妙的技巧 - 你不想说 IntermediateStep 需要 SetASetB,因为 FAKE 会 运行 都在非确定性顺序。 ?=> opreator 允许您指定 soft dependencies 表示如果 IntermediateStepSetA 都被执行,那么 SetA 有首先 - 所以最后两行不是添加依赖项,而是明确排序。