2014-10-08 86 views
1

我想设置一个应用程序,我正在Visual Studio中通过导入几个脚本在项目中包括一组标准的程序集级属性进入项目文件,因为它们是由MSBuild编译的。有问题的属性由从其中一个脚本调用的MSBuild任务生成,而另一个脚本将生成的代码文件包含为编译项目。使用属性有条件地编译使用MSBuild的源代码文件

到目前为止,我的自定义任务是生成包含文件OK并将其传回给MSBuild创建的文件的路径,但由于某种原因,MSBuild顽固地拒绝将生成的文件包含在项目的构建中。这可以通过验证编译的.dll文件的版本信息资源中没有生成的程序集属性中的任何值来确认。

我的自定义任务脚本(Build.targets):

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <UsingTask AssemblyFile="..\Build.Tasks\$(OutDir)Build.Tasks.dll" TaskName="GenerateAssemblyInfo" /> 
    <Target Name="GenerateAssemblyAttributes" Condition="'$(SkipGenerateAssemblyAttributes)' == 'false'"> 
     <GenerateAssemblyInfo AssemblyName="$(AssemblyName)" CompilationSymbols="$(DefineConstants)" IncludeFileFolder="$(AssemblyInfoFileFolder)"> 
      <Output TaskParameter="IncludeFilePath" PropertyName="AssemblyInfoFilePath"/> 
     </GenerateAssemblyInfo> 
     <Message Text="Generated AssemblyInfo include file $(AssemblyInfoFilePath)."/> 
    </Target> 
</Project> 

条件编译脚本(Build.props):

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <ItemGroup Condition="Exists('$(AssemblyInfoFilePath)')"> 
     <Compile Include="$(AssemblyInfoFilePath)"/> 
    </ItemGroup> 
</Project> 

我创建测试/演示问题的一个样本项目:

<Project DefaultTargets="GenerateAssemblyAttributes;Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <PropertyGroup> 
    <AssemblyInfoFileFolder>Properties</AssemblyInfoFileFolder> 
    <SkipGenerateAssemblyAttributes>false</SkipGenerateAssemblyAttributes> 
    </PropertyGroup> 
    <PropertyGroup> 
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> 
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> 
    ... 
    <OutputType>Library</OutputType> 
    <AppDesignerFolder>Properties</AppDesignerFolder> 
    <RootNamespace>BuildTest</RootNamespace> 
    <AssemblyName>BuildTest</AssemblyName> 
    </PropertyGroup> 
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> 
    <DebugSymbols>true</DebugSymbols> 
    <DebugType>full</DebugType> 
    <Optimize>false</Optimize> 
    <OutputPath>bin\Debug\</OutputPath> 
    <DefineConstants>DEBUG;TRACE</DefineConstants> 
    ... 
    </PropertyGroup> 
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> 
    <DebugType>pdbonly</DebugType> 
    <Optimize>true</Optimize> 
    <OutputPath>bin\Release\</OutputPath> 
    <DefineConstants>TRACE</DefineConstants> 
    ... 
    </PropertyGroup> 
    <Import Project="..\Build.Tasks\Build.targets" /> 
    <ItemGroup> 
    <Reference Include="System" /> 
    <Reference Include="System.Data" /> 
    <Reference Include="System.Xml" /> 
    </ItemGroup> 
    <Import Project="..\Build.Tasks\Build.props" /> 
    <ItemGroup> 
    <Compile Include="Class1.cs" /> 
    <Compile Include="Properties\AssemblyInfo.cs" /> 
    </ItemGroup> 
    <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> 
</Project> 

如果在Build.props脚本中,我用012替代$(AssemblyInfoFilePath)属性生成文件的路径(例如Properties\_AssemblyInfo.cs),或者我用一个Compile项替换Build.props脚本的导入,直接引用生成的文件(例如<Compile Include="Properties\_AssemblyInfo.cs" Condition="Exists('Properties\_AssemblyInfo.cs')" />),然后文件被包含在构建中,就像我期望的那样。只要我将$(AssemblyInfoFilePath)属性放回到<Compile>项目中,MSBuild就会再次忽略该文件,无论是否存在“Exists”条件。

正在创建和自定义任务的输出设置$(AssemblyInfoFilePath)属性,无论是从调用任务的目标之内我已经证明了(诊断构建输出摘录如下):

