2012-12-13 12 views
10

Oto zmniejszona wersja mojego Makefile:Makefile zależności nie działają na fałszywych cel

.PHONY: all 

all: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

chcę uruchomić make i tylko to przekompilować gdy src/server.coffee uległ zmianie. Jednak za każdym razem, to recompiles biegnę make:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 

Jeśli zmienię mojego Makefile nie używać fałszywych cel, to działa zgodnie z oczekiwaniami. Nowy Makefile:

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Wynik:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
make: `bin/server.js' is up to date. 

Dlaczego nie będzie respektować moje współzależności z fałszywych cel? Powodem, dla którego pytam, jest fakt, że w rzeczywistości nie będę tylko kompilował jednego pliku w jednym pliku, więc nie chcę śledzić nazw wszystkich plików wyjściowych, które będą używane jako cele.

Odpowiedz

8

Zamiast fałszywych cel (który jako @cmotley zaznacza, działa dokładnie tak jak powinien), co można wykorzystać, gdy chcesz uniknąć dodatkowej pracy jest "empty target":

Pusty celem jest wariant fałszywego celu; służy do przechowywania receptur dla akcji, o które prosisz od czasu do czasu. W przeciwieństwie do fałszywego celu, ten plik docelowy może naprawdę istnieć; ale zawartość pliku nie ma znaczenia i zwykle jest pusta.

Celem pustego pliku docelowego jest zapisanie, z czasem ostatniej modyfikacji, ostatniego przepisu reguły. Dzieje się tak, ponieważ jednym z poleceń w recepturze jest polecenie dotykowe, które aktualizuje plik docelowy.

Jednak, w tym przypadku istnieje naprawdę nie ma potrzeby, aby dodać dodatkowy plik pusty wyjściowy - masz już wyjścia kompilacji coffeescript! To pasuje do bardziej typowego wzorca Makefile, jak już zademonstrowałeś w swoim pytaniu. Co można zrobić, to Refactor tego podejścia:

.PHONY: all 
all: bin/server.js 

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Teraz masz dwie rzeczy: ładny konwencjonalne „wszystko” target że jest prawidłowo fałszywe, ale nie zrobi dodatkowej pracy. Jesteś w lepszej pozycji, aby to bardziej ogólne, dzięki czemu można łatwo dodać więcej plików:

.PHONY: all 
all: bin/server.js bin/other1.js bin/other2.js 

bin/%.js: src/%.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin $< 
+3

Po prostu, aby być czystym, ** pusty cel ** musi być plikiem i jest naprawdę używany tylko dla jego znacznika czasu? Czy istnieje inny rodzaj '.PHONY', który pozwala, aby reguła docelowa miała treść receptury (z wykonanymi poleceniami) * i * działają tylko wtedy, gdy zależności wymagają aktualizacji? Wygląda na to, że '.PHONY' robi różne rzeczy, w zależności od tego, czy ma ciało receptury, czy nie. – jozxyqk

4

Potrzebny jest plik docelowy do porównania w stosunku do czasu modyfikacji pliku server.coffee. Ponieważ nie masz konkretnego celu, make nie może wiedzieć, czy dane wyjściowe są nowsze, czy nie, więc zawsze będzie budować all.

+0

Ah, dzięki. Nie zdawałem sobie sprawy, w jaki sposób należy obliczyć, które pliki należy zrekompilować. Bardzo pomocna –

9

Zgodnie z dokumentacją Marka:

The prerequisites of the special target .PHONY are considered 
to be phony targets. When it is time to consider such a target, 
make will run its recipe unconditionally, regardless of whether 
a file with that name exists or what its last-modification time is. 

http://www.gnu.org/software/make/manual/html_node/Special-Targets.html

Producent prowadzi przepis fałszywych celów bezwarunkowo - przesłanki nie mają znaczenia.

+0

OK, to całkiem proste. Czy znasz jakieś dobre obejście, aby osiągnąć cel polegający na tym, że nie musisz jawnie deklarować plików wyjściowych, które zależą od zestawu plików źródłowych? –

+0

Można zadeklarować niektóre zmienne do śledzenia plików źródłowych i plików obiektów. Na przykład SRC = $ (wildcard ./src/*.c) i OBJECTS = $ (patsubst% .c,% .o, $ (SRC)). Wtedy $ (OBJECTS) może być warunkiem wstępnym dla twojego celu. Myślę, że właśnie to próbujesz zrobić. – cmotley

1

Jak inni wspomniano, należy patrzy na znaczniki czasu plików, aby dowiedzieć się, czy zależności uległy zmianie.

Jeśli chcesz "emulować" fałszywy cel za pomocą zależności, będziesz musiał utworzyć prawdziwy plik o tej nazwie i użyć polecenia touch (w systemach uniksowych).

Potrzebowałem rozwiązania do czyszczenia katalogu tylko wtedy, gdy pliki Makefile zostały zmienione (tj. Zmieniono flagi kompilatora, więc pliki obiektów musiały zostać ponownie skompilowane).

Oto, co kiedyś (i biegnie przed każdym kompilacji) z pliku o nazwie makefile_clean:

makefile_clean: makefile 
    @rm '*.o' 
    @sudo touch makefile_clean 

Komenda touch aktualizuje ostatniej modyfikacji znacznika czasu do chwili obecnej.