callmekohei's blog

callmekoheiのひとりごと

Build F# code with dotnet and msbuild

This article is F# Advent Calendar2017 8th day ( see : F# Advent Calendar 2017 - Qiita )


f:id:callmekohei00:20171209065402p:plain


Summary

I just try to build F# code with dotnet and msbuild.

Thanks

@yukitos

What is Build?

Build is compile and link.

3 ways of build

I understand a little bit of it. (^_^::

command TargetFramework reference
dotnet netstandard
dotnet msbuild net -p:FrameworkPathOverride
msbuild net Microsoft.FSharp.Targets

Environment

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.13.1
BuildVersion:   17B1003

$ uname -a
Darwin callmekoheis-MacBook-Air.local
17.2.0 Darwin Kernel
Version 17.2.0:
Fri Sep 29 18:27:05 PDT 2017;
root:xnu-4570.20.62~3/RELEASE_X86_64 x86_64

$ mono --version
Mono JIT compiler version 5.0.1.1 (2017-02/5077205 Sun Sep 17 18:29:46 BST 2017)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
    TLS:           normal
    SIGSEGV:       altstack
    Notification:  kqueue
    Architecture:  amd64
    Disabled:      none
    Misc:          softdebug 
    LLVM:          supported, not enabled.
    GC:            sgen (concurrent by default)

Prepare

install msbuild

// download source
$ git clone https://github.com/Microsoft/msbuild.git 

// build ( ignore errors )
$./cibuild.sh --target Mono

// create msbuild command
$ vim msbuild

$HOME/msbuild/packages/msbuild/MSBuild.exe $@

$ chmod 777 msbuild
$ mv msbuild /usr/local/bin/

// check
$ msbuild /version
Microsoft (R) Build Engine version 14.1.0.0
Copyright (C) Microsoft Corporation. All rights reserved.

14.1.0.0

install dotnet

// download binary
https://github.com/dotnet/core/blob/master/release-notes/download-archives/2.0.3.md

// install from a binary archive
$ mkdir dotnet
$ tar zxf ~/Downloads/dotnet-sdk-2.0.3-osx-x64.tar.gz -C $HOME/dotnet

// add PATH
$ vim .bash_profile

export PATH=$PATH:$HOME/dotnet

// check
$ dotnet --version
2.0.3

$ dotnet msbuild /version
Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

15.4.8.50001

dotenet

use dotnet core library

// write F# code
$ vim sample.fsx

printfn "hello"

// write build script
$ vim sample.fsproj

<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netstandard1.6</TargetFramework>
        <DebugType>full</DebugType>
    </PropertyGroup>

    <PropertyGroup Condition="$(OS)=='Unix'">
        <FscToolPath>/usr/local/bin/</FscToolPath>
        <FscToolExe>fsharpc</FscToolExe>
    </PropertyGroup>

    <Target Name="Copy MDBs" AfterTargets="Build">
        <Copy SourceFiles="$(IntermediateOutputPath)/$(AssemblyName).dll.mdb" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
    </Target>

    <ItemGroup>
        <Compile Include="./sample.fsx" />
    </ItemGroup>

</Project>

// create  dependencies specified in the .NET project
$ dotnet restore sample.fsproj

$ tree
.
├── obj
│   ├── project.assets.json
│   ├── sample.fsproj.nuget.cache
│   ├── sample.fsproj.nuget.g.props
│   └── sample.fsproj.nuget.g.targets
├── sample.fsproj
└── sample.fsx

1 directory, 6 files

// build
$ dotnet build sample.fsproj

$ tree
.
├── bin
│   └── Debug
│       └── netstandard1.6
│           ├── sample.deps.json
│           ├── sample.dll
│           └── sample.dll.mdb
├── obj
│   ├── Debug
│   │   └── netstandard1.6
│   │       ├── sample.dll
│   │       ├── sample.dll.mdb
│   │       ├── sample.fsproj.CoreCompileInputs.cache
│   │       └── sample.fsproj.FileListAbsolute.txt
│   ├── project.assets.json
│   ├── sample.fsproj.nuget.cache
│   ├── sample.fsproj.nuget.g.props
│   └── sample.fsproj.nuget.g.targets
├── sample.fsproj
└── sample.fsx

6 directories, 13 files

// run
$ mono ./bin/Debug/netstandard1.6/sample.dll
hello

dotenet msbuild

use dotnet library

// write F# code
$ vim sample.fsx

printfn "hello"

// write build script
$ vim sample.fsproj

<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net45</TargetFramework>
        <DebugType>full</DebugType>
    </PropertyGroup>

    <PropertyGroup Condition="$(OS)=='Unix'">
        <FscToolPath>/usr/local/bin/</FscToolPath>
        <FscToolExe>fsharpc</FscToolExe>
    </PropertyGroup>

    <Target Name="Copy MDBs" AfterTargets="Build">
        <Copy SourceFiles="$(IntermediateOutputPath)/$(AssemblyName).exe.mdb" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
    </Target>

    <ItemGroup>
        <Compile Include="./sample.fsx" />
    </ItemGroup>

</Project>

// download .NET library
$ svn export https://github.com/mono/reference-assemblies/trunk/v4.5

// create  dependencies specified in the .NET project
$ dotnet restore sample.fsproj

$ tree
.
├── obj
│   ├── project.assets.json
│   ├── sample.fsproj.nuget.cache
│   ├── sample.fsproj.nuget.g.props
│   └── sample.fsproj.nuget.g.targets
├── sample.fsproj
├── sample.fsx
└── v4.5
    ├── Accessibility.dll
    ├── CustomMarshalers.dll
    ├── Facades
    │   ├── System.Collections.Concurrent.dll
    ...

// build
$ dotnet msbuild -p:FrameworkPathOverride=./v4.5 sample.fsproj 

$ tree
.
├── bin
│   └── Debug
│       └── net45
│           ├── FSharp.Core.dll
│           ├── System.Core.dll
│           ├── System.Data.dll
│           ├── System.Drawing.dll
│           ├── System.EnterpriseServices.dll
│           ├── System.IO.Compression.FileSystem.dll
│           ├── System.IO.Compression.dll
│           ├── System.Numerics.dll
│           ├── System.Runtime.Serialization.dll
│           ├── System.Transactions.dll
│           ├── System.ValueTuple.dll
│           ├── System.Xml.Linq.dll
│           ├── System.Xml.dll
│           ├── System.dll
│           ├── mscorlib.dll
│           ├── sample.exe
│           └── sample.exe.mdb
├── obj
│   ├── Debug
│   │   └── net45
│   │       ├── sample.exe
│   │       ├── sample.exe.mdb
│   │       ├── sample.fsproj.CopyComplete
│   │       ├── sample.fsproj.CoreCompileInputs.cache
│   │       └── sample.fsproj.FileListAbsolute.txt
│   ├── project.assets.json
│   ├── sample.fsproj.nuget.cache
│   ├── sample.fsproj.nuget.g.props
│   └── sample.fsproj.nuget.g.targets
├── sample.fsproj
├── sample.fsx
└── v4.5
    ├── Accessibility.dll
    ├── CustomMarshalers.dll
    ├── Facades
    ....

// run
$ mono ./bin/Debug/net45/sample.exe
hello

msbuild

use dotnet library

// write F# code
$ vim sample.fsx

printfn "hello"

// write build script
$ vim sample.fsproj

<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net45</TargetFramework>
        <DebugType>full</DebugType>
    </PropertyGroup>

    <PropertyGroup Condition="$(OS)=='Unix'">
        <FscToolPath>/usr/local/bin/</FscToolPath>
        <FscToolExe>fsharpc</FscToolExe>
    </PropertyGroup>

    <Target Name="Copy MDBs" AfterTargets="Build">
        <Copy SourceFiles="$(IntermediateOutputPath)/$(AssemblyName).exe.mdb" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
    </Target>

    <ItemGroup>
        <Compile Include="./sample.fsx" />
    </ItemGroup>

    <Import Project="/usr/local/Cellar/mono/5.0.1.1/lib/mono/fsharp/Microsoft.FSharp.Targets" />

</Project>

// build
$ msbuild sample.fsproj 

$ tree
.
├── bin
│   └── Debug
│       ├── sample.exe
│       └── sample.exe.mdb
├── obj
│   └── Debug
│       ├── sample.exe
│       ├── sample.exe.mdb
│       ├── sample.fsproj.FileListAbsolute.txt
│       └── sample.fsprojResolveAssemblyReference.cache
├── sample.fsproj
└── sample.fsx

4 directories, 8 files

// run
$ mono ./bin/Debug/sample.exe
hello