2017-08-31 59 views
5

Chcę dodać cel Make, który uruchamia program z envdir.

ENVDIR := $(shell command -v envdir) 

serve: | $(ENVDIR) 
    $(ENVDIR) /usr/local/myservice/env python -m SimpleHTTPServer 8000 

Chodzi o to, że jeśli użytkownik nie ma zainstalowanego envdir, zainstaluje je dla nich. Potrzebuję charakteru fajki, ponieważ nie zawsze chcę, żeby to działało; Chcę tylko, żeby była jakakolwiek jego wersja. Niestety, nie mogę przewidzieć, gdzie będzie zainstalowany envdir.

UNAME := $(shell uname) 
$(ENVDIR): 
ifeq ($(UNAME), Darwin) 
    brew install daemontools 
endif 
ifeq ($(UNAME), Linux) 
    sudo apt-get install daemontools 
endif 
# Add other operating systems here as appropriate... 

Innym problemem, który napotykam, jest to, że jeśli użytkownik nie ma zainstalowanego envdir, zmienna ocenia pusty ciąg. Tak więc a) Mój cel "install envdir" faktycznie nie działa, a b) po uruchomieniu, $ (ENVDIR) nadal jest ustawiony na pusty ciąg, więc załadowanie go w celu wyświetlania nie działa.

Czy istnieje sposób, aby: a) uzyskać docelowy poziom instalacji do uruchomienia, nawet jeśli ENVDIR jest niezdefiniowany, oraz b) przedefiniować wartość zmiennej na końcu uruchomienia celu "install envdir"?

Proszę nie odpowiadać słowami "dlaczego używacie envdir" - napotykam ten problem z wieloma różnymi plikami binarnymi, na których polegam, tak się złożyło, że był to łatwy do udostępnienia przykład.

+0

Dlaczego nie używasz warunku, aby odróżnić przypadki, w których 'envdir' jest już zainstalowany i przypadki, w których nie jest? 'ifeq ($ (ENVDIR),) ... else ... endif' mógłby prawdopodobnie to zrobić. I na końcu receptury instalacyjnej 'envdir' możesz po prostu ponownie wywołać make zamiast próbować zmienić wartość zmiennej' ENVDIR' (wiem, * rekursywna marka jest zła *, ale złe rzeczy są czasami bardzo przydatne). –

Odpowiedz

0

Dla „pustym” problemu można to zrobić:

ENVDIR := $(or $(shell command -v envdir),envdir) 

tak, że jeśli funkcja shell rozwija do pustego ciągu, envdir zostaną podstawione (funkcja or dodano w GNU make 3.81). To prawdopodobnie wystarczy, aby rozwiązać wszystkie twoje problemy, ponieważ po instalacji pojawi się teraz polecenie PATH, więc nie potrzebujesz pełnej ścieżki.

1

Można zrobić to całkowicie w powłoce jako tak:

ENVDIR := $(command -v envdir 2> /dev/null || (install envdir > /dev/null && echo newEnvDirPath)) 

Jest to najprostszy, ale powoduje envdir być zainstalowane, nawet jeśli nie jest to konieczne dla bieżącego cel. Jeśli chcesz go w celu, można to zrobić coś takiego:

ENVDIR:=$(cat .ENVDIR 2> /dev/null) 
$(type -v $(ENVDIR) > /dev/null || rm .ENVDIR) 

.ENVDIR: 
    command -v envdir 2> /dev/null > [email protected] || (install envdir > /dev/null && echo newEnvDirPath > [email protected]) 
    $(eval ENVDIR:=$$(cat [email protected])) 

shell: | .ENVDIR 

Jeśli plik .ENVDIR nie istnieje, to będzie działać przepis, który będzie albo napisać zainstalowaną ścieżkę .ENVDIR, czy będzie go zainstalować i napisz nową ścieżkę do .ENVDIR. Tak czy inaczej, po zakończeniu linii receptury, .ENVDIR będzie zawierać ścieżkę wykonywalną. Cel następnie uruchamia $(eval), aby ustawić ENVDIR. Zauważ, że wywołanie eval powoduje, że plik Makefile ma zostać naprawiony, co nie jest idealne, ale powinno nastąpić tylko raz w systemie. (Zwróć też uwagę, że przed komendą cat znajduje się podwójne $$, co uniemożliwia rozszerzeniu go w trakcie odczytu ...).

Ewentualnie, jeśli istnieje .ENVDIR, to odczyta plik, aby określić, którego z nich użyć. Sprawdzanie odbywa się w następnym wierszu, aby upewnić się, że ta wersja nadal istnieje w systemie, a jeśli nie, usuwa plik, zmuszając go do odtworzenia.