当我的项目使用 Csc 任务时,如何强制 MSBuild 遵守我的解决方案中的项目依赖项?

How can I force MSBuild to respect project dependencies in my solution when my project uses a Csc task?

背景:

我目前使用的是 VS2010。

MSBuild 存在一个已知问题,解决方案中的项目依赖项在从 IDE 构建时起作用,但在通过 MSBuild 构建解决方案时不起作用。

(MSBuild 运行 通过 Cruise Control .NET 像这样:)

<cb:define buildArgs="/noconsolelogger /p:Configuration=$(configuration);Platform=$(platform) /maxcpucount /v:minimal /nologo" />
<!-- ... -->
<cb:define name="buildSolution"> 
  <msbuild>
    <executable>$(msbuildExe)</executable>
    <workingDirectory>$(localWorkingDirectory)</workingDirectory>
    <projectFile>$(solutionfile)</projectFile>
    <buildArgs>$(buildArgs)</buildArgs>
    <targets>build</targets>
    <timeout>7200</timeout>
    <logger>C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
  </msbuild>
</cb:define>

因此,我使用非链接项目引用解决了这个问题:

<!-- Inside ProjectB.csproj -->
<ProjectReference Include="..\ProjectA\ProjectA.vcxproj">
  <LinkLibraryDependencies>false</LinkLibraryDependencies>
  <Project>{GUID}</Project>
  <Name>ProjectA</Name>
</ProjectReference>

在这种情况下,ProjectA 是一个 SWIG 项目,它生成要编译到 ProjectB 中的 CS 源文件。我是这样完成的:

<ItemGroup>
  <Compile Include="Properties\AssemblyInfo.cs" />
  <Compile Include="..\ProjectA\generated\cs\*.cs" />
</ItemGroup>

但是,虽然这在通过 IDE 构建时工作正常,但在通过 MSBuild 构建时它包含 none 这些文件。我能够通过添加以下内容使其工作:

<ItemGroup>
  <CSFile Include="..\ProjectA\generated\cs\*.cs" />
</ItemGroup>
<Target Name="Build" DependsOnTargets="BeforeBuild">
  <Csc Sources="@(CSFile)" References="@(Reference)" OutputAssembly="$(OutputPath)$(AssemblyName).dll" TargetType="dll" />
</Target>

实际问题:

似乎 MSBuild 不再尊重项目引用,因此它通常会尝试在 ProjectA 之前构建 ProjectB。

看起来 MSBuild 根本无法编译 SWIG 项目,但您可以使用 Visual Studio 本身通过 SWIG 编译您的解决方案。请注意,您必须在 Cruise Control 构建服务器上安装 Visual Studio + SWIG,并以某种方式让 Cruise Control 使用正确的 Devenv Command Line Switches.

调用 devenv.exe

背景: 在 Visual Studio 中,大多数项目文件格式都具有以下两种功能:

  1. Visual Studio 理解的项目文件,可能带有像 SWIG
  2. 这样的 Visual Studio 插件
  3. MSBuild 理解的 MSBuild 文件。

这包括 csprojvcxproj 和许多其他。但是,某些项目类型,如安装项目 (vdproj) 仅支持上述 (1) - SWIG 似乎也是如此。

问题似乎不是构建顺序,而是评估通配符时的问题。

在我的示例中,CSFile 标记在从 ProjectA 生成的 .cs 文件存在之前进行评估,因此即使 ProjectA 先发生,它们也不会包含在构建中。

为了避免这种情况,我必须通过 MSBuild 从 ProjectB 手动调用 ProjectA,在运行时读取文件列表,然后手动将其附加到 Compile 集合。

在 ProjectB.csproj 文件的末尾,我插入了:

<Target Name="BeforeBuild">
  <!-- Force project references to build before this, because otherwise it doesn't... -->
  <MSBuild Projects="@(ProjectReference)"
           Targets="Build"
           BuildInParallel="false"
           Properties="%(_MSBuildProjectReferenceExistent.SetConfiguration);%(_MSBuildProjectReferenceExistent.SetPlatform)"
           ContinueOnError="false" />
  <CreateItem Include="..\ProjectA\generated$(Platform)$(Configuration)\cs\*.cs">
    <Output ItemName="Compile" TaskParameter="Include" />
  </CreateItem>
  <CreateItem Include="..\ProjectA\generated$(Platform)$(Configuration)\cs\*.cs">
    <Output ItemName="GeneratedCS" TaskParameter="Include" />
  </CreateItem>
  <Message Text="Generated .cs files...%0d    @(GeneratedCS->'%(Filename)%(Extension)','%0d    ')" Importance="high" />
</Target>

这会将所有生成的 .cs 文件添加到项目中,并将它们的所有名称打印到控制台。