2012-11-17 9 views
14

Chcę użyć dyrektywy include tylko dla określonego celu. Nie chcę uruchamiać innych plików makefile, gdy cel nie jest potrzebny, ponieważ oznacza to, że pliki makefile są generowane niepotrzebnie.Sposób użycia dyrektywy include w pliku Makefile dla określonego celu

Czy istnieje sposób warunkowego zastosowania dyrektywy include, która jest zależna od celu? Lub w jakiś sposób uczynić dyrektywę włączenia jako warunek wstępny celu.

Oto co mam do tej pory:

# Flags 

INCDIR = $(CURDIR)/include 
CFLAGS = -Wall -Wno-overflow -Wno-uninitialized -pedantic -std=c99 -I$(INCDIR) -O3 
LFLAGS = -flat_namespace -dynamiclib -undefined dynamic_lookup 

# Directory names 

# Set vpath search paths 

vpath %.h include 
vpath %.c src 
vpath %.o build 
vpath %.d build 

# Get files for the core library 

CORE_FILES = $(wildcard src/*.c) 
CORE_OBJS = $(patsubst src/%.c, build/%.o, $(CORE_FILES)) 
CORE_DEPS = $(CORE_OBJS:.o=.d) 

# Core library target linking 

core : $(CORE_OBJS) | bin 
    $(CC) $(LFLAGS) -o bin/libcbitcoin.2.0.dylib $(CORE_OBJS) 

# Include header prerequisites (How to do only for "core" target?) 

include $(CORE_DEPS) 

# Makefiles for header dependencies. 

$(CORE_DEPS): build/%.d: src/%.c | build 
    rm -f [email protected]; \ 
    $(CC) -I$(INCDIR) -MM $< -MT '$(@:.d=.o) [email protected]' > [email protected] 

# Objects depend on directory 

$(CORE_OBS) : | build 

# Create build directory 

build: 
    mkdir build 

# Create bin directory 

bin: 
    mkdir bin 

# Core Compilation 

$(CORE_OBJS): build/%.o: src/%.c 
    $(CC) -c $(CFLAGS) $< -o [email protected] 

# Depencies require include/CBDependencies.h as a prerequisite 

build/CBOpenSSLCrypto.o: include/CBDependencies.h 

# Crypto library target linking 

crypto : build/CBOpenSSLCrypto.o -lcrypto -lssl | bin 
    $(CC) $(LFLAGS) -o bin/libcbitcoin-crypto.2.0.dylib build/CBOpenSSLCrypto.o -lcrypto -lssl 

# Crypto library compile 

build/CBOpenSSLCrypto.o: dependencies/crypto/CBOpenSSLCrypto.c 
    $(CC) -c $(CFLAGS) $< -o [email protected] 

#Clean 

clean: 
    rm -f $(CORE_OBJS) $(CORE_DEPS) build/CBOpenSSLCrypto.o 

Jak powinno być w stanie powiedzieć, że nie muszą zawierać pliki „.d” za «Crypto», ale robię dla «rdzenia» (domyślnie cel).

Dziękuję za pomoc.

+0

Ty * możesz * to zrobić, ale * nie powinieneś *. To idzie wbrew ziarnu Make i istnieją lepsze sposoby. Czy chcesz szybkie i proste podejście, czy zaawansowane i mocne? – Beta

+1

Następnie mogę zadać pytanie: czym jest "ziarno marki" i te "lepsze sposoby"? Tak długo, jak jest to łatwe do utrzymania. To jest to czego chcę. Nie chcę ręcznie dodawać wstępnych wymagań nagłówka. –

Odpowiedz

15

Make nie jest językiem proceduralnym, więc traktowanie go jako jednego idzie wbrew ziarnu; twoje pliki makefile będą trudne do skalowania i mogą prowadzić do subtelnych błędów.

Tam jest better way autorstwa Toma Tromeya, który jest czysty, wydajny i skalowalny. Sztuką jest uświadomienie sobie, że możesz zbudować plik zależności w tym samym kroku, co plik obiektu. Zależności po prostu powiedzmy Make, gdy obiekt ma zostać odbudowany; nie potrzebujesz ich przy pierwszym budowaniu obiektu, ponieważ Make wie, że obiekt musi zostać zbudowany. A jeśli zależności się zmieniają, może to być tylko dlatego, że zmieniło się coś w źródłowych lub starych zależnościach, więc ponownie Make wie, że obiekt musi zostać przebudowany. (To nie jest oczywiste, więc może upłynąć trochę cogitation.)

$(CORE_OBJS): build/%.o: src/%.c 
    $(CC) -c $(CFLAGS) $< -o [email protected] 
    $(CC) -MM -MF build/$*.d $< 

-include build/*.d 

Jest jeszcze jeden szkopuł: jeśli zmienić kod, tak aby usunąć zależność - a także usunąć ten plik - wygrałeś” t być w stanie odbudować, ponieważ stara lista zależności będzie nadal wymagać pliku, który nie będzie już można znaleźć. Wyrafinowany rozwiązaniem jest przetworzyć plik zależności, tak aby każdy warunek (np nagłówka) cel sam w sobie, bez żadnych poleceń, tak że można założyć zostać odbudowane, gdy są potrzebne:

$(CORE_OBJS): build/%.o: src/%.c 
    $(CC) -c $(CFLAGS) $< -o [email protected] 
    $(CC) -MM -MF build/$*.d $< 
    @cp build/$*.d build/$*.P 
    @sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ 
      -e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d; 
    @rm build/$*.P 

cruder metoda, ale niemal równie niezawodny, jest umieszczenie w catch-all zasad nagłówków i źródeł:

$(CORE_OBJS): build/%.o: src/%.c 
    $(CC) -c $(CFLAGS) $< -o [email protected] 
    $(CC) -MM -MF build/$*.d $< 

%.cc %.h: 

EDIT:

rozbić nowe komendy:

Opcja -MM mówi gcc o utworzeniu reguły make dla pliku obiektowego, zamiast wstępnego przetwarzania lub kompilowania. Domyślnie wysyłamy regułę do miejsca, w którym wysyłane jest przetworzone wyjście, które zwykle jest standardowe.

Opcja -MF, używana z -MM, określa plik wyjściowy. Tak więc -MM -MF build/$*.d ustawi regułę tam, gdzie chcemy.

Więc poniższe dwa polecenia są (prawie zawsze) równoważne:

$(CC) -MM -MF build/$*.d $< 

    $(CC) -MM $< > build/$*.d 

(mam opuszczone naprawdę -I$(...) oraz możliwość korzystania z opcji -MMD, ponieważ zarówno trochę skomplikowane i nie są punkt pytania.)

+0

OK, dziękuję za to. Musiałem zmienić '$ (CC) -MM -MF build/$ *. D $ <' na '$ (CC) -I $ (INCDIR) -MM -MF build/$ *. D $ < > kompilacja/$ * .d', aby go uruchomić, ale w moim systemie flaga MF nie jest obsługiwana. Co powinienem zrobić, aby zastąpić funkcjonalność MF? –

+0

@MatthewMitchell, prawie sam odpowiedziałeś na to pytanie, ale zmienię moją odpowiedź. – Beta

+0

Doskonale, dzięki za wyjaśnienie. –

3

Można użyć MAKECMDGOALS.

ifeq (core,$(MAKECMDGOALS)) 
include $(CORE_DEPS) 
endif 

Można by oczywiście użyć ifneq (,$(findstring core,$(MAKECMDGOALS))) czy istnieje możliwość więcej niż jednego celu.

Uwaga: to rozwiązanie "szybkie i brudne" - zgadzam się z wersją beta, że ​​nie powinno się tego robić powszechną praktyką (może to być kłopotliwe, jeśli zrobi się to w wielu plikach Makefile ...).

John

+0

Dzięki. Myślę, że to jedna z metod, ale alternatywna metoda Bety wydaje się być najbardziej idealna. Sądzę, że używanie automake byłoby jednym ze sposobów osiągnięcia podobnych celów. –

1

Nie mogę pomóc, łamiąc wytyczne, co jest dobrą odpowiedzią.

Moja odpowiedź na oryginalne pytanie jest, moim zdaniem, nie można objąć reguł, które są zależne od celu - wszystkie reguły są przetwarzane przed uwzględnieniem celów. To jest ograniczenie make (chyba). Z drugiej strony, jest dobry punkt MAKECMDGOALS, ale czy to nie jest tylko włamanie do samego narzędzia make?

Odpowiedź z Bety jest rozsądna i ortodoksyjna, ale nie można jej nazwać czystą, nawet jeśli jest najlepsza. Nie zadziała, jeśli make nie przetworzył wcześniej określonego celu, a odpowiedni plik zależności/* .d nie istnieje.

+2

Mylisz się. Podejście, które opisuję (którego nie wymyśliłem) działa doskonale, jeśli Make nie zbudował wcześniej celu, a odpowiedni plik '.d' nie istnieje. – Beta

Powiązane problemy