14

I'm looking for a solution that invokes my FAKE build script when I do a "Build Solution" (Ctrl + F6). Bonus points for a way to specify a target other than the default.

kfazi
  • 617
  • 1
  • 9
  • 21
GeorgS
  • 741
  • 5
  • 12
  • I don't have a direct answer but Paket has `paket.targets` file (https://github.com/fsprojects/Paket/blob/68969d970bf2d60fb4e280e4365b6f87b9a7e285/.paket/paket.targets) which runs Paket when a solution is built (basically, by running the executable). I'm sure you could do the same for FAKE - but writing that MS Build XML stuff will be pain ... – Tomas Petricek May 13 '15 at 15:18
  • Post-build event? http://stackoverflow.com/a/1491413/126014 – Mark Seemann May 13 '15 at 17:22
  • 1
    I've looked into how Paket does this: they use BuildDependsOn but that wouldn't work for a FAKE script. The FAKE "Build" target, executing itself an MSBuild task, would trigger the FAKE script recursively. I've not yet found a proper way to get this working nicely. – GeorgS May 21 '15 at 12:25

2 Answers2

8

I solved this problem in another way. It requires manual edit of csproj files and the trick is in conditional override of builtin Build, Clean and Rebuild targets.

First I created custom fake.targets file and saved it in Targets folder at the solution level:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Build">
    <Exec Command="packages\FAKE\tools\FAKE.exe build.fsx Build proj=$(ProjectPath) conf=$(Configuration) plat=$(Platform)" WorkingDirectory="..\" />
  </Target>

  <Target Name="Rebuild">
    <Exec Command="packages\FAKE\tools\FAKE.exe build.fsx Rebuild proj=$(ProjectPath) conf=$(Configuration) plat=$(Platform)" WorkingDirectory="..\" />
  </Target>

  <Target Name="Clean">
    <Exec Command="packages\FAKE\tools\FAKE.exe build.fsx Clean proj=$(ProjectPath) conf=$(Configuration) plat=$(Platform)" WorkingDirectory="..\" />
  </Target>
</Project>

Next, at the bottom of <Project /> section in each *.csproj project file I added:

<PropertyGroup>
  <FakeTargetsPath>..\Targets\fake.targets</FakeTargetsPath>
</PropertyGroup>
<Import Project="$(FakeTargetsPath)" Condition="Exists($(FakeTargetsPath)) And '$(RealBuild)'!='true'" />

Note: FakeTargetsPath is relative to the csproj file.

Last step was to create build.fsx that invokes MSBuild with RealBuild = true:

#r @"packages/FAKE/tools/FakeLib.dll"
open Fake

let solution = "solution.sln"

let commonBuild target =
    let project = getBuildParamOrDefault "proj" solution
    let configuration = getBuildParamOrDefault "conf" "Release"
    let platform = getBuildParamOrDefault "plat" "AnyCPU"
    let setParams defaults =
        { defaults with
            Verbosity = Some(Quiet)
            Targets = [ target ]
            Properties =
                [
                    "Configuration", configuration
                    "Platform", platform
                    "RealBuild", "true"
                ]
        }

    build setParams project

Target "Build" (fun _ ->
    commonBuild "Build"
)

Target "Clean" (fun _ ->
    commonBuild "Clean"
)

Target "Rebuild" (fun _ ->
    commonBuild "Rebuild"
)

RunTargetOrDefault "Build"
kfazi
  • 617
  • 1
  • 9
  • 21
6

The closest I found so far is to define FAKE as an external tool via

 Tools -> External tools...

ExternalTool

Set it to use the output window and to prompt for arguments. Then, define a keyboard shortcut via

 Tools -> Options -> Environment -> Keyboard -> Tools.ExternalCommand6

When you invoke it you can provide a target or just press enter to build the default.

GeorgS
  • 741
  • 5
  • 12