.NET Framework Bookmark and Share   
 index > MSBuild > Solution building succesfully in Visual Studio 2008 fails to build in MSBuild command line
 

Solution building succesfully in Visual Studio 2008 fails to build in MSBuild command line


We have a solution with all standard .NET 3.5 projects (Silverlight 3, RIA Services enabled, Enterprise Lib projects). The solution builds without any problems inside Visual Studio, however when building from the command line with MSBuild (MSBuild MySolution.sln), it fails to build.

We get the following errors:

error CS0246: The type or namespace name 'ICategory' could not be found (are you missing a using directive or an assembly reference?)


... and more of these (on 4 Silverlight projects in total).

However, these projects contain the correct project references (that's why it's also building inside VS).

After days of trying to figure out what happens in the core msbuild files (Microsoft.Common.Targets) and the MSBuild log files, I discovered the following:

... in the log file of MSBuild:

Task "AssignProjectConfiguration"
Project reference "..\IntraCityNet.Sample.Framework\IntraCityNet.Sample.Framework.csproj" has been assigned the "Debug|AnyCPU" configuration.
Project reference "..\Yuse.Framework.Silverlight\Yuse.Framework.Silverlight.csproj" has been assigned the "Debug|AnyCPU" configuration.
Done executing task "AssignProjectConfiguration".
... so the references for this project have been correctly identified by MSBuild

on the following lines:
Done building target "SplitProjectReferencesByType" in project "IntraCityNet.Sample.Module.PostIt.Context.csproj".
Target "SplitProjectReferencesByType" skipped. Previously built successfully.
Target "_SplitProjectReferencesByFileExistence" skipped. Previously built successfully.
and again a bit further, he starts compiling the project:
Task "Csc"
Command:
c:\WINDOWS\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /nostdlib+ /errorreport:prompt /warn:4 /define:DEBUG;TRACE;SILVERLIGHT /reference:..\Lib\Silverlight\mscorlib.dll /reference:..\Lib\Silverlight\System.ComponentModel.DataAnnotations.dll /reference:..\Lib\Silverlight\System.Core.dll /reference:..\Lib\Silverlight\system.dll /reference:..\Lib\Silverlight\System.Net.dll /reference:..\Lib\Silverlight\System.Runtime.Serialization.dll /reference:..\Lib\Silverlight\System.Windows.Browser.dll /reference:..\Lib\Silverlight\System.Windows.dll /reference:..\Lib\Ria\System.Windows.Ria.dll /reference:..\Lib\Silverlight\System.Xml.dll /debug+ /debug:full /optimize- /out:obj\Debug\IntraCityNet.Sample.Module.PostIt.Context.dll /target:library Category.cs CategorySummary.cs Generated_Code\IntraCityNet.Sample.Web.g.cs PostItCategory.cs Properties\AssemblyInfo.cs c:\B\MyJames\CI_MyJames\Sources\Source\IntraCityNet.Sample.Module.PostIt.Context\Generated_Code\IntraCityNet.Sample.Web.g.cs
The "Csc" task is using "Csc.exe" from "c:\WINDOWS\Microsoft.NET\Framework\v3.5\Csc.exe".
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

CSC : warning CS2002: Source file 'c:\B\MyJames\CI_MyJames\Sources\Source\IntraCityNet.Sample.Module.PostIt.Context\Generated_Code\IntraCityNet.Sample.Web.g.cs' specified multiple times
Category.cs(5,36): error CS0246: The type or namespace name 'ICategory' could not be found (are you missing a using directive or an assembly reference?)
CategorySummary.cs(5,44): error CS0246: The type or namespace name 'ICategorySummary' could not be found (are you missing a using directive or an assembly reference?)
PostItCategory.cs(5,42): error CS0246: The type or namespace name 'IItemCategory' could not be found (are you missing a using directive or an assembly reference?)
The compilation error is normal, as MSBuild decided not to add the (needed) project references to the csc command as paramaters. The question is ... why did MSBuild decide to do that?

I think it is suspicious that MSBuild decided to skip the target "_SplitProjectReferencesByFilExistence" ("Previously built successfully."). I searched in the log where this target was previously called for this project:

Project "c:\B\MyJames\CI_MyJames\Sources\Source\IntraCityNet.Sample.Module.PostIt\IntraCityNet.Sample.Module.PostIt.csproj" (31:2) is building "c:\B\MyJames\CI_MyJames\Sources\Source\IntraCityNet.Sample.Module.PostIt.Context\IntraCityNet.Sample.Module.PostIt.Context.csproj" (32:7) on node 0 (GetCopyToOutputDirectoryItems target(s)).
...
Target "_SplitProjectReferencesByFileExistence" in file "c:\WINDOWS\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets" from project "c:\B\MyJames\CI_MyJames\Sources\Source\IntraCityNet.Sample.Module.PostIt.Context\IntraCityNet.Sample.Module.PostIt.Context.csproj":

