New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux, MSBuild does not support the task factory "CodeTaskFactory" #616

Closed
jyoungyun opened this Issue May 13, 2016 · 21 comments

Comments

Projects
None yet
9 participants
@jyoungyun

jyoungyun commented May 13, 2016

I got the below error message when I tried to build csproj file in coreclr project.

error MSB4801: The task factory "CodeTaskFactory" could not be loaded because this version of MSBuild does not support it. [/home/jyoung/git/dotnet/coreclr_buildtestsh/tests/src/GC/Regressions/v2.0-beta2/462651/462651.csproj]

The MSBuild.exe version is 14.1 and it is downloaded by init-tools.sh from nuget.

root@jyoung-Samsung-DeskTop-System:/home/jyoung/git/dotnet/coreclr_buildtestsh/Tools# ./corerun MSBuild.exe /version
Microsoft (R) Build Engine version 14.1.0.0
Copyright (C) Microsoft Corporation. All rights reserved.

14.1.0.0

CoreClr creates GenerateParamList in CLRTest.Execute.targets like below.
But as I know, the latest version does not support Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll.
Instead we can use Microsoft.Build.Tasks.Core.dll. So I changed it but it still failed and the error msg was the same.

<UsingTask                                                                    
    TaskName="GenerateParamList"                                                
    TaskFactory="CodeTaskFactory"                                               
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">          

What can I do to fix it ?

