2012-12-06 143 views
9

我有一个VS2010解决方案文件,其中包含超过20个项目,并且一些项目对解决方案中的其他项目具有依赖性。MSBuild 4.5忽略项目依赖关系

我也有不同的目的设置了多个构建配置,但我已经减少了要构建的项目,只包含最少数量的项目。

例如,我有三个库(A,B和C),一个网站项目和一个网站部署项目(VS2010)。该网站引用了库A和B,而B又引用了C.我的构建配置仅检查了网站和部署项目。按照预期,当我从解决方案的属性中检查项目依赖关系时,该网站正确列出了这些库,而B显示了C。

当我在VS2010中针对我的构建配置运行构建时,它工作得很好,但是当我在指定配置的解决方案上运行MSBuild时(如下所示),它只会导致一堆错误。

msbuild.exe mysolution.sln /t:Build /p:configuration=MyConfig

这里是我得到的错误示例:

Services\IService.cs(11,63): error CS0246: The type or namespace name 'Priority' could not be found (are you missing a using directive or an assembly reference?)

我发现我的构建服务器(TeamCity的V7.1.2)对这种情况的发生,但我可以重现它在多台机器,并且我缩小了MSBuild本身的一个问题。

它只是在我安装.NET 4.5(和2个安全补丁)之后才开始发生的,所以我卸载了它,重新安装了.NET 4.0(带补丁),因为它也被删除了,然后尝试了相同的命令,精细。

这使我相信在.NET 4.5中,MSBuild中的某些内容已经发生了变化或中断,但是他们的文档中没有任何内容似乎讨论了这种变化。

的MSBuild 4.5文档:http://msdn.microsoft.com/en-us/library/hh162058.aspx

我甚至试过路过BuildProjectDependencies=true到的MSBuild,它出现,说明它跳过了其他项目,因为他们没有在配置管理器,这是正确的,故意的选择。

我得到它与MSBuild 4.5一起工作的唯一方法是返回并选择被跳过的项目,但由于实际的解决方案与依赖链有点复杂,我不想每次我们用新项目或依赖关系更新解决方案时,都要手动管理配置。它应该是自动的。

任何想法与我在做什么?

回答

3

如果您还没有解决这个问题,让我们尝试一些盲目出手:

  1. 的MSBuild已确认的错误时,有时会产生基于其次依赖错误的生成顺序。尝试构建不是完整的解决方案,而是要构建精确的项目 - 如msbuild.exe YourWebsiteProject.csproj /t:Clean;Build /p:configuration=MyConfig。问题仍然存在?

  2. 确保YourWebsiteProject和您的库(B和C)具有适当的引用 - 在项目上,而不是在另一个项目文件夹中的DLL上(最简单的方法来解决 - 从B引用移除并重新添加它,只要确保你正在添加项目引用,而不是浏览bin \ Debug就可以获得C.dll)。问题仍然存在吗?

如果你能提供详细的,甚至诊断的MSBuild日志(添加到您的MSBuild命令行下面的开关/ DS/V:诊断,然后份额的TeamCity全力打造地方日志或管道命令行日志文件)或一些示例项目设置了我可以重现此行为的位置 - 它可以帮助解决问题。

+0

+1。 –

+0

当你说MSBuild有确认的错误时,你是什么意思?有没有在MSDN中的这个问题的链接,所以我可以跟踪它,看看微软是否有任何指导? –

+0

正是在这里 http://connect.microsoft.com/VisualStudio/feedback/details/586875/msbuild-4-0-incorrectly-processes-project-dependencies-specified-in-solution-file 固定为4.5 –

2

我遇到了完全相同的问题。我设法找到的两个解决方案从长远来看都是不可接受的,但他们确实克服了最初的问题,即让我们的构建过程与新的4.5堆栈一起工作。

  1. 交换与文件引用的项目引用
  2. 创建复合构建配置

我选择了#2,如文件引用意味着开发商将失去了实时智能感知等。

的化合物结构是简单:

  • 发布服务器 - >所有服务器项目
  • 发布消费 - >“发布服务器” +客户项目

这个问题似乎是,如果一个项目没有包括在当前/活动的构建配置,它不会将其包含为引用的依赖项。因此,通过在配置中添加依赖关系,项目至少可以编译。

