2013-08-19 29 views
5

Tôi có một kịch bản msbuild tôi đã viết để biên dịch Google file Nghị định thư Buffers: (! Yay)Làm thế nào để sửa đổi một ItemDefinitionGroup từ một mục tiêu MSBuild?

<ItemGroup> 
    <ProtocolBuffer Include="Whitelist.proto" /> 
    <ProtocolBuffer Include="Whitelist2.proto" /> 
</ItemGroup> 
<ItemDefinitionGroup> 
    <ProtocolBuffer> 
    <ProtoPath>$(ProjectDir)</ProtoPath> 
    </ProtocolBuffer> 
</ItemDefinitionGroup> 
<PropertyGroup> 
    <ProtoC>$([System.IO.Path]::GetFullPath($(ProjectDir)..\ThirdParty\protobuf-2.4.1\protoc.exe))</ProtoC> 
    <ProtoOutPath>$(IntDir)CompiledProtocolBuffers</ProtoOutPath> 
</PropertyGroup> 
<Target Name="CompileProtocolBuffers" 
     BeforeTargets="ClCompile" 
     Inputs="@(ProtocolBuffer)" 
     Outputs="@(ProtocolBuffer->'$(ProtoOutPath)\%(FileName).pb.cc');@(ProtocolBuffer->'$(ProtoOutPath)\%(FileName).pb.h')"> 
    <MakeDir Directories="$(ProtoOutPath)" /> 
    <Exec 
    Command="&quot;$(ProtoC)&quot; --proto_path=&quot;$([System.IO.Path]::GetDirectoryName(%(ProtocolBuffer.ProtoPath)))&quot; --cpp_out=&quot;$(ProtoOutPath)&quot; &quot;%(ProtocolBuffer.FullPath)&quot; --error_format=msvs" 
     /> 
    <ItemGroup> 
    <ClInclude Include="$(ProtoOutPath)\%(ProtocolBuffer.FileName).pb.h" /> 
    <ClCompile Include="$(ProtoOutPath)\%(ProtocolBuffer.FileName).pb.cc"> 
     <AdditionalIncludeDirectories>$(MSBuildThisDirectory)..\ThirdParty\protobuf-2.4.1\src</AdditionalIncludeDirectories> 
     <PrecompiledHeader></PrecompiledHeader> 
     <DisableSpecificWarnings>4244;4276;4018;4355;4800;4251;4996;4146;4305</DisableSpecificWarnings> 
     <PreprocessorDefinitions>GOOGLE_PROTOBUF_NO_RTTI</PreprocessorDefinitions> 
     <WarningLevel>Level3</WarningLevel> 
    </ClCompile> 
    </ItemGroup> 
</Target> 

này biên dịch tập tin vùng đệm giao thức một cách hoàn hảo, và thêm chúng vào đầu vào của trình biên dịch. Tuy nhiên, các tệp nguồn khác của tôi muốn bao gồm các tệp .pb.h cần phải biết nơi các tệp này được tạo - vị trí thế hệ đó cần được đặt trên đường dẫn bao gồm.

Do đó, nếu và chỉ nếu người dùng đã bao gồm một mục <ProtocolBuffer nơi nào đó trong kịch bản của họ, tôi muốn thêm vị trí thế hệ (trong trường hợp này $(ProtoOutPath) để ClCompile của <AdditionalIncludeDirectories>.

Là có thể hay tôi cần phải tạo các tệp .cpp muốn sử dụng các bit được tạo ra này nhảy qua hoops?

Trả lời

4

Đọc câu hỏi của bạn và suy nghĩ "không thể khó như vậy" Người đàn ông, tôi đã sai. Trước tiên tôi nghĩ chỉ cần đặt một điều kiện, nhưng tất nhiên, người ta không thể sử dụng ItemGroup trong điều kiện toplevel vì thứ tự đánh giá, sau đó tôi cũng không thể đưa ItemDefinitionGroup vào một mục tiêu (gây ra có ai có thể sử dụng điều kiện) và sửa đổi nó ở đó. Sau đó, tôi lén đầu vào bàn phím vài lần sau khi tôi nhận ra đó là lý do tại sao bạn hỏi câu hỏi:] (btw bạn biết bao gồm một thư mục không tồn tại không thực sự là một vấn đề vì trình biên dịch sẽ vui vẻ bỏ qua nó?)

