Jak zmusić makefile do odbudowania celu

184

Mam plik makefile, który buduje, a następnie wywołuje inny plik makefile. Ponieważ ten plik makefile wywołuje więcej plików makefile, które wykonują pracę, której tak naprawdę nie zmienia. Dlatego ciągle myśli, że projekt jest zbudowany i aktualny.

dnetdev11 ~ # make
make: `release' is up to date.

Jak zmusić plik makefile do odbudowania celu?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

Uwaga: Nazwy zostały usunięte, aby chronić niewinnych

Edycja: Wersja ostateczna naprawiona:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib
Lodle
źródło
Lodle, ponieważ jest to często zadawane pytanie, czy chcesz edytować pytanie, aby było bardziej nowoczesne? (Wygląda na to, że .PHONYnie był to twój jedyny problem, a tak naprawdę nie powinieneś edytować rozwiązania pytania, a przynajmniej już nie.)
Keith M

Odpowiedzi:

23

Możesz zadeklarować, że jeden lub więcej celów jest fałszywych .

Fałszywy cel to taki, który tak naprawdę nie jest nazwą pliku; jest to po prostu nazwa przepisu, który należy wykonać, gdy wydasz wyraźne żądanie. Są dwa powody, dla których warto użyć fałszywego celu: aby uniknąć konfliktu z plikiem o tej samej nazwie i poprawić wydajność.

...

Fałszywy cel nie powinien być warunkiem wstępnym prawdziwego pliku docelowego; jeśli tak, jego przepis będzie uruchamiany za każdym razem, gdy make przejdzie do aktualizacji tego pliku. Tak długo, jak fałszywy cel nigdy nie jest warunkiem wstępnym prawdziwego celu, przepis fałszywego celu będzie wykonywany tylko wtedy, gdy fałszywy cel jest określonym celem

Dave
źródło
68
Ta odpowiedź, mimo że jest „zaakceptowana” i bardzo „pozytywnie oceniona”, jest naprawdę nieprawdziwa. Po pierwsze, mówi „zadeklaruj, że cele są fałszywe”, a następnie mówi, że „fałszywy cel nie jest tak naprawdę nazwą pliku”. Cóż, jeśli twoim celem jest plik, jest to sprzeczność w odpowiedzi. Po drugie, mówi: „fałszywy cel nie powinien być warunkiem prawdziwego” - a co jeśli tak jest? Pierwotne pytanie nie określało, czy jest, czy nie. Poprawną odpowiedzią jest, nie zadeklarować swoje cele, aby być fałszywe, ale raczej zadeklarować dodatkowy cel fałszywy, a potem, zależy cele, które mają być odbudowane w tej sprawie.
Mark Galeck
2
@MarkGaleck. Kiedy odpowiedź stwierdza, że ​​„Fałszywy cel to taki, który tak naprawdę nie jest nazwą pliku”, cytuje bezpośrednio z gcc make manual. To jest całkowicie poprawne.
drlolly
„Cel” to termin Make, który odnosi się do tekstu po lewej stronie dwukropka :, a nie tylko wyniku końcowego, który chcesz utworzyć (np. Pliku binarnego). W pytaniu release, debug, clean, i installsą celem wykonania, nie xxx_utillub xxxcore.soczy cokolwiek innego.
Keith M
728

-BPrzełącznik do marki, którego forma jest długa --always-make, mówi makedo znaczników czasu lekceważenie i wprowadzić określone cele. Może to pokonać cel użycia make, ale może być tym, czego potrzebujesz.

sykora
źródło
4
@MarkKCowan Całkowicie się zgadzam! Ta opcja jest dokładnie tym, czego szukałem, a nie jakimś obejściem, jak sugeruje Dave.
Maarten Bamelis
8
Zastrzeżeniem tego podejścia jest to, że po prostu buduje zbyt wiele rzeczy. W szczególności w przypadku autotools widziałem, że konfiguracja jest uruchamiana ponownie. Chciałbym zbudować rozwiązanie oparte na LD_PRELOAD !!
vrdhn
tak, a nawet może przepisać pliki, których nie chciałeś! takie jak globalne biblioteki systemowe, które pojawiają się w zależnościach i zostają odbudowane i nadpisane ...
Julio Guerra,
18

Jedną sztuczką, która kiedyś była udokumentowana w podręczniku firmy Sun, makejest użycie (nieistniejącego) celu „.FORCE”. Możesz to zrobić, tworząc plik force.mk, który zawiera:

.FORCE:
$(FORCE_DEPS): .FORCE

Następnie, zakładając, że Twój makefile zostanie wywołany makefile, możesz uruchomić:

make FORCE_DEPS=release -f force.mk -f makefile release

Ponieważ .FORCEnie istnieje, wszystko, co od niego zależy, będzie nieaktualne i odbudowane.

Wszystko to będzie działać z dowolną wersją make; w Linuksie masz GNU Make i dlatego możesz używać celu .PHONY, jak omówiono.

Warto również zastanowić się, dlaczego makeuważa wydanie za aktualne. Może to być spowodowane tym, że touch releasewśród poleceń wykonano polecenie; może tak być, ponieważ istnieje plik lub katalog o nazwie „release”, który istnieje i nie ma żadnych zależności, a więc jest aktualny. Jest faktyczny powód ...

Jonathan Leffler
źródło
14

Ktoś inny zasugerował .PHONY, co jest zdecydowanie poprawne. .PHONY należy stosować dla każdej reguły, dla której porównanie daty między danymi wejściowymi i wyjściowymi jest nieprawidłowe. Ponieważ nie masz żadnych celów formularzaoutput: input , powinieneś użyć .PHONY dla WSZYSTKICH z nich!

To powiedziawszy, prawdopodobnie powinieneś zdefiniować niektóre zmienne u góry pliku makefile dla różnych nazw plików i zdefiniować reguły rzeczywistej marki, które mają sekcje wejściową i wyjściową, abyś mógł korzystać z zalet make, a mianowicie, że będziesz kompilować tylko rzeczy, które są niezbędne do skopiowania!

Edycja: dodano przykład. Niesprawdzone, ale tak właśnie robisz .PHONY

.PHONY: clean    
clean:
    $(clean)
sztaluga
źródło
1
Cóż, gdybyś mógł mi pokazać przykład, byłoby miło. Atm, po prostu włamuję się, próbując sprawić, żeby tama zadziałała: P
Lodle
1
Lokalizacja .PHONYcelu nie ma znaczenia. Może być w dowolnym miejscu w Makefile.
Adrian W
5

Jeśli dobrze pamiętam, „make” używa znaczników czasu (czas modyfikacji pliku), aby ustalić, czy cel jest aktualny. Częstym sposobem wymuszenia przebudowy jest aktualizacja znacznika czasu za pomocą polecenia „touch”. Możesz spróbować wywołać „dotyk” w swoim pliku makefile, aby zaktualizować znacznik czasu jednego z celów (być może jednego z tych plików pod-makefile), co może zmusić Make do wykonania tego polecenia.

poundifdef
źródło
5

Ta prosta technika pozwoli normalnie funkcjonować plikowi makefile, gdy wymuszanie nie jest pożądane. Utwórz nowy cel o nazwie force na końcu swojego makefile . Siła cel dotknie plik domyślny cel zależy. W poniższym przykładzie dodałem touch myprogram.cpp . Dodałem również rekurencyjne połączenie do wykonania . Spowoduje to, że domyślny cel zostanie wykonany za każdym razem, gdy wpiszesz make force .

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make
groko
źródło
Nigdy nie powinieneś używać makewewnątrz pliku Makefile. Użyj $(MAKE)zamiast tego.
Benjamin Crawford Ctrl-Alt-Tut
3

Próbowałem tego i zadziałało to dla mnie

dodaj te linie do Makefile

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

zapisz i teraz zadzwoń

make new 

i wszystko ponownie skompiluje

Co się stało?

1) „nowe” połączenia czyste. „clean” do „rm”, który usuwa wszystkie pliki obiektowe, które mają rozszerzenie „.o”.

2) „nowe” połączenia „wykonaj”. „spraw, aby” zobaczył, że nie ma plików „.o”, więc ponownie utworzy wszystkie „.o”. następnie linker łączy wszystkie pliki .o w jednym pliku wykonywalnym

Powodzenia

hamaney
źródło
1
W przepisie na newlepsze wykorzystanie $(MAKE)niżmake
Basile Starynkevitch
1

Zgodnie z Recursive Millera Uważaj za szkodliwe , powinieneś unikać dzwonienia $(MAKE)! W przypadku, gdy pokazujesz, jest to nieszkodliwe, ponieważ tak naprawdę nie jest to plik makefile, a jedynie skrypt opakowania, który równie dobrze mógłby zostać napisany w Shell. Ale mówisz, że kontynuujesz to na głębszych poziomach rekurencji, więc prawdopodobnie napotkałeś problemy pokazane w tym eseju otwierającym oczy.

Oczywiście dzięki GNU unikanie tego jest kłopotliwe. I chociaż zdają sobie sprawę z tego problemu, jest to ich udokumentowany sposób działania.

OTOH, makepp został stworzony jako rozwiązanie tego problemu. Możesz napisać swoje pliki makefile na poziomie katalogu, ale wszystkie zostaną połączone w pełny widok twojego projektu.

Ale starsze pliki makefile są zapisywane rekurencyjnie. Jest więc obejście, w którym $(MAKE)nic nie kieruje, ale kieruje żądania z powrotem do głównego procesu makepp. Tylko jeśli robisz zbędne lub, co gorsza, sprzeczne rzeczy między swoimi zgłoszeniami, musisz poprosić --traditional-recursive-make(co oczywiście łamie tę zaletę makepp). Nie znam twoich innych plików makefile, ale jeśli są one napisane czysto, przy pomocy makepp niezbędne przebudowy powinny nastąpić automatycznie, bez potrzeby sugerowania tutaj innych hacków.

Daniel
źródło
Nie odpowiedziałem na pytanie: styczne do punktu głównego i powinien być komentarzem, a nie odpowiedzią.
flungo
Może nie byłem wystarczająco jasny. Z makepp ten cały plik makefile opakowania nie jest potrzebny. Znając dokładne zależności (wszystkie, nie tylko to, co wymieniono po :), zawsze będzie się odbudowywać w razie potrzeby.
Daniel
1

Jeśli nie musisz zachowywać żadnych wyników, które udało się skompilować

nmake /A 

odbudowuje wszystko

CZahrobsky
źródło
0

To zależy od celu. Jeśli jest to fałszywy cel (tj. Cel NIE jest powiązany z plikiem), powinieneś zadeklarować go jako .PHONY.

Jeśli jednak cel nie jest fałszywym celem, ale z jakiegoś powodu chcesz go odbudować (na przykład, gdy używasz makra wstępnego przetwarzania __TIME__), powinieneś użyć schematu FORCE opisanego w odpowiedziach tutaj.

Kostas
źródło
0

Zostało już wspomniane, ale pomyślałem, że mogę dodać do korzystania touch

Jeśli touchwszystkie pliki źródłowe, które mają zostać skompilowane, touchpolecenie zmieni znaczniki czasu pliku na czas systemowy, w którym touchpolecenie zostało wykonane.

Sygnatura czasowa pliku źródłowego jest makeużywana do „poznania” pliku, który się zmienił i należy go ponownie skompilować

Na przykład: Jeśli projekt był projektem c ++, to zrób to touch *.cpp, a następnie uruchom makeponownie, a make powinno skompilować cały projekt.

mrflash818
źródło
0

Jak wskazał abernier, istnieje zalecane rozwiązanie w podręczniku GNU make manual, który wykorzystuje „fałszywy” cel do wymuszenia odbudowania celu:

clean: FORCE
        rm $(objects)
FORCE: ; 

Będzie działać czysto, niezależnie od innych zależności.

Dodałem średnik do roztworu z instrukcji, w przeciwnym razie wymagana jest pusta linia.

tdietel
źródło
-1

W moim systemie Linux (Centos 6.2) istnieje znacząca różnica między deklarowaniem celu .PHONY a tworzeniem fałszywej zależności od FORCE, kiedy reguła faktycznie tworzy plik pasujący do celu. Gdy plik musi być generowany za każdym razem, wymagał zarówno Fałszywej zależności FORCE na pliku, jak i .PHONY dla fałszywej zależności.

źle:

date > $@

dobrze:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE
Wujek
źródło
-1

make clean usuwa wszystkie już skompilowane pliki obiektowe.

Hanan Shteingart
źródło