2009-02-03 14 views
46

Piszę plik Makefile z wieloma powtarzającymi się materiałami, np.Funkcje w Makefile

debug_ifort_Linux: 
     if [ $(UNAME) = Linux ]; then       \ 
      $(MAKE) FC=ifort FFLAGS=$(difort) PETSC_FFLAGS="..." \ 
        [email protected] LEXT="ifort_$(UNAME)" -e syst;  \ 
     else             \ 
      echo $(err_arch);          \ 
      exit 1;            \ 
     fi 

gdzie docelowego Syst 'jest określona, ​​zmienna „nazwa_uż” jest zdefiniowane (i zwykle jest Linux, ale może również Cygwinem lub OSF1) a zmienne „difort” i „err_arch” są zdefiniowane . Ten blok kodu jest używany bardzo wiele razy dla różnych celów kompilatora (przy użyciu konwencji nazw ''). Ponieważ jest to ogromna ilość zbędnego kodu, chciałbym móc go napisać w prostszy sposób. Np. Chciałbym zrobić coś takiego:

debug_ifort_Linux: 
     compile(uname,compiler,flags,petsc_flags,target,lext) 

gdzie kompilacja może być funkcją wykonującą powyższy kod na podstawie argumentów. Czy ktoś ma pojęcie, jak to osiągnąć?

Odpowiedz

35

Istnieją 3 Pojęcia pokrewne:

  1. call function
  2. multi-line variables
  3. conditionals

refactored wynik mógłby wyglądać następująco:

ifeq ($(UNAME),Linux) 
    compile = $(MAKE) FC=$(1) FFLAGS=$(2) PETSC_FFLAGS=$(3) \ 
         [email protected] LEXT="$(1)_$(UNAME)" -e syst 
else 
    define compile = 
     echo $(err_arch) 
     exit 1 
    endef 
endif 


debug_ifort: 
     $(call compile,ifort,$(difort),"...") 

Pozostawiona linia \ to kontynuacja linii $(MAKE) dla powłoki. Nie jest wymagana zmienna wielowierszowa, ponieważ jest to tylko jedna linia kodu powłoki. Zmienne wielowierszowe są używane tylko w bloku else.

Jeśli nie potrzebują parametrów można użyć: = zadanie i po prostu rozwinąć metodę z $(compile) (patrz canned recipes)

[Edytuj]Uwaga: Korzystanie zrobić przed wersją 3.82, az = nie został rozpoznany na końcu definicji dla mnie. Naprawiłem to, używając zamiast tego define compile.

+0

Dlaczego ta opcja jest lepsza niż poprzednia odpowiedź, która jest obecnie oznaczona jako poprawna? –

+1

Powinieneś używać zmiennych wielowierszowych zamiast \. Który znowu byłby "za dużo, żeby po prostu edytować tę odpowiedź" (o ile dotychczas otrzymałem recenzje). – JonnyJD

+0

Wyjaśnienie zmiennych wielowierszowych jest trochę za duże na komentarz. Ale oczywiście nie musisz się zgadzać. – JonnyJD

36

Szukasz call function.

compile =             \ 
     if [ $(UNAME) = $(1) ]; then      \ 
      $(MAKE) FC=$(2) FFLAGS=$(3) PETSC_FFLAGS="..." \ 
        [email protected] LEXT="$(4)_$(UNAME)" -e syst; \ 
     else            \ 
      echo $(err_arch);        \ 
      exit 1;           \ 
     fi 

debug_ifort_Linux: 
     $(call compile,Linux,ifort,$(difort),ifort) 

Jeśli można zrestrukturyzować swoją Makefile trochę, choć, należy sprawdzić, czy można użyć make „s conditionals zamiast sh” s.

+1

Dzięki, to zadziałało! :) Nie widzę bezpośrednio, w jaki sposób mogę korzystać z warunkowości make, aby zrobić to samo, co chcę. Przynajmniej nie bez jałowej restrukturyzacji. Oczywiście może to być spowodowane tym, że nie mam dużego doświadczenia z pisaniem Makefiles ... –

+0

Jest to doskonały przykład, w którym powinieneś użyć [zmiennych wieloliniowych] (http://www.gnu.org/software/make /manual/html_node/Multi_002dLine.html). – JonnyJD