Jaka jest najlepsza praktyka dla "kopiowania lokalnego" i z odniesieniami do projektów?

Mam duży plik rozwiązania c# (~100 projektów) i staram się poprawić czas budowania. Myślę, że "Copy Local" jest dla nas marnotrawstwem w wielu przypadkach, ale zastanawiam się nad najlepszymi praktykami.

W naszym .sln, mamy aplikację a w zależności od montażu B, która zależy od montażu C. w naszym przypadku są dziesiątki " B "i garść "C". Ponieważ są one zawarte w .sln, używamy referencji do projektów. Wszystkie zestawy obecnie wbudowane w $(SolutionDir) / Debug (lub Release).

Domyślnie Visual Studio oznacza te odniesienia do projektu jako "Copy Local", co powoduje, że każde" C "jest kopiowane do $(SolutionDir)/Debug raz dla każdego" B", które buduje. To wygląda na marnotrawstwo. Co może pójść nie tak, jeśli po prostu wyłączę "Kopiuj lokalne"? Co robią inni ludzie z dużymi systemami?

Kontynuacja:

Wiele odpowiedzi sugeruje rozbicie zabudowy na mniejsze .pliki sln... W powyższym przykładzie najpierw zbudowałbym klasy fundamentowe" C", następnie większość modułów "B", a następnie kilka aplikacji,"A". W tym modelu, muszę mieć odniesienia do C spoza projektu z B. problem, który napotkam tam jest to, że " Debug "lub" Release "zostaje upieczony w ścieżce podpowiedzi i kończę budowanie moich kompilacji wydania" B "przeciwko kompilacji debugowania "C".

Dla tych z Was, którzy podzielili kompilację na wiele .pliki sln, jak poradzić sobie z tym problemem?

Author: Dave Moore, 2008-11-11

18 answers

