作为包含许多项目的解决方案的一部分,我有一个引用的项目(通过
解决方案中的其他三个项目,以及其他一些项目)。在 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" />
但是,我遇到了问题。 步骤的 IncrementalClean
任务最终会删除 ProjectC
的许多输出。在 VS2008 下运行此程序时,一个 build.force
文件被存放在 ProjectC 的 obj/Debug
文件夹中,如果我对整个解决方案进行构建,则会触发 ProjectC 重新构建如果项目包含此 AfterBuild
目标,而如果从构建中排除此项目,则它[正确]不会触发 ProjectC 的重建(并且关键会触发项目 C 的所有家属)。 这可能是 VS 特定的诡计,在 TeamBuild 或其他命令行 MSBuild 调用的上下文中不会发生(但最常见的用法是通过 VS,所以我需要以任何一种方式解决这个问题)
在这种情况下, 解决方案的其余部分)都是与 VS 交互创建的,因此 ProjectRefence 包含相对路径等。我已经看到提到这可能会导致问题 - 但没有完整的解释原因、何时修复或如何解决。换句话说,我对通过手动编辑 .csproj 将 ProjectReference
路径转换为绝对路径等并不感兴趣。
虽然我完全有可能做了一些愚蠢的事情,有人会立即指出它是什么(这会很棒),但请放心,我花了很多时间研究 /v:diag
输出等(虽然我还没有尝试从头开始构建一个重现 - 这是在相对复杂的整体构建的背景下)
As part of a solution containing many projects, I have a project that references (via a <ProjectReference>
three other projects in the solution, plus some others). In the AfterBuild
, I need to copy the outputs of 3 specific dependent projects to another location.
Via various SO answers, etc. the way I settled on to accomplish that was:
<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" />
However, I ran into problems with this. The <MSBuild
step's IncrementalClean
task ends up deleting a number of the outputs of ProjectC
. When running this under VS2008, a build.force
file being deposited in the obj/Debug
folder of ProjectC which then triggers ProjectC getting rebuilt if I do a Build on the entire solution if the project containing this AfterBuild
target, whereas if one excludes this project from the build, it [correctly] doesn't trigger a rebuild of ProjectC (and critically a rebuild of all dependents of ProjectC). This may be VS-specific trickery in this case which would not occur in the context of a TeamBuild or other commandline MSBuild invocation (but the most common usage will be via VS so I need to resolve this either way)
The dependent projects (and the rest of the solution in general) have all been created interactively with VS, and hence the ProjectRefence
s contain relative paths etc. I've seen mention of this being likely to causing issues - but without a full explanation of why, or when it'll be fixed or how to work around it. In other words, I'm not really interested in e.g. converting the ProjectReference
paths to absolute paths by hand-editing the .csproj.
While it's entirely possible I'm doing something stupid and someone will immediately point out what it is (which would be great), be assured I've spent lots of time poring over /v:diag
outputs etc. (although I havent tried to build a repro from the ground up - this is in the context of a relatively complex overall build)
发布评论
评论(4)
正如我的评论中所述,在引用的项目上调用 GetTargetPath 仅返回该项目的主输出程序集。要获取引用项目的所有引用的复制本地程序集,这有点混乱。
将以下内容添加到您引用的要获取其 CopyLocals 的每个项目中:
我的特殊情况是,我需要在顶级主机项目的 bin 文件夹中为 System.AddIn 重新创建 Pipeline 文件夹结构。这有点混乱,我对 MSDN 建议的使用 OutputPath 进行清理的解决方案并不满意 - 因为这会破坏我们的构建服务器并阻止在不同的项目(例如 SystemTest)中创建文件夹结构
所以除了添加上述目标(使用 .targets 导入),我将以下内容添加到由需要创建管道文件夹的每个“主机”导入的 .targets 文件中:
我还需要将所需的 PipelineFolder 元数据添加到实际项目引用中。例如:
As noted in my comment, calling GetTargetPath on the referenced project only returns the Primary output assembly of that project. To get all the referenced copy-local assemblies of the referenced project it's a bit messier.
Add the following to each project that you are referencing that you want to get the CopyLocals of:
My particular situation is that I needed to recreate the Pipeline folder structure for System.AddIn in the bin folder of my top level Host project. This is kinda messy and I was not happy with the MSDN suggested solutions of mucking with the OutputPath - as that breaks on our build server and prevents creating the folder structure in a different project (eg a SystemTest)
So along with adding the above target (using a .targets import), I added the following to a .targets file imported by each "host" that needs the pipeline folder created:
I also needed to add the required PipelineFolder meta data to the actual project references. For example:
您原来的解决方案只需更改
为
即可工作。
GetTargetPath
目标仅返回TargetPath
属性,不需要构建。Your original solution should work simply by changing
to
The
GetTargetPath
target simply returns theTargetPath
property and doesn't require building.如果您首先调用这样的目标,您可以保护 ProjectC 中的文件:
You may protect your files in ProjectC if you call a target like this first:
我的 当前解决方法基于这个SO问题,即,我有:
但是,这会在TeamBuild(所有输出最终都在一个目录中)下中断,并且如果依赖项目的任何输出的名称发生变化,也会中断。
编辑:还寻找有关如何使硬编码比以下内容稍微干净一点的更清晰答案的评论:
和:
My current workaround is based on this SO question, i.e, I have:
This however will break under TeamBuild (where all the outputs end up in one directory), and also if the names of any of the outputs of the dependent projects change.
EDIT: Also looking for any comments on whether there's a cleaner answer for how to make the hardcoding slightly cleaner than:
and: