VS2010和MSBuild在组合的C ++ / C#解决方案上获得了不同的结果

时间:2011-02-25 20:16:01

标签: visual-studio-2010 msbuild build

我有一个很大的VS2010解决方案,其中包含一堆C#项目。其中一个项目通过P / Invoke消耗C ++(本机,也称为非托管)库。为确保一切正确构建,我在同一解决方案中包含了所说的C ++项目。现在,问题就出现了。

简而言之:MSBuild神秘地删除了一些输出文件,而VS2010正确构建。

长篇故事
以前(VS2005 / 2008),我会使用名为“Project Dependencies”的漂亮功能。这是允许您选择给定项目所依赖的特定项目的东西,以便环境确保首先构建这些项目。

然而,VS2010已朝着MSBuild的方向发展,现在项目依赖关系显然不起作用。他们只是没有。 (例如,参见this question) 现在,为了确保我的C ++项目在使用它之前构建,我必须“添加一个引用”。所以我做到了。一切似乎都很好。

但是,然后,我转到我的命令行并启动MSBuild来构建相同的解决方案。而且一切都很好。但是当我查看输出文件夹时,C ++项目的输出不存在!

MSBuild控制台输出清楚地表明C ++项目确实在某个时候构建过。我甚至在一些项目中添加了一些“ dir bin \ MYPROJNAME.dll ”语句作为Post-Build步骤,以查看文件是否存在 - 它们Here是命令行窗口的屏幕截图。以红色圈出的是文件存在的时刻(在顶部),然后是文件丢失的时刻(在底部)。

另一个奇怪的事情是,该项目显然已经建成两次。请参阅屏幕截图中的红色下划线 - 这是关于构建同一项目的第二个消息(第一条消息以及所有编译器输出都在屏幕上方)。

看起来第二个构建事件真的是导致文件被删除的原因:当我完全禁用构建这个项目时(通过解决方案属性),它只构建了一次,最后文件就在那里。我本可以称之为“解决方案”,但随后它在Visual Studio本身中断:VS只是不构建项目。

解决此问题的另一种方法是从使用C#项目中删除“项目引用”。然后MSBuild将只构建一次C ++项目,文件将在那里。但是它又打破了另一个地方:对C ++项目的更改不会触发重建消费的C#项目。

所以问题是:如何让MSBuild不删除怪异的文件?

5 个答案:

答案 0 :(得分:1)

简短(有点黑客)回答这个问题:

你在PostBuildEvents中拥有了dir。如果您添加attrib + r,则不会删除您的文件:

<Exec Command="attrib +r $(TargetPath)"/>

(TargetPath应该是dll文件......)

答案 1 :(得分:1)

听起来你有2个项目,都依赖于第三个项目。如果不是这样,那么你可以忽略整个anwser :)

因为编译器是线程化的,所以你需要确保这两个项目在第三个项目完成之前不会尝试构建。

所以projectA和projectB都有一个依赖构建,projectC。 projectA启动,看到projectC的输出不在那里并调用Rebuild。在构建时,另一个编译线程出现了,它开始构建projectB。它没有看到projectC的输出(它还没有完成构建)所以它调用Rebuild,再次清理项目。在项目开始时检查相关构建,而不是在需要时。因此,如果projectB有4个其他项目,它必须在它的依赖链中到达projectC之前构建,可能需要一段时间才能在projectC上调用第二个Rebuild。

有几种方法可以解决它。

  1. 尝试解析依赖的构建,以便projectA依赖于projectC。当然,这可能不太理想。

  2. 我认为VS2010仍然具有构建顺序,因此您可以设置内置的订单项目。不仅仅是依赖项。确保在projectA和projectB之前列出projectC。

  3. 最简单的方法是进行2次调用。首先调用msbuild <project> /target:Clean然后调用msbuild <project> /target:Build而不是重建,只需调用Build。这样,projectA和projectB都可以看到projectC的输出,而不是尝试构建它。

答案 2 :(得分:1)

找出第一次构建它的原因可能就是要走的路。即使您删除对它的引用,某些东西也会在早期触发。你能用/ v:diag发布完整的msbuild日志吗?您发布的部分仅在之后我感兴趣的部分开始:)

答案 3 :(得分:0)

确保您正在构建正确的配置和平台。如果您没有指定平台,它将构建没有平台,这是一种Mixed平台,具体取决于msbuild文件的构造方式。 Visual Studio总是使用UI中指定的平台构建,这可能就是它与命令行不同的原因。

如果找不到解决方案,也许可行的解决方法是创建一个基于属性的条件,在命令行中删除导致问题的任何内容(例如构建项目两次)并使用/ p设置属性:从命令行。

答案 4 :(得分:0)

解决方案:为每个项目使用不同的中间目录