W poprzednim projekcie pracowałem z jednym dużym rozwiązaniem z odniesieniami do projektów i wpadłem na problem wydajności, jak również. Rozwiązanie było trzykrotnie:

  1. Zawsze ustaw właściwość Copy Local NA false i Wymuś to za pomocą niestandardowego kroku msbuild

  2. Ustaw katalog wyjściowy dla każdego projektu na ten sam katalog (najlepiej względny do $(SolutionDir)

  3. Domyślne cele cs, które są wysyłane z frameworkiem obliczają zbiór odnośniki do skopiowania do katalogu docelowego aktualnie budowanego projektu. Ponieważ wymaga to obliczenia przechodniego zamknięcia pod relacją "Reference", może to stać się bardzo kosztowne. Moje obejście tego problemu polegało na ponownym zdefiniowaniu celu GetCopyToOutputDirectoryItems we wspólnym pliku docelowym (np. Common.targets), który jest importowany do każdego projektu po zaimportowaniu Microsoft.CSharp.targets. W rezultacie każdy plik projektu wygląda następująco:

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        ... snip ...
      </ItemGroup>
      <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
      <Import Project="[relative path to Common.targets]" />
      <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
           Other similar extension points exist, see Microsoft.Common.targets.
      <Target Name="BeforeBuild">
      </Target>
      <Target Name="AfterBuild">
      </Target>
      -->
    </Project>
    

To skróciło nasz czas budowy na biorąc pod uwagę czas od kilku godzin (głównie ze względu na ograniczenia pamięci), do kilku minut.

Redefinicję GetCopyToOutputDirectoryItems można utworzyć kopiując linie 2,438-2,450 i 2,474-2,524 z C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets do Common.targets.

Dla kompletności otrzymana definicja celu staje się wtedy:

<!-- This is a modified version of the Microsoft.Common.targets
     version of this target it does not include transitively
     referenced projects. Since this leads to enormous memory
     consumption and is not needed since we use the single
     output directory strategy.
============================================================
                    GetCopyToOutputDirectoryItems

Get all project items that may need to be transferred to the
output directory.
============================================================ -->
<Target
    Name="GetCopyToOutputDirectoryItems"
    Outputs="@(AllItemsFullPathWithTargetPath)"
    DependsOnTargets="AssignTargetPaths;_SplitProjectReferencesByFileExistence">

    <!-- Get items from this project last so that they will be copied last. -->
    <CreateItem
        Include="@(ContentWithTargetPath->'%(FullPath)')"
        Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
            >
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>

    <CreateItem
        Include="@(_EmbeddedResourceWithTargetPath->'%(FullPath)')"
        Condition="'%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
            >
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>

    <CreateItem
        Include="@(Compile->'%(FullPath)')"
        Condition="'%(Compile.CopyToOutputDirectory)'=='Always' or '%(Compile.CopyToOutputDirectory)'=='PreserveNewest'">
        <Output TaskParameter="Include" ItemName="_CompileItemsToCopy"/>
    </CreateItem>
    <AssignTargetPath Files="@(_CompileItemsToCopy)" RootFolder="$(MSBuildProjectDirectory)">
        <Output TaskParameter="AssignedFiles" ItemName="_CompileItemsToCopyWithTargetPath" />
    </AssignTargetPath>
    <CreateItem Include="@(_CompileItemsToCopyWithTargetPath)">
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>

    <CreateItem
        Include="@(_NoneWithTargetPath->'%(FullPath)')"
        Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
            >
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>
</Target>

Z tym obejściem okazało się, że można mieć aż > 120 projektów w jednym rozwiązaniu, ma to główną zaletę, że kolejność budowania projektów może być nadal określona przez VS zamiast robić to ręcznie, dzieląc swoje rozwiązanie.

 82
Author: Bas Bossink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-13 09:26:05

Proponuję przeczytać artykuły Patrica Smacchia na ten temat:

CC.Net projekty VS opierają się na opcji Kopiuj lokalny zespół odniesienia ustawionej na true. [...] Nie tylko znacznie wydłuża to czas kompilacji (x3 w przypadku NUnit), ale także psuje środowisko pracy. Wreszcie, co nie mniej ważne, stwarza to ryzyko wystąpienia potencjalnych problemów w wersji. Btw, NDepend wyświetli ostrzeżenie, jeśli znajdzie 2 zespoły w 2 różne katalogi o tej samej nazwie, ale nie tej samej zawartości lub wersji.

Właściwe jest zdefiniowanie 2 katalogów $RootDir$\bin\Debug i $RootDir$\bin\Release oraz skonfigurowanie projektów VisualStudio tak, aby emitowały zespoły w tych katalogach. Wszystkie odniesienia do projektów powinny odwoływać się do zestawów w katalogu Debug.

Możesz również przeczytać ten artykuł , aby pomóc ci zmniejszyć liczbę projektów i poprawić czas kompilacji.

 31
Author: Julien Hoarau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-12 23:30:13

Sugeruję użycie copy local = false dla prawie wszystkich projektów z wyjątkiem tego, który znajduje się na szczycie drzewa zależności. I dla wszystkich referencji w tym na górze Ustaw local = true. Widzę wiele osób sugerujących dzielenie się katalogiem wyjściowym; myślę, że jest to okropny pomysł oparty na doświadczeniu. Jeśli twój projekt startowy zawiera odniesienia do biblioteki dll, do której odnosi się każdy inny projekt, w pewnym momencie wystąpi naruszenie access \ sharing, nawet jeśli copy local = false on wszystko i twoja Budowa zawiedzie. Ten problem jest bardzo irytujący i trudny do wyśledzenia. Całkowicie sugeruję trzymanie się z dala od katalogu wyjściowego shard i zamiast mieć projekt na górze łańcucha zależności, Zapisz potrzebne Zespoły do odpowiedniego folderu. Jeśli nie masz projektu na "górze", sugerowałbym kopię post-build, aby wszystko było we właściwym miejscu. Chciałbym również spróbować i pamiętać o łatwości debugowania. Wszelkie projekty exe nadal pozostawiam kopię local = true więc debugowanie F5 będzie działać.

 23
Author: Aaron Stainback,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-03 00:34:24

Masz rację. CopyLocal całkowicie zabije twój czas budowy. Jeśli masz duże drzewo źródłowe, powinieneś wyłączyć CopyLocal. Niestety nie jest tak łatwo, jak powinno być, aby wyłączyć go czysto. Odpowiedziałem dokładnie na to pytanie dotyczące wyłączania CopyLocal w Jak nadpisać ustawienie CopyLocal (Private) dla referencji W.NET z MSBUILD. Zobacz też A także najlepsze praktyki dla dużych rozwiązań w Visual Studio (2008).

Oto kilka informacji na temat CopyLocal jak ja to widzę.

CopyLocal został zaimplementowany do obsługi lokalnego debugowania. Przygotowując aplikację do pakowania i wdrożenia, powinieneś zbudować swoje projekty w tym samym folderze wyjściowym i upewnić się, że masz tam wszystkie potrzebne referencje.

O tym, jak radzić sobie z budowaniem dużych drzew źródłowych pisałem w artykule MSBuild: Best Practices For Creating Reliable Builds, Part 2.
 10
Author: Sayed Ibrahim Hashimi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:34

Moim zdaniem rozwiązanie ze 100 projektami to duży błąd. Prawdopodobnie możesz podzielić swoje rozwiązanie na ważne logiczne małe jednostki, upraszczając w ten sposób zarówno konserwację, jak i kompilację.

 9
Author: Bruno Shine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-11 12:45:15

Dziwię się, że nikt nie wspomniał o używaniu hardlinków. Zamiast kopiować pliki, tworzy twarde łącze do oryginalnego pliku. Oszczędza to miejsce na dysku, a także znacznie przyspiesza kompilację. Można to włączyć w wierszu poleceń z następującymi właściwościami:

/p:CreateHardLinksForAdditionalFilesifpossible=true;CreateHardLinksForCopyAdditionalfilesifpossible=true;CreateHardLinksForCopyFilesToOutputdirectoryifpossible=true;CreateHardLinksForCopyLocalIfPossible=true;CreateHardLinksForPublishFilesIfpossible=true

Możesz również dodać to do centralnego pliku importu, aby wszystkie projekty mogły również uzyskać tę korzyść.

 6
Author: Matt Slagle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-17 19:53:16

Jeśli masz strukturę zależności zdefiniowaną za pomocą referencji projektu lub zależności poziomu rozwiązania, bezpiecznie jest włączyć "Copy Local", powiedziałbym nawet, że jest to najlepsza praktyka, więc ponieważ pozwoli Ci to używać MSBuild 3.5 do uruchamiania kompilacji równolegle (poprzez /maxcpucount) bez różnych procesów potkających się o siebie podczas próby skopiowania odwołanych zestawów.

 5
Author: Torbjörn Gyllebring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 07:58:40

Naszą "najlepszą praktyką" jest unikanie rozwiązań w wielu projektach. Mamy katalog o nazwie "matrix" z aktualnymi wersjami złożeń, a wszystkie odniesienia pochodzą z tego katalogu. Jeśli zmienisz jakiś projekt i powiesz "teraz zmiana jest zakończona" możesz skopiować montaż do katalogu "matrix". Tak więc wszystkie projekty, które zależą od tego zestawu, będą miały aktualną (=najnowszą) wersję.

Jeśli masz kilka projektów w rozwiązaniu, proces budowania jest znacznie szybszy.

Ty można zautomatyzować krok "Kopiuj montaż do katalogu macierzy" za pomocą makr visual studio lub za pomocą " menu - > Narzędzia - > Narzędzia zewnętrzne...".

 4
Author: TcKs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-18 23:58:55

Ustawienie CopyLocal = false skraca czas kompilacji, ale może powodować różne problemy podczas wdrażania.

Istnieje wiele scenariuszy, kiedy trzeba mieć Copy Local 'left' do True, np.

  • projekty najwyższego poziomu,
  • zależności drugiego poziomu,
  • DLLs wywołane przez odbicie

Możliwe zagadnienia opisane w So questions
"kiedy copy-local powinien być ustawiony na true, a kiedy nie?",
"komunikat o błędzie ' Nie można załadować jeden lub więcej żądanych typów. Aby uzyskać więcej informacji, należy pobrać właściwość LoaderExceptions.'"
i aaron-stainback'S odpowiedz na to pytanie.

Moje doświadczenie z ustawieniem CopyLocal = false nie powiodło się. Zobacz mój wpis na blogu " Nie zmieniaj "Kopiuj lokalne" odniesienia do projektu na false, chyba że zrozumiesz."

Czas rozwiązania problemów obciąża korzyści płynące z ustawienia copyLocal = false.

 3
Author: Michael Freidgeim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:55

Nie musisz zmieniać wartości CopyLocal. Wszystko, co musisz zrobić, to wstępnie zdefiniować wspólną $(OutputPath) dla wszystkich projektów w rozwiązaniu i wstępnie ustawić $(UseCommonOutputDirectory) na true. Zobacz też: http://blogs.msdn.com/b/kirillosenkov/archive/2015/04/04/using-a-common-intermediate-and-output-directory-for-your-solution.aspx

 3
Author: Sheen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-15 22:11:06

Mam tendencję do budowania wspólnego katalogu (np. ..\bin), dzięki czemu mogę tworzyć małe rozwiązania testowe.

 1
Author: kenny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-11 12:39:59

Możesz spróbować użyć folderu, w którym zostaną skopiowane wszystkie zespoły współdzielone między projektami, a następnie utworzyć zmienną środowiskową DEVPATH i ustawić

<developmentMode developerInstallation="true" />

w maszynie.plik konfiguracyjny na każdej stacji roboczej programisty. Jedyne, co musisz zrobić, to skopiować nową wersję do folderu, w którym znajduje się zmienna DEVPATH.

Również podzielić swoje rozwiązanie na kilka mniejszych rozwiązań, jeśli to możliwe.

 1
Author: Aleksandar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-11 12:54:06

To może nie jest najlepsza pratice, ale tak pracuję.

Zauważyłem, że Managed C++ zrzuca wszystkie swoje binaria do $(SolutionDir) / 'DebugOrRelease'. Więc wyrzuciłem tam wszystkie moje projekty C#. Wyłączyłem również "Kopiuj lokalne" wszystkich odniesień do projektów w rozwiązaniu. Miałem zauważalną poprawę czasu budowy w moim małym rozwiązaniu projektowym 10. To rozwiązanie jest mieszanką projektów C#, managed C++, native C++, C# webservice i installer.

Maybe something is broken, ale ponieważ jest to jedyny sposób, w jaki pracuję, nie zauważam tego.

Byłoby ciekawie dowiedzieć się, co łamię.

 1
Author: jyoung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-11 14:16:33

Zwykle musisz tylko skopiować lokalny, jeśli chcesz, aby twój projekt korzystał z biblioteki DLL, która jest w Twoim koszu vs. co jest gdzie indziej (GAC, inne projekty, itp.)

Zgodzę się z innymi ludźmi, że powinieneś również spróbować, jeśli to możliwe, rozbić To rozwiązanie.

Możesz również użyć Configuration Managera, aby stworzyć różne konfiguracje budowania w ramach tego jednego rozwiązania, które będzie budować tylko dane zestawy projektów.

Wydaje się dziwne, gdyby wszystkie 100 projekty polegały na sobie, więc powinieneś być w stanie je rozdzielić lub użyć menedżera konfiguracji, aby sobie pomóc.

 0
Author: CubanX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-11 12:48:08

Możesz mieć odniesienia do projektów wskazujących na wersje debugowania bibliotek DLL. Niż na skrypcie msbuild, możesz ustawić /p:Configuration=Release, dzięki czemu będziesz miał wersję release swojej aplikacji i wszystkich zestawów satelitarnych.

 0
Author: Bruno Shine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-12 12:32:37

Jeśli chcesz mieć centralne miejsce do odwoływania się do DLL za pomocą copy local false zawiedzie bez GAC, chyba że to zrobisz.

Http://nbaked.wordpress.com/2010/03/28/gac-alternative/

 0
Author: user306031,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-31 13:17:40

Jeśli Referencja nie jest zawarta w GAC, musimy ustawić Copy Local na true, aby aplikacja działała, jeśli jesteśmy pewni, że Referencja będzie preinstalowana w GAC, to możemy ją ustawić na false.

 0
Author: SharpGobi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-16 07:25:36

Cóż, na pewno Nie wiem, jak problemy się rozwiązują, ale miałem kontakt z rozwiązaniem build, które pomogło sobie w tym, że wszystkie utworzone pliki umieszczane są na ramdisk za pomocą dowiązań symbolicznych .

  • c:\solution folder\bin - > ramdisk r:\solution folder\bin \
  • C:\solution folder \ obj - > ramdisk r:\solution folder\obj\

  • Możesz również dodatkowo powiedzieć visual studio, który katalog tymczasowy może użyć do kompilacji.

Właściwie to nie było to, co zrobił. Ale to naprawdę uderzyło w moje rozumienie wydajności.
100% wykorzystanie procesora i ogromny projekt w mniej niż 3 minuty ze wszystkimi zależnościami.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-24 13:01:13