Msbuild: UsingTask within a Target?

Created on 20 May 2016  路  7Comments  路  Source: dotnet/msbuild

Is it possible to have a UsingTask definition within a target?

My use-case is that I have a custom task within the same solution as the code that it is being applied to. Both co-evolve, so I'd like to have the custom task as a project reference of the projects that it's being applied to, and always use the latest build of the custom task for the consecutive projects of the same build. Is something like that possible, and of so how?

Thanks!

Postponed

Most helpful comment

No, this isn't currently possible. UsingTasks are handled in pass 4 of the evaluator, before Targets are thought about and before the build itself (that is, target/task execution) even starts.

This is a reasonable feature request, though. I don't see a conceptual problem with doing it.

I can think of a couple of possible (untested) workarounds:

  • Make your actual task assembly a teeny-tiny shim that just calls out to a DLL with the real implementation. Then make sure the DLL is updated before invoking the task for the first time in a build with the appropriate project references.
  • use CodeTaskFactory to build your task. You can point to files on disk, and MSBuild itself will handle building the task assembly for you, so it's "always" up to date. Of course, this makes developing and debugging the task more difficult.

All 7 comments

No, this isn't currently possible. UsingTasks are handled in pass 4 of the evaluator, before Targets are thought about and before the build itself (that is, target/task execution) even starts.

This is a reasonable feature request, though. I don't see a conceptual problem with doing it.

I can think of a couple of possible (untested) workarounds:

  • Make your actual task assembly a teeny-tiny shim that just calls out to a DLL with the real implementation. Then make sure the DLL is updated before invoking the task for the first time in a build with the appropriate project references.
  • use CodeTaskFactory to build your task. You can point to files on disk, and MSBuild itself will handle building the task assembly for you, so it's "always" up to date. Of course, this makes developing and debugging the task more difficult.

Closing because this has workarounds and seems unlikely to come to the top of the feature-request list in the foreseeable future. If anyone would like to argue that it should, feel free to make a case.

@rainersigwald, this is something that could make source-build significantly simple for WPF on .NET Core.

I'm trying to puzzle out the best way to do markup compilation using (a) PresenationBuildTasks (PBT) that is built in our repo and (b) copy of Microsoft.WinFx.targets in our repo that we ship in the Sdk.

Ideally, we'd build our projects (that require Xaml compilation) as Net.Sdk projects, import Microsoft.WinFx.targets, and ProjectReference the WPF assemblies we need during build - so far, so good.

The trick is in having the full path to PresentationBuildTasks before we import Microsoft.winfx.targets, so that resolves correctly. Right now, that requires calling an MSBuild task on PresentationBuildTasks.csproj and collecting the resultant path to the assembly, and then passing it along to UsingTask - something that's not possible.

If UsingTask were allowed within targets, I could write a preamble targets that runs before any of the PBT supplied targets, checks that was called (a bool flag could be set), and if not, call UsingTask from within that preamble.

As is, I can try to make it all work using the existing infrastructure and the workarounds you've outlined here, but it is going to look very complicated.

I just replied to a similar question internally:

One option would be to add a target after ResolveProjectReferences and before the target that uses the task that copies the output of the task project (from the output of RPR) to a known location under the current project鈥檚 obj directory (something like $(IntermediateOutputPath)\TaskAssembly.dll), and use that in the UsingTask(probably by defining a property for both the destination of the copy and the using. This takes advantage of the fact that the assembly isn't loaded until a task in it is _used_, so the assembly doesn't need to exist at evaluation time.

assembly isn't loaded until a task in it is _used_

That's a great tip - thanks!

I just replied to a similar question internally:

One option would be to add a target after ResolveProjectReferences and before the target that uses the task that copies the output of the task project (from the output of RPR) to a known location under the current project鈥檚 obj directory (something like $(IntermediateOutputPath)\TaskAssembly.dll), and use that in the UsingTask(probably by defining a property for both the destination of the copy and the using. This takes advantage of the fact that the assembly isn't loaded until a task in it is _used_, so the assembly doesn't need to exist at evaluation time.

I'm just curious, how would that look like? And is this just an idea/theory, or does this really work?

@biohazard999

I was able to use this pattern successfully. See Pbt.targets for how we did it in WPF to use locally built PresentationBuildTasks.dll to run markup compilation for building WPF product assemblies like System.Windows.Controls.Ribbon.dll etc.

Was this page helpful?
0 / 5 - 0 ratings