Mam duży plik rozwiązania C # (~ 100 projektów) i próbuję poprawić czas kompilacji. Myślę, że „Kopiuj lokalnie” w wielu przypadkach jest dla nas marnotrawstwem, ale zastanawiam się nad najlepszymi praktykami.
W naszym .sln mamy aplikację A zależną od zespołu B, która zależy od zespołu C. W naszym przypadku mamy dziesiątki "B" i garść "C". Ponieważ są one zawarte w .sln, używamy odwołań do projektów. Wszystkie zestawy są obecnie kompilowane w $ (SolutionDir) / Debug (lub Release).
Domyślnie program Visual Studio oznacza te odwołania do projektów jako „Kopiuj lokalne”, co powoduje, że każde „C” jest kopiowane do $ (SolutionDir) / Debug raz na każde „B”, które jest kompilowane. Wydaje się to marnotrawstwem. Co może się nie udać, jeśli wyłączę opcję „Kopiuj lokalnie”? Co robią inne osoby z dużymi systemami?
NASTĘPUJĄCE:
Wiele odpowiedzi sugeruje rozbicie kompilacji na mniejsze pliki .sln ... W powyższym przykładzie najpierw zbudowałbym klasy podstawowe „C”, a następnie większość modułów „B”, a następnie kilka aplikacji, „ ZA". W tym modelu potrzebuję odwołań niezwiązanych z projektem do C z B. Problem, który tam napotykam, polega na tym, że „Debugowanie” lub „Wydanie” jest wypalane w ścieżce podpowiedzi i kończy się budowanie moich kompilacji wydania „B” przeciwko kompilacjom debugowania „C”.
Dla tych z Was, którzy podzielili kompilację na wiele plików .sln, jak poradzicie sobie z tym problemem?
źródło
<Private>True</Private>
w przypadku csproj?.sln
na mniejsze łamie automagii obliczenia współzależności vs dotyczącą<ProjectReference/>
s. Sam przeniosłem się z wielu mniejszych.sln
na jeden duży,.sln
tylko dlatego, że VS powoduje w ten sposób mniej problemów… Może więc w dalszej części przyjmuję niekoniecznie najlepsze rozwiązanie pierwotnego pytania? ;-)Odpowiedzi:
W poprzednim projekcie pracowałem z jednym dużym rozwiązaniem z odniesieniami do projektu i napotkałem również problem z wydajnością. Rozwiązanie było trojakie:
Zawsze ustawiaj właściwość Copy Local na false i wymuszaj to za pomocą niestandardowego kroku msbuild
Ustaw katalog wyjściowy dla każdego projektu na ten sam katalog (najlepiej względem $ (SolutionDir)
Domyślne cele cs, które są dostarczane z platformą, obliczają zestaw odniesień do skopiowania do katalogu wyjściowego aktualnie budowanego projektu. Ponieważ wymaga to obliczenia domknięcia przechodniego w ramach relacji „Referencje”, może to być BARDZO kosztowne. Moim obejściem tego problemu było ponowne zdefiniowanie
GetCopyToOutputDirectoryItems
celu we wspólnym pliku celów (np.Common.targets
), Który jest importowany w każdym projekcie po zaimportowaniu plikuMicrosoft.CSharp.targets
. W rezultacie każdy plik projektu wygląda następująco:Skróciło to nasz czas kompilacji w danym momencie z kilku godzin (głównie z powodu ograniczeń pamięci) do kilku minut.
Przedefiniowana
GetCopyToOutputDirectoryItems
mogą być tworzone poprzez kopiowanie linie 2,438-2,450 oraz 2,474-2,524 odC:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets
doCommon.targets
.Aby uzyskać kompletność, wynikowa definicja celu staje się wtedy:
Po zastosowaniu tego obejścia okazało się, że wykonalne jest posiadanie aż> 120 projektów w jednym rozwiązaniu, co ma tę główną zaletę, że kolejność kompilacji projektów może być nadal określana przez VS zamiast robić to ręcznie, dzieląc rozwiązanie .
źródło
Proponuję przeczytać artykuły Patrica Smacchii na ten temat:
Możesz również przeczytać ten artykuł, aby pomóc Ci zmniejszyć liczbę projektów i skrócić czas kompilacji.
źródło
Sugeruję, aby kopiować local = false dla prawie wszystkich projektów z wyjątkiem tego, który znajduje się na górze drzewa zależności. A dla wszystkich odniesień w tym na najwyższym zestawie kopiuj local = true. Widzę, że wiele osób sugeruje udostępnienie katalogu wyjściowego; Myślę, że to okropny pomysł oparty na doświadczeniu. Jeśli Twój projekt startowy zawiera odwołania do biblioteki DLL, do której odwołuje się inny projekt, w pewnym momencie wystąpi naruszenie zasad dostępu \ udostępniania, nawet jeśli kopia local = false na wszystkim się nie powiedzie. Ten problem jest bardzo irytujący i trudny do wyśledzenia. Całkowicie sugeruję trzymanie się z dala od katalogu wyjściowego fragmentu i zamiast umieszczania projektu na górze łańcucha zależności, zapisuj potrzebne zestawy do odpowiedniego folderu. Jeśli nie masz projektu na górze, wtedy zasugerowałbym kopię post-build, aby wszystko było we właściwym miejscu. Starałbym się również pamiętać o łatwości debugowania. Wszelkie projekty exe, które nadal zostawiam copy local = true, więc debugowanie F5 będzie działać.
źródło
Masz rację. CopyLocal całkowicie zabije Twój czas tworzenia. Jeśli masz duże drzewo źródeł, powinieneś wyłączyć CopyLocal. Niestety nie jest to tak łatwe, jak powinno być, aby go czysto wyłączyć. Odpowiedziałem dokładnie na to pytanie dotyczące wyłączania CopyLocal w Jak nadpisać ustawienie CopyLocal (Prywatne) dla odwołań w .NET z MSBUILD . Sprawdź to. Jak również najlepsze rozwiązania dotyczące dużych rozwiązań w programie Visual Studio (2008).
Oto więcej informacji na temat CopyLocal, jak to widzę.
CopyLocal został zaimplementowany tak, aby wspierać lokalne debugowanie. Przygotowując aplikację do pakowania i wdrażania, należy skompilować projekty w tym samym folderze wyjściowym i upewnić się, że masz wszystkie potrzebne odniesienia.
O tym, jak radzić sobie z budowaniem dużych drzew źródłowych, pisałem w artykule MSBuild: najlepsze praktyki tworzenia niezawodnych kompilacji, część 2 .
źródło
Moim zdaniem posiadanie rozwiązania obejmującego 100 projektów to DUŻY błąd. Prawdopodobnie możesz podzielić swoje rozwiązanie na prawidłowe logiczne małe jednostki, upraszczając w ten sposób zarówno konserwację, jak i kompilację.
źródło
Dziwię się, że nikt nie wspomniał o używaniu twardych linkó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; CreateForHardLinksForCopyFilesToOutputDirectoryIfPossible = true; CreateHardLinksForCopyLocalIfPossible = true;
Możesz również dodać to do centralnego pliku importu, aby wszystkie Twoje projekty również mogły uzyskać tę korzyść.
źródło
Jeśli masz strukturę zależności zdefiniowaną za pomocą odwołań do projektu lub zależności na poziomie rozwiązania, możesz bezpiecznie wyłączyć „Kopiuj lokalnie”, powiedziałbym nawet, że jest to najlepsza praktyka do zrobienia, ponieważ pozwoli ci to użyć MSBuild 3.5 do równoległego uruchamiania kompilacji ( via / maxcpucount) bez potykania się różnych procesów o siebie podczas próby kopiowania zestawów, do których istnieją odwołania.
źródło
naszą „najlepszą praktyką” jest unikanie rozwiązań w wielu projektach. Mamy katalog o nazwie „matrix” z aktualnymi wersjami zestawów, a wszystkie odwołania pochodzą z tego katalogu. Jeśli zmienisz jakiś projekt i możesz powiedzieć „teraz zmiana jest zakończona”, możesz skopiować zespół do katalogu „matrix”. Zatem wszystkie projekty zależne od tego zestawu będą miały bieżącą (= najnowszą) wersję.
Jeśli masz kilka projektów w rozwiązaniu, proces kompilacji jest znacznie szybszy.
Możesz zautomatyzować krok „kopiuj zestaw do katalogu macierzy” za pomocą makr programu Visual Studio lub za pomocą „menu -> narzędzia -> narzędzia zewnętrzne ...”.
źródło
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 ustawić $ (UseCommonOutputDirectory) na true. Zobacz: http://blogs.msdn.com/b/kirillosenkov/archive/2015/04/04/using-a-common-intermediate-and-output-directory-for-your-solution.aspx
źródło
Ustawienie CopyLocal = false skróci czas kompilacji, ale może powodować różne problemy podczas wdrażania.
Istnieje wiele scenariuszy, w których musisz ustawić opcję Copy Local na True, np
Możliwe problemy opisane w pytaniach SO
„ Kiedy należy ustawić wartość true dla funkcji copy-local, a kiedy nie? ”,
„ Komunikat o błędzie„ Nie można załadować jednego lub więcej żądanych typów. Pobierz właściwość LoaderExceptions, aby uzyskać więcej informacji ”. "
I Aaron-stainback jest odpowiedź na to pytanie.
Moje doświadczenie z ustawieniem CopyLocal = false NIE powiodło się. Zobacz mój post na blogu „Nie zmieniaj odniesień do projektu„ Kopiuj lokalnie ”na fałsz, chyba że rozumiesz podciągi”.
Czas potrzebny na rozwiązanie problemów przeważa nad korzyściami wynikającymi z ustawienia copyLocal = false.
źródło
CopyLocal=False
z pewnością spowoduje pewne problemy, ale są na to rozwiązania. Powinieneś także poprawić formatowanie swojego bloga, jest on ledwo czytelny, a stwierdzenie, że „Zostałem ostrzeżony przez <losowego konsultanta> z <losowa firma> o możliwych błędach podczas wdrażania” nie jest argumentem. Musisz się rozwijać.Staram się budować do wspólnego katalogu (np. \ Bin), więc mogę tworzyć małe rozwiązania testowe.
źródło
Możesz spróbować użyć folderu, w którym zostaną skopiowane wszystkie zespoły współdzielone między projektami, a następnie utwórz zmienną środowiskową DEVPATH i ustaw ją
<developmentMode developerInstallation="true" />
w pliku machine.config na stacji roboczej każdego programisty. Jedyne, co musisz zrobić, to skopiować każdą nową wersję do swojego folderu, w którym wskazuje zmienna DEVPATH.
Jeśli to możliwe, podziel również rozwiązanie na kilka mniejszych.
źródło
Może to nie jest najlepsza praktyka, ale tak właśnie pracuję.
Zauważyłem, że Managed C ++ zrzuca wszystkie swoje pliki binarne do $ (SolutionDir) / 'DebugOrRelease'. Więc porzuciłem tam również wszystkie moje projekty C #. Wyłączyłem również opcję „Kopiuj lokalnie” wszystkich odniesień do projektów w rozwiązaniu. Zauważyłem znaczną poprawę czasu kompilacji w moim małym rozwiązaniu dla 10 projektów. To rozwiązanie jest mieszanką projektów C #, zarządzanego języka C ++, natywnego języka C ++, usługi sieci web języka C # i projektów instalatora.
Może coś jest zepsute, ale ponieważ to jedyny sposób, w jaki pracuję, nie zauważam tego.
Byłoby interesujące dowiedzieć się, co łamię.
źródło
Zwykle wystarczy skopiować lokalnie, jeśli chcesz, aby projekt korzystał z biblioteki DLL znajdującej się w Twoim Bin, a nie z tego, co jest gdzie indziej (GAC, inne projekty itp.)
Zgodziłbym się z innymi ludźmi, że powinniście również spróbować, jeśli to w ogóle możliwe, zerwać z tym rozwiązaniem.
Możesz również użyć Configuration Manager, aby stworzyć różne konfiguracje kompilacji w ramach tego jednego rozwiązania, które będzie budować tylko określone zestawy projektów.
Wydawałoby się dziwne, gdyby wszystkie 100 projektów opierało się na sobie nawzajem, więc powinieneś być w stanie je rozbić lub użyć Configuration Manager, aby sobie pomóc.
źródło
Możesz mieć odniesienia do projektów wskazujące na wersje debugowania bibliotek dll. Następnie w swoim skrypcie msbuild możesz ustawić
/p:Configuration=Release
, dzięki czemu będziesz mieć wersję swojej aplikacji i wszystkie zestawy satelickie.źródło
Jeśli chcesz mieć centralne miejsce do odwoływania się do biblioteki DLL, używając polecenia copy local false, zakończy się niepowodzeniem bez GAC, chyba że to zrobisz.
http://nbaked.wordpress.com/2010/03/28/gac-alternative/
źródło
Jeśli referencja nie jest zawarta w GAC, musimy ustawić Copy Local na true, aby aplikacja działała, jeśli mamy pewność, że referencja zostanie preinstalowana w GAC, to możemy ustawić ją na false.
źródło
Cóż, na pewno nie wiem, jak działają problemy, ale miałem kontakt z rozwiązaniem do kompilacji, które pomogło sobie w taki sposób, że wszystkie utworzone pliki były umieszczane na ramdysku za pomocą dowiązań symbolicznych .
c: \ folder rozwiązania \ obj -> ramdysk r: \ folder rozwiązania \ obj \
Możesz również wskazać programowi Visual Studio, którego katalogu tymczasowego może użyć do kompilacji.
Właściwie to nie wszystko, co zrobił. Ale to naprawdę uderzyło w moje rozumienie wydajności.
100% wykorzystania procesora i ogromny projekt w mniej niż 3 minuty ze wszystkimi zależnościami.
źródło