c++ - How can one modify an ItemDefinitionGroup from an MSBuild target? -


i have msbuild script wrote compile google protocol buffers files:

<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> 

this compiles protocol buffers files perfectly, , adds them compiler's inputs (yay!). however, other source files want include .pb.h files need know these files got generated -- generation location needs put on include path.

therefore, if , if user has included <protocolbuffer item somewhere in script, want add generation location (in case $(protooutpath) clcompile's <additionalincludedirectories>.

is possible or need make .cpp files want use these generated bits jump through hoops?

read question , thought "can't hard". man, wrong. first thought putting condition on it, of course 1 can't use itemgroups in toplevel conditions because of evaluation order. figured it's not possible put itemdefinitiongroup in target (cause there 1 can use conditions) , modify there. bonked head on keyboard couple of times after realized that's why asked question :] (btw know including nonexisting directory not problem since compiler happily ignore it?)

maybe there's simpler solution, lastly figured: if nothing works, favourite msbuild toy aka codetaskfactory must able fix it. (i hope, didn't test result), it's not straightforward @ all. here go, make sure invoke test target somewhere before c++ build starts.

<!--uncomment below define protocolbuffers-->   <!--<itemgroup>   <protocolbuffer include="whitelist.proto" />   <protocolbuffer include="whitelist2.proto" /> </itemgroup>-->  <!--suppose these default include files defined in c++ project--> <itemdefinitiongroup label="defaultincludes">   <clcompile>     <additionalincludedirectories>/path/to/x;/path/to/y</additionalincludedirectories>   </clcompile> </itemdefinitiongroup>  <!--include @ least 1 item can play it--> <itemgroup>   <clcompile include="iamaninclude"/> </itemgroup>  <!--use code append 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 itemgroup, clear it:   if output taskparameter itemgroup, apparently content   gets appended group instead of replacing it.   found no documentation whatsoever though???-->   <itemgroup condition="@(protocolbuffer) != ''">     <clcompilecopy include="@(clcompile)"/>     <clcompile remove="@(clcompile)"/>   </itemgroup>    <!--stage 2: append 'protobufincludedir' additionalincludedirectories,   , append result 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> 

this prints

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

unless protocolbuffer not empty in case prints

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

Popular posts from this blog

php - How should I create my API for mobile applications (Needs Authentication) -

5 Reasons to Blog Anonymously (and 5 Reasons Not To)

Google AdWords and AdSense - A Dynamic Small Business Marketing Duo