当我的项目使用 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 中,大多数项目文件格式都具有以下两种功能:
- Visual Studio 理解的项目文件,可能带有像 SWIG
这样的 Visual Studio 插件
- MSBuild 理解的 MSBuild 文件。
这包括 csproj
、vcxproj
和许多其他。但是,某些项目类型,如安装项目 (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 文件添加到项目中,并将它们的所有名称打印到控制台。
背景:
我目前使用的是 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 中,大多数项目文件格式都具有以下两种功能:
- Visual Studio 理解的项目文件,可能带有像 SWIG 这样的 Visual Studio 插件
- MSBuild 理解的 MSBuild 文件。
这包括 csproj
、vcxproj
和许多其他。但是,某些项目类型,如安装项目 (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 文件添加到项目中,并将它们的所有名称打印到控制台。