Có lẽ có một giải pháp đơn giản hơn, nhưng cuối cùng tôi đã tìm ra: nếu không có gì hoạt động, đồ chơi msbuild yêu thích của tôi aka CodeTaskFactory phải có khả năng sửa chữa nó. Nó (tôi hy vọng, không hoàn toàn kiểm tra kết quả), nhưng nó không đơn giản chút nào. Ở đây bạn đi, hãy chắc chắn để gọi các mục tiêu thử nghiệm một nơi nào đó trước khi bắt đầu xây dựng C++.

<!--Uncomment the below to define some ProtocolBuffers--> 
<!--<ItemGroup> 
    <ProtocolBuffer Include="Whitelist.proto" /> 
    <ProtocolBuffer Include="Whitelist2.proto" /> 
</ItemGroup>--> 

<!--Suppose these are your default include files defined in your C++ project--> 
<ItemDefinitionGroup Label="DefaultIncludes"> 
    <ClCompile> 
    <AdditionalIncludeDirectories>/path/to/x;/path/to/y</AdditionalIncludeDirectories> 
    </ClCompile> 
</ItemDefinitionGroup> 

<!--Include at least one item so we can play with it--> 
<ItemGroup> 
    <ClCompile Include="iamaninclude"/> 
</ItemGroup> 

<!--Use code to append to AdditionalIncludeDirectories--> 
<UsingTask TaskName="AppendMetadata" TaskFactory="CodeTaskFactory" 
      AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> 
    <ParameterGroup> 
    <Append ParameterType="System.String" Required="true"/> 
    <ItemList ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true"/> 
    <OutputItemList ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" /> 
    </ParameterGroup> 
    <Task> 
     <Code> 
     <![CDATA[ 
      const string dirz = "AdditionalIncludeDirectories"; 
      foreach(var item in ItemList) 
      { 
       var cur = item.GetMetadata(dirz); 
       item.SetMetadata(dirz, cur + ";" + Append); 
      } 
      OutputItemList = ItemList; 
     ]]> 
    </Code> 
    </Task> 
</UsingTask> 

<!--Main target--> 
<Target Name="Test"> 
    <!--stage 1: copy the itemgroup, then clear it: 
    if an Output TaskParameter is an Itemgroup, apparently the content 
    gets appended to the group instead of replacing it. 
    Found no documentation about this whatsoever though???--> 
    <ItemGroup Condition="@(ProtocolBuffer) != ''"> 
    <ClCompileCopy Include="@(ClCompile)"/> 
    <ClCompile Remove="@(ClCompile)"/> 
    </ItemGroup> 

    <!--stage 2: append 'ProtoBufIncludeDir' to AdditionalIncludeDirectories, 
    and append the result to the origiginal again--> 
    <AppendMetadata ItemList="@(ClCompileCopy)" Append="ProtoBufIncludeDir" Condition="@(ProtocolBuffer) != ''"> 
    <Output ItemName="ClCompile" TaskParameter="OutputItemList"/> 
    </AppendMetadata> 

    <!--stage 3: use modified itemgroup--> 
    <Message Text="@(ClCompile->'%(Identity): %(AdditionalIncludeDirectories)')"/> 
</Target> 

này in

iamaninclude: /path/to/x;/path/to/y 

trừ khi ProtocolBuffer là không có sản phẩm nào trong trường hợp này nó in

iamaninclude: /path/to/x;/path/to/y;ProtoBufIncludeDir 
+1

tôi đã phải đối mặt với cùng một vấn đề (mặc dù thiết lập 'PreprocessorDefinitions' lập trình thay vì ' AdditionalIncludeDirectories'). Thánh bò này là ma thuật, nhưng nó hoạt động khá tốt. Cảm ơn! –

Các vấn đề liên quan