作为含有许多项目的解决方案的一部分,我有一个项目,该项目的引用(经由<ProjectReference>在溶液中其他三个项目,再加上一些其他)。在AfterBuild,我需要的3个特定项目相关的输出复制到另一个位置。

经由各种SO答案等的方式我定居在完成这是:

    <MSBuild 
        Projects="@(ProjectReference)" 
        Targets="Build" 
        BuildInParallel="true" 
        Condition="'%(Name)'=='ProjectA' OR '%(Name)'=='ProjectB' OR '%(Name)'=='ProjectC'">
        <Output TaskParameter="TargetOutputs" ItemName="DependentAssemblies" />
    </MSBuild>
    <Copy SourceFiles="@(DependentAssemblies)" DestinationFolder="XX" SkipUnchangedFiles="true" />

然而,我跑与此问题。该<MSBuild步的IncrementalClean任务结束了删除一些ProjectC的输出。当VS2008下运行这一点,build.force文件被存放在项目C的obj/Debug文件夹,然后触发项目C从构建得到重建,如果我做一个基础上,如果包含该AfterBuild目标项目的整个解决方案,而如果排除这个项目,它[正确]不触发重建项目C的(和临界重建项目C的所有依赖的)。这可能是在这种情况下具体的VS-诡计(所以我需要解决此无论哪种方式,但最常见的使用将是经由VS),这将不处于TeamBuild或其他命令行的MSBuild调用上下文发生

在相关项目(和一般的溶液的其余部分)都被以交互方式创建VS,因此ProjectRefences包含相对路径等。我已经看到了这个是有可能导致问题的提及 - 但没有一个完整的为什么,或者它会被固定或如何解决它的解释。换句话说,我不是真的有兴趣在如通过转换ProjectReference路径绝对路径手动编辑的.csproj。

虽然这是完全有可能我在做一些愚蠢的事,有人会立即指出这是什么(这将是巨大的),放心吧,我花了很多时间研读/v:diag输出等(虽然我还没有试过从地面构建REPRO - 这是相对复杂的整个构建的上下文中)

有帮助吗?

解决方案

正如我的评论指出,呼吁GetTargetPath对所引用的项目只装配该项目的返回主输出。为了得到引用的项目这是一个有点混乱的所有引用的复制本地组件。

添加下面的每个项目所引用,你想要得到的CopyLocals:

    <Target
    Name="ComputeCopyLocalAssemblies"
    DependsOnTargets="ResolveProjectReferences;ResolveAssemblyReferences"
    Returns="@(ReferenceCopyLocalPaths)" /> 

我的具体情况是,我需要重新创建System.AddIn的管道文件夹结构,在我的顶级主机项目的bin文件夹。这是有点乱,我很不满意MSDN建议用OutputPath碴的解决方案 - 为我们的构建服务器上休息,并防止在不同的项目中创建的文件夹结构(例如SystemTest)

因此,与将上述目标(使用.targets进口)一起添加以下到由需要创建的管道文件夹中每个“宿主”导入的.targets文件:

<Target
    Name="ComputePipelineAssemblies"
    BeforeTargets="_CopyFilesMarkedCopyLocal"
    Outputs="%(ProjectReference.Identity)">

    <ItemGroup>
        <_PrimaryAssembly Remove="@(_PrimaryAssembly)" />
        <_DependentAssemblies Remove="@(_DependentAssemblies)" />
    </ItemGroup>

    <!--The Primary Output of the Pipeline project-->
    <MSBuild Projects="%(ProjectReference.Identity)"
             Targets="GetTargetPath"
             Properties="Configuration=$(Configuration)"
             Condition=" '%(ProjectReference.PipelineFolder)' != '' ">
        <Output TaskParameter="TargetOutputs"
                ItemName="_PrimaryAssembly" />
    </MSBuild>

    <!--Output of any Referenced Projects-->
    <MSBuild Projects="%(ProjectReference.Identity)"
             Targets="ComputeCopyLocalAssemblies"
             Properties="Configuration=$(Configuration)"
             Condition=" '%(ProjectReference.PipelineFolder)' != '' ">
        <Output TaskParameter="TargetOutputs"
                ItemName="_DependentAssemblies" />
    </MSBuild>

    <ItemGroup>
        <ReferenceCopyLocalPaths Include="@(_PrimaryAssembly)"
                                 Condition=" '%(ProjectReference.PipelineFolder)' != '' ">
            <DestinationSubDirectory>%(ProjectReference.PipelineFolder)</DestinationSubDirectory>
        </ReferenceCopyLocalPaths>
        <ReferenceCopyLocalPaths Include="@(_DependentAssemblies)"
                                 Condition=" '%(ProjectReference.PipelineFolder)' != '' ">
            <DestinationSubDirectory>%(ProjectReference.PipelineFolder)</DestinationSubDirectory>
        </ReferenceCopyLocalPaths>
    </ItemGroup>