So the _SplitProjectReferenceByFileExistence target was last called for this project from the GetCopyToOutputDirectoryItems target.

I think that at that time, the _MSBuildProjectReferenceExistent item collection is being "cleared".

A bit later, MSBuild decides to build/compile (default target) the project again, but (as I described above) because the SplitProjectReferenceByFileExistence target was already called, it decides to skip it ... and finally passes to the csc command the empty _MSBuildProjectReferenceExistent list.

... and then we get the compilation error.

I managed to implement a temporary workaround by overriding some of the targets with my "CustomAfterMicrosoftCommon.targets" file, listed below:

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

  <!--
    ============================================================
                                        _YuseSplitProjectReferencesByFileExistence

    Split referenced projects into two lists: those that exist on
    disk and those that don't.
    + Yuse patch: this target is always called except when executing target GetCopyToOutputDirectoryItems (then the original _SplitProjectReferencesByFileExistence gets called)
    ============================================================
    -->
  <Target
    Name="_YuseSplitProjectReferencesByFileExistence">
    <Message Text="YUSE (_YuseSplitProjectReferencesByFileExistence): in _YuseSplitProjectReferencesByFileExistence" />

    <!--
        Use this task for matching projects with pre-resolved project outputs set by the IDE
        if building inside the IDE.  The IDE only includes non-MSBuild projects in the output list.  We'll
        use MSBuild to resolve MSBuild projects.
        This task will resolve VSIP (3rd party) project references and create a new item list with only project references
        to projects in the MSBuild format.
        -->
    <ResolveNonMSBuildProjectOutput
        ProjectReferences="@(NonVCProjectReference)"
        PreresolvedProjectOutputs="$(VSIDEResolvedNonMSBuildProjectOutputs)"
        Condition="'$(BuildingInsideVisualStudio)'=='true' and '@(NonVCProjectReference)'!=''">

      <Output TaskParameter="ResolvedOutputPaths" ItemName="_ResolvedProjectReferencePaths"/>
      <Output TaskParameter="UnresolvedProjectReferences" ItemName="_MSBuildProjectReference"/>

    </ResolveNonMSBuildProjectOutput>

    <!--
       If building from the command line, simply copy the NonVCProjectReference item list to _MSBuildProjectReference,
       since we have to assume all non-VC projects are in the MSBuild format. We have no way of building
       VSIP (3rd party) projects from the command line.
       -->
    <ItemGroup>
      <_MSBuildProjectReference Include="@(NonVCProjectReference)" Condition="'$(BuildingInsideVisualStudio)'!='true' and '@(NonVCProjectReference)'!=''"/>
    </ItemGroup>

    <!-- Break the project list into two lists: those that exist on disk and those that don't. -->
    <ItemGroup>
      <_MSBuildProjectReferenceExistent Include="@(_MSBuildProjectReference)" Condition="Exists('%(Identity)')"/>
      <_MSBuildProjectReferenceNonexistent Include="@(_MSBuildProjectReference)" Condition="!Exists('%(Identity)')"/>
    </ItemGroup>

    <Message Text="YUSE (_YuseSplitProjectReferencesByFileExistence): _MSBuildProjectReferenceExistent=@(_MSBuildProjectReferenceExistent)" />

    <Message Text="YUSE (_YuseSplitProjectReferencesByFileExistence): _MSBuildProjectReference=@(_MSBuildProjectReference)" />

  </Target>


  <Target
       Name="CleanReferencedProjects"
       DependsOnTargets="SplitProjectReferencesByType; _YuseSplitProjectReferencesByFileExistence">

    <!--
        When building the project directly from the command-line, clean those referenced projects
        that exist on disk.  For IDE builds and command-line .SLN builds, the solution build manager
        takes care of this.
        -->
    <MSBuild
        Projects="@(_MSBuildProjectReferenceExistent)"
        Targets="Clean"
        BuildInParallel="$(BuildInParallel)"
        UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)"
        Condition="'$(BuildingInsideVisualStudio)' != 'true' and '$(BuildingSolutionFile)' != 'true' and '$(BuildProjectReferences)' == 'true' and '@(_MSBuildProjectReferenceExistent)' != ''" />

  </Target>

  <Target
        Name="ResolveProjectReferences"
        DependsOnTargets="SplitProjectReferencesByType;_YuseSplitProjectReferencesByFileExistence">

    <!--
        When building this project from the IDE or when building a .SLN from the command-line,
        just gather the referenced build outputs.  The code that builds the .SLN will already have
        built the project, so there's no need to do it again here.

        The ContinueOnError setting is here so that, during project load, as
        much information as possible will be passed to the compilers.
        -->

    <Message Text="YUSE (_MSBuildProjectReferenceExistent): _MSBuildProjectReferenceExistent=@(_MSBuildProjectReferenceExistent)" />

    <MSBuild
        Projects="@(_MSBuildProjectReferenceExistent)"
        Targets="GetTargetPath"
        BuildInParallel="$(BuildInParallel)"
        UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)"
        Properties="%(_MSBuildProjectReferenceExistent.SetConfiguration); %(_MSBuildProjectReferenceExistent.SetPlatform)"
        Condition="'@(NonVCProjectReference)'!='' and ('$(BuildingSolutionFile)' == 'true' or '$(BuildingInsideVisualStudio)' == 'true' or '$(BuildProjectReferences)' != 'true') and '@(_MSBuildProjectReferenceExistent)' != ''"
        ContinueOnError="!$(BuildingProject)">

      <Output TaskParameter="TargetOutputs" ItemName="_ResolvedProjectReferencePaths"/>

    </MSBuild>

    <!--
        Build referenced projects when building from the command line.

        The $(ProjectReferenceBuildTargets) will normally be blank so that the project's default
        target is used during a P2P reference. However if a custom build process requires that
        the referenced project has a different target to build it can be specified.
        -->
    <MSBuild
        Projects="@(_MSBuildProjectReferenceExistent)"
        Targets="$(ProjectReferenceBuildTargets)"
        BuildInParallel="$(BuildInParallel)"
        UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)"
        Condition="'@(NonVCProjectReference)'!='' and '$(BuildingInsideVisualStudio)' != 'true' and '$(BuildingSolutionFile)' != 'true' and '$(BuildProjectReferences)' == 'true' and '@(_MSBuildProjectReferenceExistent)' != ''">

      <Output TaskParameter="TargetOutputs" ItemName="_ResolvedProjectReferencePaths"/>

    </MSBuild>

    <!--
        Get manifest items from the (non-exe) built project references (to feed them into ResolveNativeReference).
        -->
    <MSBuild
        Projects="@(_MSBuildProjectReferenceExistent)"
        Targets="GetNativeManifest"
        BuildInParallel="$(BuildInParallel)"
        UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)"
        Properties="%(_MSBuildProjectReferenceExistent.SetConfiguration); %(_MSBuildProjectReferenceExistent.SetPlatform)"
        Condition="'@(NonVCProjectReference)'!='' and '$(BuildingProject)'=='true' and '@(_MSBuildProjectReferenceExistent)'!=''">

      <Output TaskParameter="TargetOutputs" ItemName="NativeReference"/>

    </MSBuild>

    <!-- Issue a warning for each non-existent project. -->
    <Warning
        Text="The referenced project '%(_MSBuildProjectReferenceNonexistent.Identity)' does not exist."
        Condition="'@(NonVCProjectReference)'!='' and '@(_MSBuildProjectReferenceNonexistent)'!=''"/>

  </Target>

