我有一个包含20多个项目的VS2010解决方案文件,其中一些项目依赖于解决方案中的其他项目。
我还为不同的目的设置了多个构建配置,但是我已经减少了要构建的项目,只包括最少数量的项目。
例如,我有三个库(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一起使用的唯一方法是返回并选择被跳过的项目,但由于实际的解决方案对依赖链有点复杂,我不想要每次我们使用新项目或依赖项更新解决方案时,都会尝试手动管理配置。它应该是自动的。
我正在做什么的想法?
答案 0 :(得分:4)
如果您仍未解决此问题,请尝试一些盲目的镜头:
Msbuild在根据后续依赖项有时会生成错误的构建顺序时确认了错误。尝试构建不是整个解决方案,而是构建您想要构建的项目 - 例如msbuild.exe YourWebsiteProject.csproj /t:Clean;Build /p:configuration=MyConfig
。问题是否仍然存在?
确保YourWebsiteProject和你的libs(B和C)有正确的引用 - 在项目上,而不是在另一个项目文件夹中的dll上(最简单的方法来修复它 - 从B引用中删除C并再次重新添加它) ,只需确保您正在添加项目引用而不是浏览到bin \ Debug for very C.dll)。问题还存在吗?
如果你能提供详细甚至诊断的msbuild日志(在switch / ds / v:diag之后添加到你的msbuild命令行,然后在某处共享teamcity完整构建日志或管道命令行日志到文件)或者某些示例项目设置在哪里我可以重现这种行为 - 它可以帮助解决问题。
答案 1 :(得分: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 - 由于微软的这一改变几乎使这项工作脱轨!
干杯。
答案 2 :(得分:3)
在.NET 4.5中,C:\ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ Microsoft.Common.targets中OnlyReferenceAndBuildProjectsEnabledInSolutionConfiguration属性的默认值已从false
更改为{ {1}}。顾名思义,此属性会导致MSBuild忽略对从构建配置中排除的项目的引用。
(即使我警告他们更改会破坏构建,但Microsoft可能会对Connect bug I filed against MSBuild 4.0做出此更改。)
解决方法很简单:在每个项目的第一个true
部分中将属性设置回false
:
<PropertyGroup>
答案 3 :(得分:2)
我遇到了完全相同的问题。我设法找到的这两种解决方法从长远来看都是不可接受的,但是它们确实克服了使用新的4.5堆栈使我们的构建过程老化的初始问题。
我选择了#2,因为文件引用意味着开发人员会失去实时智能感知等。
复合配置就是这样:
问题似乎是,如果项目未包含在当前/活动构建配置中,则它不会将其作为引用依赖项包含在内。因此,通过将依赖项添加到配置中,项目至少会进行编译。
两者都很难看,但至少它让我脱离了紧张的地方。
马特
答案 4 :(得分:0)
我明白这个问题有多种原因。我在这里尝试了大部分解决方案。我无法更改我们的构建服务器以使用PS脚本,以便解决方案。没有什么我可以尝试的。
最后,我删除了我的解决方案并开始了一个新的解决方案。新的解决方案奏效了。用工作溶液对破碎的溶液进行分析后,我发现原来的解决方案是缺少线条。无法编译的每个依赖项都缺少此行:
{A93FB559-F0DB-4F4D-9569-E676F59D6168}.Release|Any CPU.Build.0 = Release|Any CPU
注1:GUID将从依赖变为依赖。
注2:您可以在&#34; GlobalSection(ProjectConfigurationPlatforms)= postSolution&#34;下找到类似这样的行。解决方案文件的一部分。
我的build.proj文件说build&#34; Release&#34;使用&#34;任何CPU&#34;平台。因为MSBuild无法找到此行,所以它没有构建此依赖项。这会导致&#34; 错误CS0246:无法找到类型或命名空间&#34;消息。
如果您感到好奇,有人已将此解决方案设置为&#34; x86&#34;平台(这对我们来说是错误的)。我将其更改为&#34;任何CPU&#34; (以及其他一些变化)。 Visual Studio未将相应的行添加到解决方案文件中。在IDE中一切都很好,但MSBuild开始抛出错误。
答案 5 :(得分:0)
我发现MSBuild正在从一个解决方案构建项目,以便在.sln文件中声明它们。因此,如果您使用文本编辑器对它们进行重新排序,则可以修复MSBuild的订单。