</Target>

我也需要必要的PipelineFolder元数据添加到实际的项目引用。例如:

    <ProjectReference Include="..\Dogs.Pipeline.AddInSideAdapter\Dogs.Pipeline.AddInSideAdapter.csproj">
        <Project>{FFCD0BFC-5A7B-4E13-9E1B-8D01E86975EA}</Project>
        <Name>Dogs.Pipeline.AddInSideAdapter</Name>
        <Private>False</Private>
        <PipelineFolder>Pipeline\AddInSideAdapter\</PipelineFolder>
    </ProjectReference>

其他提示

您原始溶液应该简单地通过改变工作

Targets="Build"

Targets="GetTargetPath"

GetTargetPath目标只返回TargetPath属性,并且不需要建立。

您可以在项目C,如果你这样调用第一目标保护您的文件:

  <Target Name="ProtectFiles">
    <ReadLinesFromFile File="obj\ProjectC.csproj.FileListAbsolute.txt">
        <Output TaskParameter="Lines" ItemName="_FileList"/>
    </ReadLinesFromFile>
    <CreateItem Include="@(_DllFileList)" Exclude="File1.sample; File2.sample">
        <Output TaskParameter="Include" ItemName="_FileListWitoutProtectedFiles"/>
    </CreateItem>      
      <WriteLinesToFile 
        File="obj\ProjectC.csproj.FileListAbsolute.txt"
        Lines="@(_FileListWitoutProtectedFiles)"
        Overwrite="true"/>
  </Target>

当前的解决方法基于这太问题,即我有:

    <ItemGroup>
        <DependentAssemblies Include="
            ..\ProjectA\bin\$(Configuration)\ProjectA.dll;
            ..\ProjectB\bin\$(Configuration)\ProjectB.dll;
            ..\ProjectC\bin\$(Configuration)\ProjectC.dll">
        </DependentAssemblies>
    </ItemGroup>

此然而TeamBuild(其中所有输出在一个目录结束)下将打破,并且如果任何从属项目变化的输出的名称。

编辑:另外寻找是否有关于如何使硬编码稍微干净比一个更清洁的答案有任何意见:

    <PropertyGroup>
        <_TeamBuildingToSingleOutDir Condition="'$(TeamBuildOutDir)'!='' AND '$(CustomizableOutDir)'!='true'">true</_TeamBuildingToSingleOutDir>
    </PropertyGroup>

    <ItemGroup>
        <DependentAssemblies 
            Condition="'$(_TeamBuildingToSingleOutDir)'!='true'"
            Include="
                ..\ProjectA\bin\$(Configuration)\ProjectA.dll;
                ..\ProjectB\bin\$(Configuration)\ProjectB.dll;
                ..\ProjectC\bin\$(Configuration)\ProjectC.dll">
        </DependentAssemblies>
        <DependentAssemblies 
            Condition="'$(_TeamBuildingToSingleOutDir)'=='true'"
            Include="
                $(OutDir)\ProjectA.dll;
                $(OutDir)\ProjectB.dll;
                $(OutDir)\ProjectC.dll">
        </DependentAssemblies>
    </ItemGroup>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top