既丑陋,但至少它让我走出一个狭窄的地方。

马特

4

我想我会更新我以前的答案,因为我已经花了很多时间和精力创造我自己的解决此问题的。解决问题的方法比简单地解决问题要全面一些,但我试图消除这个问题,并且避免像这样的未来冲击。

MSBuild已从解决方案,配置或其他方面降级。只要求MSBuild独立编译项目。这种情况发生的顺序是通过Powershell脚本来计算的,该脚本解析我们的解决方案和项目以制定出最佳的即时生成执行计划。

关键就在这(我想你可能会发现有用)如下片段:

识别我的解决方案

我在我的平台上的所有解决方案的列表,我基本上是重复在每个这些。

$buildPlan = (
@{ 
    solutions = (
     @{ 
      name  = "DataStorage" 
      namespace = "Platform.Databases" 
     }, 
     @{ 
      name  = "CoreFramework" 
     }, 
     @{ 
      namespace = "Platform.Server" 
      name  = "Application1" 
     }, 
     @{ 
      namespace = "Platform.Server" 
      name  = "Application2" 
     }, 
     @{ 
      namespace = "Platform.Client" 
      name  = "Application1" 
     } 
    ) 
}) 

我有一些逻辑,帮助转化为实际的物理路径,这一点,但它很定制我们的需求,所以我不会在这里列出来。足以说,从这个列表中,我可以找到需要解析的.sln文件。

解析为项目

随着每个解决方案解决方案文件,我看了.sln文件,并尝试提取我以后需要建立包含内的所有项目。

所以,首先,找出所有的项目在我

$solutionContent = Get-Content $solutionFile 

$buildConfigurations += Get-Content $solutionFile | Select-String "{([a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})}\.(Release.*)\|Any CPU\.Build" | % { 
     New-Object PSObject -Property @{ 
      Name = $_.matches[0].groups[3].value.replace("Release ",""); 
      Guid = $_.matches[0].groups[1].value 
      } 

    } | Sort-Object Name,Guid -unique 

然后翻译成的,我以后可以遍历项目一个不错的榜单。

$projectDefinitions = $solutionContent | 
     Select-String 'Project\(' | 
     ForEach-Object { 
      $projectParts = $_ -Split '[,=]' | ForEach-Object { $_.Trim('[ "{}]') }; 
      $configs = ($buildConfigurations | where {$_.Guid -eq $projectParts[3]} | Select-Object Name) 

      foreach ($config in $configs) 
      { 
       $santisiedConfig = if ([string]::IsNullOrEmpty($config.Name)){"Release"}else{$config.Name} 
       if ($projectParts[1] -match "OurCompanyPrefix.") 
       { 
        New-Object PSObject -Property @{ 
        Name = $projectParts[1]; 
        File = $projectParts[2]; 
        Guid = $projectParts[3]; 
        Config = $santisiedConfig 
        } 
       } 
      } 
    } 

加载Visual Studio项目

从我的解决方案文件的解析,我现在的每解决方案项目,其中关键的是含有从解决方案根的相对文件路径,找到名单项目。

$projectDefinition = [xml](Get-Content $csProjectFileName) 
$ns = @{ e = "http://schemas.microsoft.com/developer/msbuild/2003" } 
$references = @(); 

1)确定外部项目引用

$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:ItemGroup/e:Reference" -Namespace $ns | % {$_.Node} | where {$_.Include -match "OurCompanyPrefix" -and $_.HintPath -notmatch "packages"} | % {$_.Include} 

2)确定内部项目引用

$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:ItemGroup/e:ProjectReference" -Namespace $ns | % { $_.Node.Name } 

3)继 “生成后” 事件作为外部引用

$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup/e:PostBuildEvent" -Namespace $ns | where {(!([String]::IsNullOrEmpty($_.Node.InnerText)))} | % { 

      $postBuildEvents = $_.Node.InnerText.Split("`n") 
      $projectsReferencedInPostBuildEvents = $postBuildEvents | Select-String "\(SolutionDir\)((\w|\.)*)" | % {$_.Matches[0].Groups[1].Value} 
      if ($projectsReferencedInPostBuildEvents -ne $null) 
      { 
       Write-Output $projectsReferencedInPostBuildEvents | % { $matchedProject = $_; ($releaseConfiguation | ? {$_.File -match $matchedProject}).Name } 
      } 

     } 

