在我的构建定义中,我需要一个包含所有已编译程序集的列表。这是微不足道的:
<CompiledAssemblies Include="$(OutDir)\MyCompany.*.dll" />
现在,如果我需要排除某些dll,我只需添加Exclude
属性。但我想更进一步:
如何排除上面CompiledAssemblies
的所有原生 dll?
答案 0 :(得分:1)
原则并不那么难:列表中的批处理,找出哪些dll是原生的,并创建一个只有那些dll的新列表。
检查dll是否正确的程序集的简单方法是在其上运行corflags
:如果它返回0,则它是一个程序集。或者在msbuild代码中(输出被重定向到NUL,否则msbuild会以红色显示错误):
<ItemGroup>
<AllDlls Include="$(OutDir)\MyCompany.*.dll"/>
</ItemGroup>
<Target Name="RunCorFlags">
<Exec Command="corflags.exe %(AllDlls.Identity) > NUL" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" ItemName="CorFlagsErrorCode"/>
</Exec>
</Target>
所以现在我们只需排除那些CorFlagsErrorCode为1的dll。这应该很简单,但是我无法弄清楚如何使用纯msbuild来实现它,因为CorFlagsErrorCode将包含一个包含1和0的列表,所以无论如何在批处理时有多少条目,它只会运行两次,因为批处理会跳过重复的项目。无论如何,CodeTaskFactory也提供了一个解决方案:
<Target Name="GetAssemblies" DependsOnTargets="RunCorFlags">
<GetAssembliesOnly Dlls="@(AllDlls)" CorFlagsErr="@(CorFlagsErrorCode)">
<Output TaskParameter="Assemblies" ItemName="CompiledAssemblies"/>
</GetAssembliesOnly>
<Message Text="CompiledAssemblies = %(CompiledAssemblies.Identity)"/>
</Target>
<UsingTask TaskName="GetAssembliesOnly" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
<ParameterGroup>
<Dlls Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
<CorFlagsErr Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
<Assemblies Output="true" ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
var temp = new List<ITaskItem>();
for( int i = 0 ; i < Dlls.Length ; ++i )
if( CorFlagsErr[ i ].ItemSpec == "0" )
temp.Add( Dlls[ i ] );
Assemblies = temp.ToArray();
]]>
</Code>
</Task>
</UsingTask>