(I tired to build msbuild too, because it also uses UsingTask element. But it built successfully and there is no distinction btw init-tools.sh in coreclr and init-tools.sh in msbuild. I think this issue might be related to CoreCLR envrionment. But I couldn't find it...)

@wjk

This comment has been minimized.

wjk commented May 15, 2016

@jyoungyun Unfortunately, MSBuild on .NET Core does not support CodeTaskFactory. This is because CodeTaskFactory is built using the deprecated System.CodeDom.Compiler APIs, that are only available in the full .NET Framework, which is Windows-only. (CodeTaskFactory can in theory be rewritten on top of the open-source Roslyn project, but that entails significant work and has not yet been attempted.)

@jyoungyun

This comment has been minimized.

jyoungyun commented May 15, 2016

@wjk Thank you for your comments! I can't get any info about this error. But I can build MSBuild successfully on Linux and it also uses UsingTask with CodeTaskFactory. What is the difference btw MSBuild and CoreCLR? (MSBuild uses the element in source file by comparison with targets file in CoreCLR. Does it make difference?)

@wjk

This comment has been minimized.

wjk commented May 15, 2016

Most likely when you build MSBuild on Linux, it has been compiled against Mono instead of .NET Core. Unlike .NET Core, Mono supports System.CodeDom.Compiler.

@jyoungyun

This comment has been minimized.

jyoungyun commented May 15, 2016

@wjk Got it. I need to find other way to replace CodeTaskFactory. Your comments are a lot of help to me. Thank you!

@rainersigwald

This comment has been minimized.

Contributor

rainersigwald commented May 16, 2016

@jyoungyun You can always compile your own task assembly as a DLL and load it from there, instead of compiling the assembly at build time with CodeTaskFactory. The full-framework instructions at https://msdn.microsoft.com/en-us/library/t9883dzc.aspx look good, except that the project should a) target the CoreCLR/.NET Standard 1.3 and b) reference the CoreCLR, 14.1 versions of MSBuild assemblies.

@jyoungyun

This comment has been minimized.

jyoungyun commented May 16, 2016

@rainersigwald Thank you for your comments! I'm trying to create a task assembly as a DLL. And I'm going to use UsingTask element to load the task, it makes the same result with CodeTaskFactory I think.

@iskiselev

This comment has been minimized.

iskiselev commented Sep 7, 2017

@rainersigwald, will task that reference 14.1 versions of MSBuild assemblies work with Visual Studio 2013 or earlier? What is recommended way to create msbuild task, that will work in earlier VS version alongside with dotnet build?

@dls314

This comment has been minimized.

dls314 commented Dec 20, 2017

For those arriving from search, see also: https://github.com/jeffkl/RoslynCodeTaskFactory

@rainersigwald

This comment has been minimized.

Contributor

rainersigwald commented Dec 20, 2017

@iskiselev There's no good way to write a single task assembly that works on MSBuild 4 or 12 and on .NET Core MSBuild. I'd suggest shipping multiple assemblies, one compiled against an old MSBuild and one compiled against the 14.1 assemblies, and using two <UsingTask>s conditioned on $(MSBuildAssemblyVersion).

@ro-jo

This comment has been minimized.

ro-jo commented Mar 19, 2018

I know this topic is closed. I installed RoslynCodeTaskFactory and it works perfectly, but with one problem - there's a catch-22 isn't there?

  • User 1 updates Project X with PackageReference + new UsingTask with RoslynCodeTaskFactory
  • User 2 pulls the change, build fails because RoslynCodeTaskFactory doesn't exist, 'UsingTask' statement cannot succeed unless RoslynCodeTaskFactory already installed...

It's unacceptable to me to commit changes that will break builds, am I doing something wrong, or should RoslynCodeTaskFactory be integrated into the default dotnet msbuild tools?

@jeffkl

This comment has been minimized.

Contributor

jeffkl commented Mar 19, 2018

@ro-jo The <UsingTask /> should have a condition on it so that its not created unless packages have been restored. My sample has the condition on there but people miss it. Condition=" '$(RoslynCodeTaskFactory)' != '' "

<UsingTask  
    TaskName="DoNothing"  
    TaskFactory="CodeTaskFactory"  
    AssemblyFile="$(RoslynCodeTaskFactory)"
    Condition=" '$(RoslynCodeTaskFactory)' != '' ">

Users must restore packages before building to ensure a successful result. RoslynCodeTaskFactory is no different then any package in that way. If you reference Newtonsoft.Json but a user does not restore first, they will get compilation errors.

dotnet build does an implicit restore for you unless you specify --no-restore. So by adding a condition and users just running dotnet build, everything should work perfectly. On Windows, Visual Studio does a restore before building and MSBuild.exe has a /restore argument that runs a restore prior to building.

@ro-jo

This comment has been minimized.

ro-jo commented Mar 19, 2018

@jeffkl Firstly - thanks for providing CodeTaskFactory - it's the most useful of all MSBuild tasks. In fact it's probably the only task anyone needs.

I had the condition, everything looked ok but still NuGet restore wasn't pulling the package, and even after I installed it manually, $(RoslynCodeTaskFactory) was empty...

I was calling my 'UsingTask' with AfterTargets = 'PrepareForBuild', I thought it might be the reason, so changed it to AfterTargets='Restore' - still didn't work.

Then I noticed that for some reason 'InitialTargets' in the project file had been set to the target that was calling the CodeTaskFactory 'UsingTask'. I deleted it and everything works as expected. I just didn't notice the change. It wasn't put there by VS or anything, one of our team did it - sorry.

@abatishchev

This comment has been minimized.

abatishchev commented May 20, 2018

Any chance CodeTaskFactory will work one day on Core without 3rd party packages?

@eduherminio

This comment has been minimized.

eduherminio commented May 20, 2018

#3175

@abatishchev

This comment has been minimized.

abatishchev commented May 20, 2018

Cool! Do you know what version of Core is going to include that?

@eduherminio

This comment has been minimized.

eduherminio commented May 20, 2018

I guess it will be included in next VS minor release (v15.8), can you confirm it @jeffkl?

@jeffkl

This comment has been minimized.

Contributor

jeffkl commented May 21, 2018

Cool! Do you know what version of Core is going to include that?

RoslynCodeTaskFactory will be available in daily builds of .NET Core CLI after dotnet/cli#9279 goes in.

I guess it will be included in next VS minor release (v15.8), can you confirm it @jeffkl?

Yes, the RoslynCodeTaskFactory will first be available in Visual Studio 2017 15.8 Preview 2. I think that it will be out in the next week or so. My guess is that Visual Studio 2017 15.8 RTM will ship in the summer.

@ro-jo

This comment has been minimized.

ro-jo commented May 22, 2018

@jeffkl
CodeTaskFactory already works in visual studio with core projects (from .Net runtime). It's needed in builds run from the .Net core command line. Am I missing something?

@jeffkl

This comment has been minimized.

Contributor

jeffkl commented May 22, 2018

Yeah its a little confusing. Visual Studio uses MSBuild.exe which is compiled against .NET Framework 4.6. The .NET Core SDK is a collection of build targets and tasks that can run on .NET Framework or .NET Core and emit assemblies that can target either.

So you only truly run .NET Core MSBuild when you run dotnet build. The .NET Core MSBuild can't use the CodeTaskFactory because it uses CodeDom which does not support compiling assemblies cross-platform (it throws a runtime exception that the platform is not supported on Linux and Mac).

The RoslynCodeTaskFactory generates code, references netstandard.dll, and uses the managed compilers that are next to MSBuild. This means it can run the same on .NET Framework and .NET Core.

We did want to just make CodeTaskFactory work on .NET Core but it would have been a very intrusive change which would have a high likelihood of a regression. The last thing we want is for people to upgrade to the latest MSBuild and their build is broken ☹️. So we chose to introduce a new task factory that you have to opt-in to. That way we don't break anyone.

@abatishchev

This comment has been minimized.

abatishchev commented May 22, 2018

Why don't rename the new RoslynCodeTaskFactory to just CodeTaskFactory so nobody would notice?

And another question, please. When the new task will be available on build servers? That's what interests me, rather than when it's shipped with VS. as nothing is worse than when a build works fine locally and not at all on the build server (Windows container on VSTS in my case).

@jeffkl

This comment has been minimized.

Contributor

jeffkl commented May 22, 2018

Why don't rename the new RoslynCodeTaskFactory to just CodeTaskFactory so nobody would notice?

If there's a bug or difference in how RoslynCodeTaskFactory works, you could take a 10 year old code base, upgrade to the latest MSBuild, and no longer be able to build. That is what I'm trying to avoid. If you need to use inline tasks on .NET Core, you've never been able to before. So to start using a new thing, you'll need to use a different task factory. And if you don't care, you don't change the task factory name and we have no chance of breaking you.

When the new task will be available on build servers?

I am not certain how often build servers are updated. I know that AppVeyor has a Visual Studio Preview version which is updated regularly. RoslynCodeTaskFactory will be publicly available in 15.8 Preview 2. Each build system will need to update to that version before you'll be able to use it. And of course, if you really can't wait, you can use my NuGet package immediately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment