GitVersionTask does not work correctly with fsharp projects building an exe.

Created on 27 Sep 2019  Â·  18Comments  Â·  Source: GitTools/GitVersion

When adding the GitVersionTask to a fsharp fsproj that build an exe one get this error message when running dotnet build

C:\Users\...\repos\reproducegvdn\Program.fs(3,1): error FS0222: Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration. [C:\Users\...\repos\reproducegvdn\reproducegvdn.fsproj]

My best guess is that the generated GitVersionInformation.fs file is placed last in the list of files to compile. The Program.fs containing the decorated main function must always be last. See below for details.

Shortest steps to reproduce:

md reproducebug
cd reproducebug
dotnet new console -lang f#
dotnet add package gitversiontask
git init
git add -A
git commit -m "Initial commit"
dotnet build

If one run with dotnet build --verbosity detailed one can find the following input to the fsc compiler (redacted for clarity). Notice the order of the files in the end.

C:\Program Files\dotnet\dotnet.exe "C:\Program Files\dotnet\sdk\2.2.300\FSharp\fsc.exe" -o:obj\Debug\netcoreapp2.2\reproducegvdn.dll
         -g
         --debug:portable
         --noframework
         --define:TRACE
         --define:DEBUG
         --define:NETCOREAPP
         --define:NETCOREAPP2_2
         --optimize-
         --tailcalls-
         ...
         --target:exe
         --warn:3
         --warnaserror:3239,76
         --fullpaths
         --flaterrors
         --highentropyva-
         --targetprofile:netcore
         --nocopyfsharpcore
         --simpleresolution
         C:\Users\...\AppData\Local\Temp\.NETCoreApp,Version=v2.2.AssemblyAttributes.fs
         obj\Debug\netcoreapp2.2\reproducegvdn.AssemblyInfo.fs
         Program.fs
         obj\Debug\netcoreapp2.2\AssemblyInfo_reproducegvdn_da4sk0i1.nf4.g.fs
         obj\Debug\netcoreapp2.2\GitVersionInformation_reproducegvdn_woodujve.ebf.g.fs

Same error with both SDK 2.2.300 and 3.0.100

Most helpful comment

Perhaps the presence of AssemblyVersionAttribute and friends is something we can add a test for by producing an assembly with GitVersion, then loading that assembly and reading its version number?

All 18 comments

I might be missing something here but I think..

What is needed here is that the gitversion__.fs is placed first in the list of fs files to compile. F# Does not like any file to exist after the Program.fs file.

It doesn't make sense to place it in the project file but how could one make it appear first in the list of files to be sent to the compiler?

Yay, I found the cause of the problem and a workaround!
in GitVersionTask.targets UpdateAssemblyInfo and GenerateGitVersionInformation do this:

<ItemGroup>
     <Compile Include="$(AssemblyInfoTempFilePath)" />
</ItemGroup>

<!-- and -->
<ItemGroup>
    <Compile Include="$(GitVersionInformationFilePath)" />
    <FileWrites Include="$(GitVersionInformationFilePath)" />
</ItemGroup>

This appends these two files to the list of files to be compiled. Since F# requires that the [<EntryPoint>] marked expression (in this case in Program.fs) is the last one that is compiled this build will break.

