piątek, 9 kwietnia 2010

sprytniejsze budowanie zbiorcze

Jest sobie duży projekt w C++? Jest problem z czasem kompilacji z powodu dużej liczby jednostek translacji(plików cpp)? Oto proste rozwiązanie, oparte na znanej idei budowania zbiorczego, czyli "unity build" (zwanej też "uber build" albo "bulk build"), polegającej na #includowaniu plików cpp do zbiorczego pliku cpp i kompilowaniu jego zamiast rzeczonych plików.

Cechą unikatową rozwiązania, które zaraz opiszę jest to, że:
A) Nie trzeba męczyć się z ręcznym wybieraniem plików, które mają być skompilowane. Po prostu kompilujemy wszystkie pliki cpp (w przeciwieństwie do powyżej realizacji "unity build").
B) Można dowolnie przełączać pomiędzy "unity build" a normalną kompilacją.

Cały mechanizm zadziała automatycznie, jedyną rzeczą, która sygnalizuje chęć skorzystania z unity build jest dodanie jednej opcji polecenia wywołującego linker.

Aby zaimplementować mechanizm, wystarczy zrobić 2 rzeczy:
A) W każdym pliku cpp dopisać na początku (przed poleceniami #include)
#if defined(IN_COLLECTIVE) or not defined(BUILD_COLLECTIVELY)
a na końcu
#endif
B) W każdym folderze zrobić plik zbiorczy collective.cpp, wyglądający mniej więcej tak:
#ifdef BUILD_COLLECTIVELY
#define IN_COLLECTIVE
#include"A.cpp"
#include"B.cpp"
#include"C.cpp"
#include"D.cpp"
#include"E.cpp"
#undef IN_COLLECTIVE
#endif


Oczywiście A,B,C,D,E to nazwy plików cpp w folderze, gdzie znajduje się plik z powyższym kodem.

W efekcie, jeśli dodamy do opcji linkera makrodefinicję BUILD_COLLECTIVELY, to program zbuduje nam się kilka razy szybciej. Jeżeli nie, to wszystko będzie po staremu. Podkreślam, że BUILD_COLLECTIVELY możemy dodać do wywołania linkera, np.
g++ -DBUILD_COLLECTIVELY ..., nie musimy w żadnym pliku nagłówkowym.
Nie będę tu gęsto tłumaczył dlaczego to przyspiesza kompilację, ani nie będę wymieniał wszystkich zalet i wad "unity build", najlepiej odeślę do materiałów poglądowych:
http://buffered.io/2007/12/10/the-magic-of-unity-builds/
http://stackoverflow.com/questions/861707/is-reducing-number-of-cpp-translation-units-a-good-idea
a tutaj tylko zakreślę przyczynę: chodzi głównie o to, że wszystkie includowane nagłówki są przetwarzane tylko raz, a nie tyle razy, ile jest plików cpp.

W pierwszym linku powyżej są opisywane rozwiązania polegające na wyłączeniu z kompilacji wszystkich plików cpp poza zbiorczym lub też tworzeniu osobnego projektu do budowania zbiorczego. Moje rozwiązanie stanowi ulepszenie w stosunku do nich, dlatego, że w praktyce jeżeli pliki są wyłączane z projektu w ulubionym IDE lub kod jest wyłączony kompilacją warunkową, ciężko jest zmusić IDE do włączenia w takim kodzie pomocy kontekstowej, podświetlania znaczeniowego i innych udogodnień. W moim rozwiązaniu do wygodnej pracy nad tym kodem wystarczy nie zdefiniować BUILD_COLLECTIVELY (czyli tak naprawdę nie trzeba robić nic).

Zauważ, że rozwiązanie jest całkowicie transparentne, tzn jeżeli kolega zacznie pracować nad naszym kodem i utworzy sobie do tego celu nowy projekt, to domyślnie będzie miał stary, znany mu sposób budowania, pomoc kontekstową i nie będzie musiał nic dodatkowo ustawiać, żeby w ogóle zacząć pracę.

Zauważ również, że w wymienionych wymienionych powyżej krokach nie ma nic, czego nie mógłby dopisać prosty skrypt, można więc z łatwością zaimplementować to rozwiązanie w naprawdę dużym projekcie.

Brak komentarzy:

Prześlij komentarz