而且,由于我们是在它,了解一些基本的输出信息太

这是非常方便,当涉及到迭代我的项目,以建立清单,知道在哪里推输出,或在哪里查找依赖项的输出。

$assemblyName = (Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup/e:AssemblyName" -Namespace $ns).Node.InnerText 
$outputPath = (Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup[contains(@Condition,'Release|')]/e:OutputPath" -Namespace $ns).Node.InnerText 

而在这一切

我们只需要确保我们没有任何重复,所以我只记录这个特殊的代码项目的不同依赖结束:

$dependendents = @(); 
if ($references -ne $null) 
{ 
    $buildAction.project.dependencies += $references | where {(!([string]::IsNullOrEmpty($_))) -and ($_ -match "OurCompanyPrefix\.(.*)")} | % { $_.ToLower()} | Select -unique 
}  

我希望这可以为您提供足够的信息来解析您的SLN和PROJ文件。如何选择捕获和存储这些信息我认为完全取决于您。

我正在编写一篇相当深入的博客文章,其中将包含我上面未提及的所有修剪和框架。这篇文章还没有准备好,但我会从早期的文章链接到它:http://automagik.piximo.me/2013/02/just-in-time-compilation.html - 由于微软的这一改变几乎使这项工作脱轨!

干杯。

3

在.NET 4.5,在C OnlyReferenceAndBuildProjectsEnabledInSolutionConfiguration属性的默认值:\ WINDOWS \ Microsoft.NET \框架\ v4.0.30319 \ Microsoft.Common.targets从false改为true。顾名思义,该属性使MSBuild忽略对构建配置中排除的项目的引用。

(这有可能是微软在响应做出这种改变的Connect bug I filed against MSBuild 4.0,即使我警告他们的变化打破了编译。)

解决方法很简单:在第一<PropertyGroup>的属性设置回false您的每个项目的部分:

<PropertyGroup> 
    ... 
    <OnlyReferenceAndBuildProjectsEnabledInSolutionConfiguration>false</OnlyReferenceAndBuildProjectsEnabledInSolutionConfiguration> 
</PropertyGroup> 
+0

For某些原因导致我的Connect错误现在已经被破坏。 Bing仍然有一个[缓存版本](http://cc.bingj.com/cache.aspx?q=OnlyReferenceAndBuildProjectsEnabledInSolutionConfiguration&d=4756437099940543&mkt=en-US&setlang=en-US&w=gy6I4RMi2T9y-j5M_jzlnbwuu4wnvbzd)。 –

0

我明白这个问题有多种原因。我在这里尝试了大部分解决方案。我无法将我们的构建服务器更改为使用PS脚本,因此解决方案无法使用。没有什么我可以尝试工作。

最后,我删除了我的解决方案并开始了一个新的解决方案。新解决方案奏效。在用工作溶液分解破碎的溶液后,我发现原来的解决方案是缺少线。不能编译的每个依赖关系都缺少这一行:

{A93FB559-F0DB-4F4D-9569-E676F59D6168}.Release|Any CPU.Build.0 = Release|Any CPU 

注1:GUID将从依赖关系更改为依赖关系。注意2:您可以在解决方案文件的“GlobalSection(ProjectConfigurationPlatforms)= postSolution”部分下找到类似此行的行。

我的build.proj文件说使用“任何CPU”平台构建“Release”。因为MSBuild无法找到这条线,所以没有建立这个依赖关系。这会导致“错误CS0246:无法找到类型或名称空间”消息。

如果您好奇,有人已将此解决方案设置为“x86”平台(这对我们来说是错误的)。我将其更改为“任何CPU”(以及其他一些更改)。 Visual Studio没有将相应的行添加到解决方案文件中。在IDE中一切都很好,但MSBuild开始抛出错误。

0

我发现MSBuild正在从解决方案中建立项目,以便在.sln文件中声明它们。所以如果你使用文本编辑器对它们进行重新排序,你可以修复MSBuild的顺序。第二个原因为