Chociaż potrafię kodować, nie mam jeszcze doświadczenia w pracy przy dużych projektach. Do tej pory robiłem albo kodowanie małych programów, które kompilowałem w ciągu kilku sekund (różne ćwiczenia c / c ++, takie jak algorytmy, zasady programowania, pomysły, paradygmaty, lub po prostu wypróbowywanie interfejsu API ...) lub praca nad kilkoma mniejszymi projektami, które były wykonane w języku (językach) skryptowym (python, php, js), w których nie jest wymagana kompilacja.
Chodzi o to, że kiedy koduję w języku skryptowym, za każdym razem, gdy chcę spróbować, czy coś działa - po prostu uruchamiam skrypt i sprawdzam, co się stanie. Jeśli coś nie działa, mogę po prostu zmienić kod i wypróbować go ponownie, uruchamiając skrypt ponownie i robiąc to, dopóki nie uzyskam oczekiwanego rezultatu. Chodzi mi o to, że nie musisz czekać na wszystko do skompilowania, dzięki czemu łatwo jest wziąć dużą bazę kodu, zmodyfikować ją, dodać do niej coś lub po prostu grać z nią - zmiany można zobaczyć natychmiast.
Jako przykład wezmę Wordpress. Łatwo jest spróbować dowiedzieć się, jak utworzyć dla niego wtyczkę. Najpierw zaczniesz od utworzenia prostej wtyczki „Hello World”, następnie utworzysz prosty interfejs dla panelu administracyjnego, aby zapoznać się z interfejsem API, a następnie zbudujesz go i stworzysz coś bardziej złożonego, w międzyczasie zmieniając jego wygląd razy .. Pomysł powtarzania kompilacji czegoś tak dużego jak WP w kółko, po każdej drobnej zmianie, aby spróbować „jeśli to działa” i „jak to działa / czuje się” wydaje się po prostu nieefektywny, powolny i niewłaściwy.
Jak mogę to zrobić z projektem napisanym w skompilowanym języku? Chciałbym uczestniczyć w niektórych projektach typu open source, a to pytanie wciąż mnie denerwuje. Sytuacja prawdopodobnie różni się w zależności od projektu, w którym niektóre z nich, które zostały mądrze przemyślane, będą w pewnym sensie „modułowe”, podczas gdy inne będą tylko jednym wielkim blobem, który należy ponownie kompilować.
Chciałbym dowiedzieć się więcej o tym, jak to zrobić poprawnie. Jakie są typowe praktyki, podejścia i projekty projektów (wzorce?), Aby sobie z tym poradzić? Jak nazywa się ta „modułowość” w świecie programistów i po co powinienem szukać w Google, aby dowiedzieć się więcej na ten temat? Czy często projekty wyrastają z pierwotnych proporcji, które po pewnym czasie stają się kłopotliwe? Czy jest jakiś sposób na uniknięcie długiego kompilowania niezbyt dobrze zaprojektowanych projektów? Sposób na ich modularyzację (może z wyłączeniem nieistotnych części programu podczas opracowywania (jakieś inne pomysły?))?
Dzięki.
źródło
Odpowiedzi:
Tak jak powiedziano, nigdy nie rekompilujesz całego projektu za każdym razem, gdy dokonasz niewielkiej zmiany. Zamiast tego rekompilujesz tylko część kodu, która uległa zmianie, a także cały kod w zależności od niego.
W C / C ++ kompilacja jest dość prosta. Ci skompilować tłumaczyć każdy plik źródłowy do kodu maszynowego (nazywamy je sprzeciw pliki * .o), a następnie połączyć wszystkie pliki obiektów w jeden duży plik wykonywalny.
Tak jak wspomniano w MainMa, niektóre biblioteki są wbudowane w osobne pliki, które będą dynamicznie łączone w czasie wykonywania z plikiem wykonywalnym. Biblioteki te nazywane są obiektami współdzielonymi (* .so) w systemach Unix i dynamicznie połączonych bibliotekach (DLL) w systemie Windows. Biblioteki dynamiczne mają wiele zalet, z których jedną jest to, że nie trzeba ich kompilować / łączyć, chyba że kod źródłowy skutecznie się zmieni.
Istnieją narzędzia automatyzacji kompilacji, które pomogą Ci:
Najsłynniejsze (make, ant, maven, ...) mogą automatycznie wykryć, które części kodu zostały zmienione od czasu ostatniej kompilacji i dokładnie jaki obiekt / plik binarny wymaga aktualizacji.
Jest to jednak (stosunkowo niewielki) koszt napisania „skryptu kompilacji”. Jest to plik zawierający wszystkie informacje o twojej kompilacji, takie jak definiowanie celów i ich zależności, definiowanie jakiego kompilatora chcesz i jakich opcji użyć, definiowanie środowiska kompilacji, ścieżek bibliotek, ... Być może słyszałeś o Makefiles (bardzo powszechne w świecie Unix) lub build.xml (bardzo popularny w świecie Java). Tak robią.
źródło
build.xml
plikuNie kompilujesz całego projektu za każdym razem. Na przykład, jeśli jest to aplikacja C / C ++, istnieje szansa, że zostanie ona podzielona na biblioteki (biblioteki DLL w systemie Windows), a każda biblioteka zostanie skompilowana osobno.
Sam projekt jest zazwyczaj kompilowany codziennie na dedykowanym serwerze: są to kompilacje nocne. Proces ten może zająć dużo czasu, ponieważ obejmował nie tylko czas kompilacji, ale także czas poświęcony na przeprowadzanie testów jednostkowych, innych testów i innych procesów.
źródło
Sądzę, że wszystkie dotychczasowe odpowiedzi wskazywały na to, że duże projekty oprogramowania prawie zawsze dzielą się na znacznie mniejsze części. Każdy kawałek jest zwykle przechowywany we własnym pliku.
Te elementy są indywidualnie kompilowane w celu tworzenia obiektów. Obiekty są następnie łączone ze sobą, tworząc produkt końcowy. [W pewnym sensie przypomina to budowanie z Legos. Nie próbujesz uformować ostatecznej rzeczy z jednego dużego kawałka plastiku, zamiast tego łączysz kilka mniejszych kawałków.]
Podział projektu na osobne kompilacje pozwala na pewne fajne rzeczy.
Budynek przyrostowy
Po pierwsze, po zmianie jednego elementu zwykle nie trzeba ponownie kompilować wszystkich elementów. Ogólnie rzecz biorąc, dopóki nie zmienisz sposobu, w jaki inne elementy oddziałują z twoim kawałkiem, inne nie muszą być ponownie kompilowane.
Daje to początek pomysłowi przyrostowego budowania . Podczas wykonywania kompilacji przyrostowej rekompilowane są tylko te części, na które zmiana miała wpływ. To znacznie przyspiesza czas programowania. To prawda, że nadal możesz poczekać, aż wszystko zostanie ponownie połączone, ale wciąż jest to oszczędność w porównaniu z koniecznością ponownej kompilacji i ponownego połączenia. (BTW: Niektóre systemy / języki obsługują łączenie przyrostowe, więc tylko te rzeczy, które uległy zmianie, muszą zostać ponownie połączone. Kosztem tego jest zwykle słaba wydajność i rozmiar kodu.)
Testów jednostkowych
Drugą rzeczą, którą pozwalają ci małe kawałki, jest indywidualne testowanie kawałków przed ich połączeniem. Jest to znane jako testowanie jednostkowe . W testach jednostkowych każda jednostka jest indywidualnie testowana, zanim zostanie zintegrowana (połączona) z resztą systemu. Testy jednostkowe są zwykle pisane, aby można je było szybko uruchomić bez angażowania reszty systemu.
Ograniczający przypadek zastosowania testów jest widoczny w Test Driven Development (TDD). W tym modelu programistycznym żaden kod nie jest zapisywany / modyfikowany, chyba że ma on na celu naprawienie nieudanego testu.
Ułatwienie
Rozbijanie rzeczy wydaje się dobre, ale wydaje się również, że potrzeba dużo pracy, aby zbudować projekt: musisz dowiedzieć się, jakie elementy się zmieniły i co zależy od tych elementów, skompiluj każdy element, a następnie połącz wszystko ze sobą.
Na szczęście programiści są leniwi *, więc wymyślają wiele narzędzi, aby ułatwić sobie pracę. W tym celu napisano wiele narzędzi automatyzujących powyższe zadanie. Najsłynniejsze z nich zostały już wspomniane (marka, mrówka, maven). Narzędzia te pozwalają określić, jakie elementy należy złożyć, aby wykonać końcowy projekt, i jak elementy zależą od siebie (tj. Jeśli to zmienisz, należy to ponownie skompilować). Rezultat jest taki, że wydanie tylko jednego polecenia pozwala ustalić, co należy ponownie skompilować, skompilować i ponownie połączyć wszystko.
Ale to wciąż pozwala ustalić, jak rzeczy mają się do siebie. To dużo pracy i jak powiedziałem wcześniej, programiści są leniwi. Więc wymyślili inną klasę narzędzi. Te narzędzia zostały napisane w celu określenia zależności dla Ciebie! Często narzędzia te są częścią zintegrowanych środowisk programistycznych (IDE), takich jak Eclipse i Visual Studio, ale są też pewne samodzielne narzędzia używane zarówno do ogólnych, jak i specyficznych aplikacji (makedep, QMake dla programów Qt).
* W rzeczywistości programiści nie są zbyt leniwi, po prostu lubią spędzać czas na rozwiązywaniu problemów, nie wykonując powtarzalnych zadań, które mogą być zautomatyzowane przez program.
źródło
Oto moja lista rzeczy, które możesz spróbować przyspieszyć kompilacje C / C ++:
źródło
Wykonanie czegoś interpretowanego jest również bardzo nieefektywne i powolne oraz (prawdopodobnie) nieprawidłowe. Narzekasz na wymagania czasowe na komputerze programisty, ale brak kompilacji powoduje wymagania czasowe na komputerze użytkownika , co jest prawdopodobnie znacznie gorsze.
Co ważniejsze, nowoczesne systemy mogą przeprowadzać dość zaawansowane przyrostowe przebudowy i nie jest powszechne rekompilowanie całości w przypadku drobnych zmian - systemy kompilowane mogą zawierać komponenty skryptu, szczególnie wspólne dla takich rzeczy jak interfejs użytkownika.
źródło
Jeśli projekt implementuje poprawną zależność kompilacji DAG, można uniknąć rekompilacji tylko plików obiektowych, na które wpływa zmiana.
Zakładając również, że DAG jest zależny od kompilacji, możesz kompilować używając wielu procesów. Jedno zadanie na rdzeń / procesor jest normą.
Możesz utworzyć wiele plików wykonywalnych do testowania, które łączą tylko określone pliki obiektów.
źródło
Oprócz odpowiedzi MainMa właśnie zaktualizowaliśmy maszyny, na których pracujemy. Jednym z najlepszych zakupów, jakie zrobiliśmy, był dysk SSD, na który nie można pomóc, ale zrekompilować cały projekt.
Inną sugestią byłoby wypróbowanie innego kompilatora. Wcześniej przeszliśmy z kompilatora Javy na Jikes, a teraz przeszliśmy do korzystania z kompilatora dołączonego do Eclipse (nie wiem, czy ma nazwę), który lepiej wykorzystuje procesory wielordzeniowe.
Nasz projekt 37 000 plików skompilował się od zera przed wprowadzeniem tych zmian. Po zmianach został skrócony do 2-3 minut.
Oczywiście warto jeszcze raz wspomnieć o MainMa. Nie kompiluj całego projektu za każdym razem, gdy chcesz zobaczyć zmianę.
źródło