2009-02-26 16 views
11

Mam nieco hackish makefile do uruchamiania testów:Dlaczego GNU make usunąć plik

### Run the tests 

tests := tests/test1 tests/test2 ... 

test: $(tests) 

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 
    [email protected] 

to działa, ale to sprawia, że ​​Marka zrobić coś, czego nigdy nie widziałem to zrobić wcześniej. Mój test jest obecnie uszkodzony i powoduje błąd magistrali. Make podaje następujące dane wyjściowe:

gcc -o tests/test1 [flags blah blah] tests/test1.c 
tests/test1 
make: *** [tests/test1] Bus error 
make: *** Deleting file `tests/test1' 

Jestem ciekawa ostatniej linii. Nigdy wcześniej nie widziałem, żeby to robił. Dlaczego Make usunąć skompilowany test?

Uwaga: Bardzo mocno zredagowałem ten przykład, aby było prostsze. Mogłem wprowadzić pewne błędy.

Odpowiedz

14

Ponieważ cel mógł nie zostać poprawnie zbudowany. Następnym razem, gdy wykonasz projekt, spróbujesz odbudować cel. Jeśli plik nie został usunięty, nie ma możliwości stwierdzenia, że ​​coś poszło nie tak. make nie może wiedzieć, że błąd pochodzi z testu, a nie z procesu, który buduje cel.


To, czy takie zachowanie jest pożądane w twoim przypadku, zależy od charakteru testów. Jeśli planujesz naprawienie testu, aby nie powodowało to błędu, usunięcie celu nie jest wielkim problemem. Jeśli chcesz później użyć narzędzia do debugowania, musisz wprowadzić zmiany w swoim procesie tworzenia.

Jednym ze sposobów, aby nie usuwać celów, jest użycie celu .PRECIOUS.


Innym przykładem może być:

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 
    [email protected] 

nie testowano, ale documentation wskazuje cel nie zostaną usunięte:

Kiedy błąd zdarza się, że makijaż nie zostało mu ignorować oznacza to, że aktualny cel nie może zostać poprawnie przetworzony, podobnie jak żaden inny, od którego zależy bezpośrednio lub pośrednio. Żadne dalsze polecenia nie zostaną wykonane dla tych celów, ponieważ ich warunki wstępne nie zostały osiągnięte.

oraz:

Zwykle, gdy komenda nie powiedzie się, jeśli został zmieniony plik docelowy w ogóle, że plik jest uszkodzony i nie może być używany, a przynajmniej nie jest całkowicie zaktualizowany. Jednak sygnatura czasowa pliku mówi, że jest teraz aktualna, więc przy następnym uruchomieniu nie będzie próbowała aktualizować tego pliku. Sytuacja jest taka sama, jak wtedy, gdy polecenie jest zabijane przez sygnał; patrz Przerwania. Zasadniczo więc właściwym rozwiązaniem jest usunięcie pliku docelowego, jeśli polecenie nie powiedzie się po rozpoczęciu zmiany pliku. make zrobi to, jeśli .DELETE_ON_ERROR pojawi się jako cel. Jest to prawie zawsze to, co chcesz zrobić, ale nie jest to praktyka historyczna; więc ze względu na zgodność musisz wyraźnie o to poprosić.

11

Jednym ze sposobów uniknięcia tego problemu jest podział kompilacji i wykonanie testu w dwóch etapach:

tests := tests/test1 tests/test2 ... 

test: $(tests) runtests 

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 

runtests: %.out: % 
    $< | tee [email protected] 

(tam prawdopodobnie błędy w moim make składni, nikt nie krępuj się go poprawić.) Ogólną zasadą jest, aby przebieg testowy generował plik wyjściowy, co ułatwia make uruchamianie każdego testu indywidualnie.

+1

+1 za jedyną odpowiedź, która wskazywała, że ​​zachowanie było spowodowane przez plik Makefile, który łączył generowanie programu testowego i uruchamianie go w pojedynczej regule. –

+0

IMO to lepsze rozwiązanie: czystsze i bardziej "przypominające". Chociaż szczegóły mogą być obsługiwane bardziej czyściej. Najpierw autor pliku Makefile musi zdecydować: czy chcesz _always_ uruchamiać testy, czy uruchamiać testy tylko wtedy, gdy plik testowy został przebudowany (ten drugi jest tym, co zrobił oryginalny przykład). – MadScientist

6

Jest to domyślne zachowanie marki make. Gdy polecenie zwraca kod błędu (np. Niezerowy powrót), cel wykonania zostanie usunięty. Dyrektywy makefile .PRECIOUS i .IGNORE mogą zmienić to zachowanie.

Powiązane problemy