Skip to content
Oleg edited this page May 18, 2018 · 11 revisions

The file is created for 0.xx version of xake and is now being rewritten for xake 1.x which targets netcore as primary environment. Bootstrap code will change while the other things are left intact.

Creating simple script

The most simple, but structured script looks as follows:

#r "paket:
    nuget Xake ~> 1.1 prerelease
    nuget Xake.Dotnet ~> 1.1 prerelease //" // (1)

open Xake                          // (2)
open Xake.Dotnet                   // (2.1)

do xakeScript {                    // (3)
    rule("main" <== ["hw.exe"])    // (4)
    rule("hw.exe" ..> recipe {     // (5)
        do! Csc {
            CscSettings with
                Src = !! "hw.cs"
        }
    })

    rule (FileRule ("greet", recipe { do! trace Info "hello" }))
}

Here are we doing the following steps:

  1. reference f# libraries containing core functionality and dotnet specific tasks
  2. open Xake namespace, which contains definition of xakeScript and recipe computation expressions, Xake.Dotnet namespace contains definition for Csc task
  3. define a "main" function of the build script
  4. add the rule for "main" target (the default one in case targets are not defined in parameters) which demands "hw.exe" file
  5. define the rule for "hw.exe" target

Running your script

Create a new project and save the script to build.fsx file. The build script is a valid F# script and .fsx is a standard file extension.

  • Both Fake and Xake are available on Nuget so the first step is to download nuget.exe from nuget/downloads page.

Issue the following commands to get Fake and Xake installed in tools folder.

nuget install Xake -excludeVersion -outputdirectory tools
  • Copy the following code to hw.cs file:
class Program
{
    public static void Main()
    {
        System.Console.WriteLine("Hello world!");
    }
}
  • run the build using following command:
fsi.exe build.fsx

You will need fsi tool in your path. Open Visual Studio Command prompt console which adds path to FSI to PATH. The other option is using mono's fsharpi (available on linux, osx, and Windows).

The option which does not require installing Mono or Visual Studio is described on integration page.

What the rule and recipe is?

Recipes

Recipe is block of F# code with some extras such as method for accessing script execution context without using globals or parameters, asynchronous execution, tracking and recording dependencies, and more.

All tasks such as copying files, compiling application (Csc task in the example above) and so on are all recipes. Defining your own recipe is as simple as defining function:

let makePackageName variableName = recipe {
    let! ver = getEnv(variableName)
    return sprintf "Xake.%s.nupkg" (ver =? "0.0.1")
}

In this example getEnv is internal function (and also recipe) for accessing environment variables. Such call is recorded in dependency tree and respective (calling?) rule will be marked as dependent on particular variable. If on the next run the value is changed Xake will rebuild the target.

In order to call the recipe the "bang" versions of "do" and "let" must be used - that is the way to pass context down to recipe.

Rules and dependencies

Rule is a pair of target name and the recipe defining how to build the target.

The following statement defines the rule (but does not add it to script):

let rule = "hi" ..> recipe {do! trace Info "Hello world"}
// equivalent to
let rule = FileRule ("greet", recipe { do! trace Info "hello" })

..> is an infix operator for creating file rule.

The rules directive in script allows to add multiple rules passed as array. For example:

do xake ExecOptions.Default {
    rules [
        "main" <== ["hw.exe"]
        "hw.dll" ..> Csc {CscSettings with Src = !! "util.cs"}
        "hw.exe" ..> Csc {CscSettings with Src = !! "hw.cs"; Ref = !! "hw.dll"}
    ]
}

When build tool meet the Ref pointing to "hw.dll" it looks for rule matching the file name, starts the build step and waits until it completes.

Filesets defined

Filesets are widely used to define source files, list of library modules. Fileset defines the way to get the list of files, but not the list itself.

// define a fileset (!! operator) and add two more files
let refs = !! "bin/FSharp.Core.dll" + "bin/nunit.framework.dll" + "bin/Xake.Core.dll"

// using builder
let sourceFiles = fileset {
    basedir "src"
    includes "**/*.cs"
    includes "../versioninfo.cs"
}

// or...
let sourceFiles2 = +"src" + "**/*.cs" + "../versioninfo.cs"

There's no difference in slash/backslash. Xake will translate it to path separator used in particular operating system. I'm using slash for simplicity (no escaping characters involved).

See some

Operator (example) Description
let src = !! "src/*.cs" Creates a new fileset
let src1 = !! "src/*.cs" + "common.cs" Adds another filemask to a fileset.
let src2 = !! "src/*.cs" - "src/tests.cs" Remove the filemask from fileset
let src = !! "*.cs" @@ "src" Changes "base" directory, which the other masks are related to.
let src3 = src +? (NUNIT, "tests/*.cs") Adds the filemask if condition is met
let src = +"src" + "*.cs" Unary plus creates an empty fileset with specified directory.

Function Fileset.toFileList "executes" the fileset and returns the list of files.

Editing the script

There are many good tools for working with F#. Under Windows it is Visual Studio. Xamarin Studio is available on Windows, OSX, and Linux. These IDEs not only allow to edit script but also provide rich debugging and refactoring tools.

My favourite environment however is Visual Studio Code and Ionide plugin. It takes a couple minutes to download and install; and it works everywhere.