2011-02-24 10 views
14

W stosunkowo dużych projektach, które używają zwykłego starego make, nawet budowanie projektu, gdy nic się nie zmieniło, zajmuje kilka dziesiątek sekund. Zwłaszcza z wieloma wykonaniami make -C, które mają nowy narzut procesu.Czy istnieje narzędzie do kompilacji oparte na mechanizmie inotify?

Oczywistym rozwiązaniem tego problemu jest narzędzie do budowania oparte na funkcji podobnej do systemu operacyjnego w wersji inotify. Wyszuka, kiedy dany plik zostanie zmieniony i na podstawie tej listy skompiluje ten plik sam.

Czy istnieje taka maszyna? Punkty premiowe za projekty open source.

Odpowiedz

14

To znaczy, jak Tup:

Od strony głównej:

„Tup jest system budowania oparty na plikach - to wprowadza listę zmian w plikach i skierowany graf acykliczny (DAG), następnie przetwarza DAG, aby wykonać odpowiednie polecenia wymagane do aktualizacji plików zależnych DAG jest przechowywany w bazie danych SQLite Domyślnie lista zmian plików jest generowana przez skanowanie systemu plików.Alternatywnie, lista może być dostarczona z góry, uruchamiając dołączone demon monitora plików. "

+0

Właściwie to słyszałem o tym, ale nie wyszło mi to na myśl. –

+0

Zastanawiam się, co się dzieje, gdy edytujesz plik i zapisujesz jego niekompletne wersje. Musi być tak, że każde zapisanie wyzwala "Tup", aby go skompilować, prawda? –

+0

Tup kompiluje się tylko, gdy pytasz, ale zawsze obserwuje system plików w poszukiwaniu zmian. –

0

Opisana zależność od zmiany jest już częścią Make, ale Make jest na tyle elastyczna, że ​​można jej używać w sposób nieefektywny. Jeśli powolne spowolnienie jest spowodowane poleceniami rekursji (make -C) - co prawdopodobnie jest - powinieneś zmniejszyć rekursję. (Można spróbować umieścić w swojej własnej logiki warunkowej, aby zdecydować, czy wykonać make -C, ale byłoby to bardzo nieeleganckie rozwiązanie).

Z grubsza rzecz biorąc, jeśli makefile wygląda to

# main makefile 

foo: 
    make -C bar baz 

i tym

# makefile in bar/ 

baz: quartz 
    do something 

można zmienić je w ten sposób:

# main makefile 

foo: bar/quartz 
    cd bar && do something 

Istnieje wiele szczegółowych informacji, ale teraz, jeśli bar/quartz nie została zmieniona, reguła foo nie zostanie uruchomiona.

+0

To jest kompromis. Idąc z podejściem daje mi ogromny nadęty plik Makefile, który jest szybszy. Chcę zjeść moje ciasto i je też. I jest to możliwe dzięki magii inotify. Nigdy nie dotykaj żadnego pliku, który nie został zmodyfikowany, nawet w dniu modyfikacji. –

1

Zainstaluj inotify-tools i napisz kilka linii bash, aby wywołać make, gdy niektóre katalogi są aktualizowane.

Na marginesie, rekurencyjne powodują poważne błędy i są podatne na błędy. Preferuj non-recursive make.

+0

Huh? Wywołanie powoduje dotknięcie każdego pliku w projekcie. Nie chcę tego robić! Cała sprawa, aby nigdy nie dotykać wszystkich plików, nawet w celu uzyskania czasu modyfikacji. –

+0

@Elazar Leibovich: make nie dotyka żadnych plików. To pliki źródłowe stat, aby sprawdzić, czy cel musi zostać odbudowany. –

+0

Maxim, nie wiem co z tobą, ale uważam, że 'stat'ing pliku, dotykając go. A jeśli potrzebujesz statystyki 100 000 plików za każdym razem, gdy robisz jedną markę, może to trochę potrwać (99,9% z tych plików nie jest dla ciebie interesujących, już skompilowałeś je do libsomething.so, i to wszystko czego potrzebujesz). –

4

Zastanawiam się tylko, czy jest to stat() ing plików, które trwa tak długo. Aby to sprawdzić tutaj jest mały systemtap skrypt pisałem zmierzyć czas potrzebny do stat() plików:

# call-counts.stp 

global calls, times 

probe kernel.function(@1) { 
    times[probefunc()] = gettimeofday_ns() 
} 

probe kernel.function(@1).return { 
    now = gettimeofday_ns() 
    delta = now - times[probefunc()] 
    calls[probefunc()] <<< delta 
} 

a następnie używać go tak:

$ stap -c "make -rC ~/src/prj -j8 -k" ~/tmp/count-calls.stp sys_newstat 
make: Entering directory `/home/user/src/prj' 
make: Nothing to be done for `all'. 
make: Leaving directory `/home/user/src/prj' 
calls["sys_newstat"] @count=8318 @min=684 @max=910667 @sum=26952500 @avg=3240 

Projekt Pobiegłem go na ma 4593 pliki źródłowe i trwa ~ 27msec (26952500nsec powyżej), aby dokonać statowania wszystkich plików wraz z odpowiednimi plikami .d. Korzystam jednak z nierekurencyjnej marki.

+0

Możecie być poprawne, a to może być przedwczesna optymalizacja . BTW był gorący cache? Interesujące jest spojrzenie na projekt z 100 000 i sprawdzenie, czy czasy statystyki są większe. Zwróć uwagę, że tworzenie nierekursywne nie jest często opcją dla naprawdę dużych projektów. +1 za poświęcenie czasu na profil. –

+0

Pamięć podręczna systemu plików była gorąca (stacja robocza, którą skompilowałem ma 12 GB pamięci RAM). I to na lokalnym systemie plików ext3. Przy budowaniu na NFS trwa to o kilka rzędów wielkości w przypadku plików 'stat()'. –

+0

autor 'tup', mierzy kilka sekund na zrobienie niezmienionego projektu z plikami 100k http://gittup.org/tup/make_vs_tup.html –

2

Jeśli używasz OSX, można użyć fswatch

https://github.com/alandipert/fswatch

Oto jak korzystać fswatch do zmian do pliku, a następnie uruchomić zrobić, jeśli wykryje żadnego

fswatch -o anyFile | xargs -n1 -I{} make 

Możesz uruchomić fswatch z pliku Makefile tak:

watch: $(FILE) 
    fswatch -o $^ | xargs -n1 -I{} make 

(Oczywiście, $ (FILE) jest zdefiniowana wewnątrz makefile.) make mogą teraz obserwować zmiany w pliku jak ten:

> make watch 

można oglądać inny plik tak:

> make watch anotherFile 
Powiązane problemy