</Project>


Actually with this workaround I make sure that when building the project, the _YuseSplitProjectReferencesByFileExistence target (which is just an exact copy of the original _SplitProjectReferencesByFileExistence ... only with a different name) gets always called.

With this temp fix, my solution builds fine in MSBuild. But of course I'm looking for a cleaner and more correct solution and explanation for the problem.

According to me, MSBuild is somehow not building the projects in the solution in the right order ... e.g. the 4 projects that fail to compile all get compiled twice. The first time successfully (then the compilation is triggered by another project in the solution that is referencing this project). After that it copies the binaries to the output location of the project ... and many steps (and compilations) later ... MSBuild decides to build the project again (although it was already compiled succesfully), this time the compilation is triggered from the solution ... and the compilation fails. I do not understand why it decides to try to compile the project again.

One more finding: when I use MSBuild to compile each of the projects separately from the command line, all projects compile successfully.







Thomas Phlips
I suggest you to explicitly specify the build orders in Visual Studio and check ifit works.

When msbuild builds sln file, it constructs a msbuild project in memory. In order to view it, please follow the instructions in blog: http://weblogs.asp.net/kdente/archive/2005/06/05/410432.aspx

If it is possible, please let me know if there is any steps to make a simplified repro projects and solution.
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
Hongye Sun
I already tried explicitly specifying the build order in Visual Studio, however this didn't help.
I also think the solution is building the projects in the correct order, it is only strange that it tries to build some of the project for a second time (after they have already been build successfully). (see my original post)


I will try to let MSBuild save the temporary build project file to disk as you suggest in the coming days ... hopefully this will clear out some things.

I already tried to reproduce the same problem in a small test solution containing some similar projects/project structures, however I did not yet succeed to simulate the problem in this way (the test solution builds without any problems).

Thomas Phlips

Wouldyou mindsending me the build log file? My email is hongyes@online.microsoft.com, please remove 'online'.


Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
Hongye Sun

You can use google to search for other answers

Custom Search

More Threads

• How to specify a project for msbuild to build when building the solution file?
• parameterize/reuse of targets?
• VS2005 fails to build solution
• Cannot Create a Proper Build - Keeps Failing
• Command line build can't find odbc32.lib - but it's there!
• Problems trying to add unnecessary files to TFS source control
• MSBuild requirements for WPF app publish
• Hand-made COM interop dll as COMReference
• Extend not Override a target
• ZipProject for Extensibility Web Templates