Target "GenerateAssemblyAttributes" in file "... Build.Tasks\Build.targets": 
    Using "GenerateAssemblyInfo" task from assembly "... Build.Tasks\..\Build.Tasks\bin\Debug\Build.Tasks.dll". 
    Task "GenerateAssemblyInfo" 
    Build 2.0.5394.41529 
    Done executing task "GenerateAssemblyInfo". 
    Task "Message" 
    Generated AssemblyInfo include file Properties\_AssemblyInfo.cs. 
    Done executing task "Message". 
Done building target "GenerateAssemblyAttributes" in project "BuildTest.csproj". 
Target "BeforeBuild" in file "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets": 
... 

,也通过将另一个目标添加到应用程序项目文件中,取决于GenerateAssemblyAttributes目标,该目标也使用<Message>元素来输出该属性的值。

我只是不能解决为什么,如果包含生成的源代码文件的路径属性从自定义任务的输出正确设置,MSBuild的行为就像它甚至不存在?使用Visual Studio 2005和MSBuild 2.0。

编辑:所以,如果我修改我的Build.targets文件,像这样:

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <UsingTask AssemblyFile="..\Build.Tasks\$(OutDir)Build.Tasks.dll" TaskName="GenerateAssemblyInfo" /> 
    <Target Name="GenerateAssemblyAttributes" Condition="'$(SkipGenerateAssemblyAttributes)' == 'false'"> 
     <GenerateAssemblyInfo AssemblyName="$(AssemblyName)" CompilationSymbols="$(DefineConstants)" IncludeFileFolder="$(AssemblyInfoFileFolder)"> 
      <Output TaskParameter="IncludeFilePath" PropertyName="AssemblyInfoFilePath"/> 
     </GenerateAssemblyInfo> 
     <Message Text="Generated AssemblyInfo include file $(AssemblyInfoFilePath)."/> 
    <CreateItem Include="$(AssemblyInfoFilePath)" Condition ="Exists('$(AssemblyInfoFilePath)')"> 
     <Output TaskParameter="Include" ItemName="Compile"/> 
    </CreateItem> 
    </Target> 
</Project> 

并取出Build.props从应用项目文件文件,然后生成最终被“说对了一半”因为自定义任务生成的源代码文件包含在构建中。不幸的是,的MSBuild然后进行到产生在每个应用项目的所述第一源代码文件中的下面的错误包括:(引用)在正在构建的项目:

错误147项“source_code_file的.cs “在”Sources“参数中指定了多次。 “Sources”参数不支持重复的项目。 C:\ WINDOWS \ Microsoft.NET \框架\ V2.0.50727 \ Microsoft.CSharp。针对

如果执行自定义任务和创建(添加)“编译”项目生成的源代码文件的目标仅是指源代码文件的路径,它是如何不相关的源代码文件得到重复的源代码文件列表发送到编译器作为MSBuild声明?

回答

1

我现在有MSBuild包括生成的源代码文件,其路径在我的自定义生成任务的属性输出中指定,通过向“编译”项目添加项目来编译每个应用程序集合组中调用自定义任务的目标(如上所述)。

编译器报告的“重复来源”问题已经通过在应用程序项目文件中添加另一个目标,以在编译程序集之前从“编译”项目组中删除重复项而得到解决。

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <Target Name="RemoveSourceCodeDuplicates" > 
    <RemoveDuplicates Inputs="@(Compile)"> 
     <Output TaskParameter="Filtered" ItemName="Compile"/> 
    </RemoveDuplicates> 
    </Target> 
</Project> 

,并在应用项目文件:

<Project DefaultTargets="GenerateAssemblyAttributes;Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    ... 
    <Import Project="..\Build.Tasks\RemoveDuplicates.targets"/> 
    <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> 
    ... 
</Project> 
1

这是评估顺序。在执行任何任务之前对<Itemgroup>进行评估。 相反,将这些项目添加为生成它们的任务的一部分,而不是在全局级别。对于旧版本的MSBuild来说,这并不美妙:我不知道在什么时候添加了简单地将项目组放入任务元素的能力。

此外,通配符的Include只会添加存在的执行时间,因此您会遇到问题,它无法在干净的构建中工作,但在第二次尝试后似乎可以正常工作,如果它正在解决路径(就像你有硬编码一样)。

+0

OK,我很害怕,可能是这样。我可能不得不重新考虑我的方法。感谢您的正确方向。 – Matthew 2014-10-12 03:52:31

+0

我做了类似的工作正常:将文件添加到生成它们的任务中的项目组,而不是在全局级别。任何机会,你可以使用一个新的MSBuild? – 2014-10-12 03:58:59

+0

我相信我已经解决了我遇到的问题,遵循了您的建议,并对导致构建失败的相关问题进行了一些额外的研究。 – Matthew 2014-10-13 05:47:22

相关问题