Workaround
We found a workaround: Put the Include Program.fs into a task that is guaranteed to be executed after GitVersionInformationFilePath and UpdateAssemblyInfo. Remove the existing Program.fs inclusion and include it again.
This makes Program.fs to end up as the last file to be compiled.
This seems to be working ok in Visual Studio 2019 but perhaps not in Visual Studio Code (it doesn't show Program.fs in the right place)

  <ItemGroup>
    <Compile Include="SomeFunctions.fs" />
    <Compile Include="Program.fs" />
  </ItemGroup>

  <Target Name="GitVersionInfoBeforeEntryPointFileWorkaround"
          AfterTargets="GenerateGitVersionInformation;UpdateAssemblyInfo"
          DependsOnTargets="GenerateGitVersionInformation;UpdateAssemblyInfo">
    <ItemGroup>
      <Compile Remove="Program.fs" />
      <Compile Include="Program.fs" />
    </ItemGroup>
  </Target>

That's great, @da9l! Is there something that can be adjusted in GitVersion to make this experience better out of the box? If you have ideas, we would love a PR.

Yeah, I've got some ideas. I'll get back with them. Hopefully in a PR.

Den tors 31 okt. 2019 22:51Asbjørn Ulsberg notifications@github.com skrev:

That's great, @da9l https://github.com/da9l! Is there something that
can be adjusted in GitVersion to make this experience better out of the
box? If you have ideas, we would love a PR.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/GitTools/GitVersion/issues/1831?email_source=notifications&email_token=AABD23JQM2CK2TUSB36EBC3QRNHOVA5CNFSM4I3FI562YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECZLSUI#issuecomment-548583761,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AABD23PU2KNBCGXRWM57P2LQRNHOVANCNFSM4I3FI56Q
.

Basically, in f# exe projects the include of the last fs file in project
need to be included after gv generated gitversioninformation and assembly
info.

Not sure how it's best done but I have a few ideas.

/D

Den fre 1 nov. 2019 08:23daniel hegner daniel@hegner.se skrev:

Yeah, I've got some ideas. I'll get back with them. Hopefully in a PR.

Den tors 31 okt. 2019 22:51Asbjørn Ulsberg notifications@github.com
skrev:

That's great, @da9l https://github.com/da9l! Is there something that
can be adjusted in GitVersion to make this experience better out of the
box? If you have ideas, we would love a PR.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/GitTools/GitVersion/issues/1831?email_source=notifications&email_token=AABD23JQM2CK2TUSB36EBC3QRNHOVA5CNFSM4I3FI562YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECZLSUI#issuecomment-548583761,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AABD23PU2KNBCGXRWM57P2LQRNHOVANCNFSM4I3FI56Q
.

Hey, I've seen this issue on Twitter and thought I'd chime in.

The .NET SDK generates an assembly info file for F# projects by default, too, but it doesn't add the newly generated file as an Compile item, but as an CompileBefore item. MSBuild then turns these to Compile items and prepends them to the users files. This package should do that as well for F# projects.

Wow! I really didn't know that. Thanks!
@inosik, do you have a link to any documentation on CompileBefore? I don't get any hit on that in the official ms docs: https://docs.microsoft.com/en-us/search/?search=CompileBefore&category=All
I'm assuming that I'm looking in the wrong place.

@asbjornu do you think it would be a good idea to always add the gitversion generated files as CompileBefore? Regardless of the language?

Ok, some searching tells me this is a F# thing.
https://github.com/dotnet/fsharp/blob/master/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets
I will try to create a PR with a conditional on the inclusion. Have no clue on how to write a test for it tho.

For anyone following this, I've made some progress but it's not complete.
https://github.com/da9l/GitVersion/tree/feature/EnableGitVersionTaskForFSharpExeProjects

I've made the CompileBefore Include conditional wrt the $(Language) property. It still works for C# projects but I'm not getting any version info at all into the F# assemblies.

I'm testing it in this repo: https://github.com/da9l/testgitversiontask4fsexe

Blergh. I've managed to make dotnet build on fsproj to behave nicely when gitversiontask is included. nuget packages are being generated with nice versions.

I'm however unable to get version info into the assemblies. Doing some searching this seems to be a problem with the F# dotnet core compiler that it can't make this work atm. https://github.com/dotnet/fsharp/pull/7220

It should work with Visual Studio 2019.
My goal is to complete the PR anyway and let it be up to the maintainer here to make the call.

Ok. Verified. Assembly info gets into the assemblies when compiling in in VS2019. But not in dotnet cli.

VS2019:
image

dotnet build:
image

Keep in mind that this dialog doesn't show the actual attribute values. .NET assemblies carry some Windows specific resources, which is what the "Properties" dialog shows.

You can check the assembly with the IL Disassembler. If it has the AssemblyVersionAttribute and friends set to the correct values, we're good.

Perhaps the presence of AssemblyVersionAttribute and friends is something we can add a test for by producing an assembly with GitVersion, then loading that assembly and reading its version number?

@inosik I tried to view the dll using ildasm and it shows

.assembly fconsole
{
  .ver 0:1:0:0
}

Don't know if that counts.

Note to anyone looking for this:
As mentioned before the version resource info, visible when displaying file properties on an assembly in windows, is not created when running
dotnet build
but when building with VS or classic msbuild it works
msbuild <yoursln.sln>

Yes, almost. This version is the value of the AssemblyVersion attribute. In your screenshot of the "Properties" dialog above, the value of "File version" is AssemblyFileVersion, and "Product version" is AssemblyInformationalVersion.

What I meant was this:

ildasm_2019-11-11_12-05-42

Thanks!
I got this result that match the output of cli gitversion.

.custom instance void [System.Runtime]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 30 2E 31 2E 30 2E 30 00 00 )             // ...0.1.0.0..
.custom instance void [System.Runtime]System.Reflection.AssemblyVersionAttribute::.ctor(string) = ( 01 00 07 30 2E 31 2E 30 2E 30 00 00 )             // ...0.1.0.0..
.custom instance void [System.Runtime]System.Reflection.AssemblyInformationalVersionAttribute::.ctor(string) = ( 01 00 42 30 2E 31 2E 30 2B 34 2E 42 72 61 6E 63   // ..B0.1.0+4.Branc

Was this page helpful?
0 / 5 - 0 ratings