Any way to have a many-buildfile structure in FAKE?

f#, f#-fake, f#-fake-4

Solution

Here's a solution I came up with. I had to separate out the targets from the build process, due to the realities of `#load` and the FAKE process for running targets. But it at least accomplishes my goal. I'm not entirely sure how I feel about it, because of the "loose" connection between the inter-file dependencies; but perhaps one could argue that that is a good thing.

Problem

In FAKE you typically have a buildscript like: ``` // "foo.fsx" #r @"./packages/tools/FAKE/tools/FakeLib.dll" open Fake Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" ) Run "Foo" ``` Which works fine. Now suppose you want another buildscript, called "bar.fsx", ``` // "bar.fsx" #r @"./packages/tools/FAKE/tools/FakeLib.dll" #load "foo.fsx" open Fake Target "Bar" (fun _ -> trace "And you have me building software ..." ) Run "Bar" ``` This is now wrong. If you try and run "bar.fsx" it will first execute the task "Foo" even though I didn't explicitly ask for that as a dependency. It's because the `load` directive runs the `foo.fsx` script. So, my question is, how can I import the `foo.fsx` file, obtain all the Targets, but not execute say the `Run` command. Or perhaps more interestingly, and what I really want to do; how can I share `Target`s between scripts in FAKE? It doesn't help if I put the `Target` definitions into a module, like so: ``` module FooTargets = Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" ) ``` which is perhaps mildly surprising to me ... Appreciate any advice on how to accomplish this. My "best" idea so far has been to define some constant in say 'foo.fsx' and then conditionally `load` it in all other scripts. This seems pretty offensive, though (edit: and happily, not even possible.) -- Update: Below is a more complete (i.e. runnable) example. It fails with FAKE 2.2.12.0, with a Duplicate Key error, as the module Common has been loaded twice, and FAKE has populated the target dictionary with the same "Env" target. ``` // "common.fsx" #r @"../../tools/FAKE/FakeLib.dll" open Fake module Common = Target "Env" (fun _ -> trace "Env") ``` , ``` // "foo.fsx" #r @"../../tools/FAKE/FakeLib.dll" #load @"common.fsx" open Fake module Foo = Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" ) "Env" ==> "Foo" ``` , ``` // "bar.fsx" #r @"../../tools/FAKE/FakeLib.dll" #load @"common.fsx" open Fake module Bar = Target "Bar" (fun _ -> trace "And you have me building software ..." ) "Env" ==> "Bar" ``` , ``` // "marvin.fsx" #r @"../../tools/FAKE/FakeLib.dll" #load @"common.fsx" #load @"foo.fsx" #load @"bar.fsx" open Fake module Marvin = Target "Marvin" (fun _ -> ()) "Bar" ==> "Marvin" "Foo" ==> "Marvin" Run "Marvin" ``` Build with: `fake.exe Marvin.fsx`. Error: ``` System.TypeInitializationException: The type initializer for '<StartupCode$FSI_0002>.$FSI_0002_Common$fsx' threw an exception. ---> System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at Fake.TargetHelper.targetFromTemplate[a](TargetTemplate`1 template, String name, a parameters) at Fake.TargetHelper.TargetTemplateWithDependecies@140.Invoke(String name, a parameters) at <StartupCode$FSI_0002>.$FSI_0002_Common$fsx..cctor() in c:\Users\Noon\dev\beep\common.fsx:line 7 --- End of inner exception stack trace --- at <StartupCode$FSI_0002>.$FSI_0002_Foo$fsx.main@() in c:\Users\Noon\dev\beep\foo.fsx:line 8 Stopped due to error Searching for process with name = fsi.exe Searching for process with name = msbuild ```

Original source