Use custom MSBuild tasks from the same solution?
Asked Answered
S

7

26

I'm a new to MSBuild and wanted to play around with it a bit, but I just cannot figure out why this isn't working.

So my solution has two projects: "Model" and "BuildTasks". BuildTasks just has a single class:

using Microsoft.Build.Utilities;

namespace BuildTasks
{
    public class Test : Task
    {
        public override bool Execute()
        {
            Log.LogMessage( "FASDfasdf" );
            return true;
        }
    }
}

And then in the Model.csproj I've added this:

  <UsingTask TaskName="BuildTasks.Test" AssemblyFile="$(SolutionDir)src\BuildTasks\bin\BuildTasks.dll" />
  <Target Name="AfterBuild">
    <Test />
  </Target>

I've set up the build order so "BuildTasks" gets built before "Model". But when I try to build Model I get this error:

The "BuildTasks.Test" task could not be loaded from the assembly C:\WIP\TestSolution\src\BuildTasks\bin\BuildTasks.dll. Could not load file or assembly 'file:///C:\WIP\TestSolution\src\BuildTasks\bin\BuildTasks.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct, and that the assembly and all its dependencies are available.

This file definitely exists, so why can't MSBuild find it?

I've even tried hard-coding "C:\WIP\TestSolution" in place of "$(SolutionDir)" and get the same error. However, if I copy that .dll to my desktop and hard-code the path to my desktop, it DOES work, which I can't figure out why.

EDIT: I don't have the path wrong. I modified the Debug/Release builds for BuildTasks to output the .dll to just the bin folder since I didn't want Debug/Release to have different paths.

Slit answered 12/11, 2008 at 0:23 Comment(2)
Did you manage to solve the problem? I am having the same issue.Arellano
3 years without a resolution? I am having this problem but this post doesn't help a bit as it's not clear the problem was ever resolved...Shreveport
S
15

We tried this and we found that you have to place the UsingTask at the top of the project file (and have all your paths right). However once thats in place and the task loads up it will only work once. After that the build starts failing because it cant copy the DLL that the task is in. We are actually running a post build task thats inside the same assembly/project that we are building.

What we did to solve this is to launch a separate MSBuild process on a seperate MSBuild file to run the Post Build tasks. That way the DLL is not loaded until after its built and copied to the bin directory.

<Target Name="AfterBuild">
    <Exec Command="$(MSBuildBinPath)\MSBuild.exe 
          &quot;$(MSBuildProjectDirectory)\PostBuild.msbuild&quot; 
          /property:SomeProperty=$(SomeProperty)" />
</Target>

Note that you can pass properties into this sub-build task on the command line.

And the PostBuild.msbuild looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="PostBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
    <UsingTask TaskName="PostBuild" AssemblyFile="$(MSBuildProjectDirectory)\bin\AssemblyThatJustBuiltAndContainsBuildTask.dll" />
    <PropertyGroup>
        <SomeProperty>SomePropertyDefaultValue</SomeProperty>
    </PropertyGroup>

    <Target Name="PostBuild">
        <MyPostBuildTask SomeProperty="$(SomeProperty)" />
    </Target>
</Project>
Steward answered 8/7, 2010 at 21:52 Comment(0)
B
5

The locking of the custom task DLLs can be avoided if all custom tasks inherit from AppDomainIsolatedTask and if you set the environment variable MSBUILDDISABLENODEREUSE = 1 before starting Visual Studio.

The assembly with the custom build tasks is locked both by devenv.exe and by msbuild.exe.

You can make the msbuild.exe processes go away with MSBUILDDISABLENODEREUSE = 1, but devenv.exe will still sporadically lock the custom task assembly if your custom tasks inherit from Task.

On the other hand, if you only inherit from AppDomainIsolatedTask and do not set MSBUILDDISABLENODEREUSE the idle MSBuild processes will still lock the assembly.

Button answered 20/5, 2016 at 10:46 Comment(2)
Can you explain a bit more?Antic
I have expanded the answer.Button
A
2

Slace had it right. You more than likely have your path to the assembly wrong. And it should probably be:

<UsingTask 
    TaskName="BuildTasks.Test" 
    AssemblyFile="$(SolutionDir)src\BuildTasks\bin\$(Configuration)\BuildTasks.dll" />

<Target Name="AfterBuild">
    <Test />
</Target>
Asper answered 12/11, 2008 at 1:55 Comment(1)
@Tinister: Per your edit above, using $(Configuration) in the path is the right way, as it will be either 'Release' or 'Debug' (or whatever other name you use)With
B
2

Disabling MSBuild node reuse will also fix this issue:

  • On the MSBuild command line, pass the /nr:false option.
  • For Visual Studio, you have to set the MSBUILDDISABLENODEREUSE environment variable to 1 before starting VS.

See Visual Studio 2012 RTM has MSBuild.exe in memory after close

Button answered 20/5, 2016 at 10:9 Comment(0)
E
0

Are you sure you have your path write? Shouldn't it be in the bin\Configuration Type\BuildTasks.dll?

I found this link: http://bartdesmet.net/blogs/bart/archive/2008/02/15/the-custom-msbuild-task-cookbook.aspx (archived copy) very helpful when starting to write MSBuild tasks.

Erlond answered 12/11, 2008 at 0:33 Comment(0)
C
0

You might try fuslogvw to diagnose the issue, thought I'm unclear if it's getting that far...

http://msdn.microsoft.com/en-us/library/e74a18c4.aspx

Conveyance answered 12/11, 2008 at 23:8 Comment(0)
B
0

In our case, addition of PlaformTarget to the project file (.csproj), resolved the issue.

Bear answered 8/9, 2020 at 11:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.