2010-02-24 7 views
6

कई परियोजनाओं वाले समाधान के हिस्से के रूप में, मेरे पास एक प्रोजेक्ट है जो संदर्भ (<ProjectReference> समाधान में तीन अन्य परियोजनाओं के साथ-साथ कुछ अन्य) के माध्यम से संदर्भित करता है। AfterBuild में, मुझे 3 विशिष्ट आश्रित परियोजनाओं के आउटपुट को किसी अन्य स्थान पर कॉपी करने की आवश्यकता है।एमएसबिल्ड में प्रोजेक्ट रिफरेंस के आउटपुट को अनावश्यक पुनर्निर्माण ट्रिगर किए बिना

वाया विभिन्न अतः जवाब, आदि तरह से मैं पर बसे है कि पूरा करने के लिए किया गया था:

<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 प्रोजेक्टसी के obj/Debug फ़ोल्डर में फ़ाइल में जमा किया जा रहा है, जो कि अगर मैं AfterBuild लक्ष्य वाले प्रोजेक्ट को शामिल करता हूं, तो पूरे समाधान पर बिल्ड करते समय प्रोजेक्टसी को पुनर्निर्मित कर देता है, जबकि यदि कोई इस परियोजना को निर्माण से बाहर करता है, यह [सही ढंग से] ProjectC (और गंभीर रूप से प्रोजेक्टसी के सभी आश्रितों के पुनर्निर्माण) के पुनर्निर्माण को ट्रिगर नहीं करता है। यह इस मामले में वीएस-विशिष्ट चाल हो सकता है जो टीमबिल्ड या अन्य कमांडलाइन एमएसबिल्ड आमंत्रण के संदर्भ में नहीं होगा (लेकिन सबसे आम उपयोग वीएस के माध्यम से होगा, इसलिए मुझे इसे किसी भी तरह से हल करने की आवश्यकता है)

आश्रित परियोजनाओं (और सामान्य रूप से शेष समाधान) सभी को वीएस के साथ अंतःक्रियात्मक रूप से बनाया गया है, और इसलिए ProjectRefence के सापेक्ष पथ आदि शामिल हैं। मैंने देखा है कि इस मुद्दे का कारण होने की संभावना है - लेकिन बिना किसी पूर्ण स्पष्टीकरण के, या जब यह तय किया जाएगा या इसके आसपास कैसे काम करना है। दूसरे शब्दों में, मुझे वास्तव में दिलचस्पी नहीं है उदा। .csproj को हाथ से संपादित करके ProjectReference पथों को पूर्ण पथों में परिवर्तित करना।

हालांकि यह पूरी तरह संभव मैं कुछ बेवकूफ कर रहा हूँ और किसी को तुरंत बाहर बिंदु होगा कि यह क्या है (जो बहुत अच्छा होगा), आश्वासन दिया जा रहा /v:diag से अधिक आउटपुट आदि poring (हालांकि मैंने कोशिश नहीं की है बहुत समय बिताया है जमीन से एक रेप्रो निर्माण करने के लिए - यह एक अपेक्षाकृत जटिल समग्र निर्माण के संदर्भ) में है

उत्तर

6

के रूप में मेरी टिप्पणी में बताया गया है, संदर्भित परियोजना पर GetTargetPath बुला केवल कि इस परियोजना के प्राथमिक उत्पादन विधानसभा देता है। संदर्भित परियोजना की सभी संदर्भित प्रति-स्थानीय असेंबली प्राप्त करने के लिए यह थोड़ा गड़बड़ है।

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

मेरे विशेष स्थिति है कि मैं बिन में System.AddIn के लिए पाइप लाइन फ़ोल्डर संरचना को पुन: करने के लिए आवश्यक है:

प्रत्येक परियोजना है कि आप संदर्भित कर रहे है कि आप की CopyLocals प्राप्त करना चाहते हैं के लिए निम्न जोड़ें मेरे शीर्ष स्तर की मेजबान परियोजना का फ़ोल्डर। यह थोड़े गन्दा है और मैं आउटपुटपैथ के साथ एमकडीएन के सुझावों के साथ खुश नहीं था - क्योंकि यह हमारे बिल्ड सर्वर पर टूटता है और एक अलग परियोजना (जैसे सिस्टमटेस्ट) में फ़ोल्डर संरचना बनाने से रोकता है

तो जोड़ने के साथ आवश्यक PipelineFolder मेटा डेटा जोड़ने के

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

मैं भी जरूरत: ऊपर लक्ष्य (एक .targets आयात का उपयोग), मैं एक .targets प्रत्येक "मेजबान" कि पाइपलाइन फ़ोल्डर बनाया जरूरत से आयात की गई फ़ाइल के लिए निम्न जोड़ा वास्तविक परियोजना संदर्भों के लिए। उदाहरण के लिए:

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

मेरे current workaround is based on this SO question, यानी, मेरे पास है:

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

हालांकि यह TeamBuild (नीचे टूट जाएगा, जहां सभी उत्पादन एक निर्देशिका में समाप्त होता है), और यदि निर्भर प्रोज के किसी भी आउटपुट के नाम भी हैं ects बदल जाते हैं।

संपादित करें:

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

आप ProjectC में आपकी फ़ाइलों की रक्षा कर सकते हैं इसके अलावा कि क्या वहाँ कैसे hardcoding थोड़ा क्लीनर की तुलना में बनाने के लिए के लिए एक क्लीनर जवाब पर कोई टिप्पणी की तलाश में यदि आप पहले इस तरह के लक्ष्य को कॉल करते हैं:

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

सबसे पहले, इस गूढ़ व्यक्ति को अपने पहले कभी SO उत्तर के रूप में चुनने पर धन्यवाद/बधाई! मैं व्यक्तिगत रूप से इस प्रकार की MSBuild के आंतरिक भागों पर निर्भरता को शुरू करने के बारे में मितभाषी होगा, लेकिन हाँ, यह निश्चित रूप से मुझे प्राप्त करने के लिए "क्या फ़ाइलों यह लिखा" प्रोग्राम के रूप में की अनुमति होगी! SO पर कुछ अन्य "आउटपुट की गणना करें" प्रश्न हैं कि यह एक उत्तर के रूप में बेहतर फिट हो सकता है। मेरे लिए यहां मुख्य मुद्दा यह है कि '

5

आपकी उत्पत्ति एल समाधान

Targets="GetTargetPath" 

को

Targets="Build" 

बदलकर बस काम करना चाहिए GetTargetPath लक्ष्य बस TargetPath संपत्ति वापस आती है और निर्माण की आवश्यकता नहीं है।

+0

+1 धन्यवाद, यह सत्यापित करने की स्थिति में नहीं है कि यह निश्चित रूप से काम करता है (पुल के नीचे से बहुत सारे पानी!), लेकिन यह एक बहुत व्यवहार्य और साफ दृष्टिकोण लगता है। –

+0

वाईएमएमवी: GetTargetPath केवल एक प्रोजेक्ट की प्राथमिक आउटपुट असेंबली (डीएलएल/.EXE) देता है यदि आप उस परियोजना के _all_ संदर्भित असेंबली चाहते हैं तो एक अलग तकनीक –

+0

की आवश्यकता है यदि किसी और को C++ प्रोजेक्ट के लिए ऐसा करने की ज़रूरत है तो सही लक्ष्य आमंत्रित करने के लिए लक्ष्य = "GetNativeTargetPath" है। – Neutrino

संबंधित मुद्दे