2009-02-03 30 views
46

Estoy escribiendo un Makefile con muchas cosas repetitivas, p.Funciones en 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 

donde se define el destino 'Syst', la variable 'UNAME' se define (y es generalmente de Linux, pero podría también por Cygwin o OSF1) y las variables 'difort' y 'err_arch' también se definen . Este bloque de código se usa muchas veces para diferentes objetivos de compilación (usando una convención de nombre de ''). Como se trata de una gran cantidad de código redundante, me gustaría poder escribirlo de una manera más simple. Por ejemplo, me gustaría hacer algo como esto:

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

donde compilación podría ser una función que hace el código anterior en base a los argumentos. ¿Alguien tiene alguna idea de cómo podría lograr esto?

Respuesta

35

Hay 3 conceptos relacionados:

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

El resultado refactorizado podría tener este aspecto:

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),"...") 

Ese \ que queda es continuar la línea $(MAKE) para el shell. No es necesaria ninguna variable multilínea aquí, porque es solo una línea de código de shell. Las variables de línea múltiple solo se usan en el bloque else.

Si usted no necesita parámetros que se pueden utilizar: = misiones y acaba de ampliar el método con $(compile) (ver canned recipes)

[Editar]Nota: El uso de hacer antes de la versión 3.82, los = no fue reconocido al final de la declaración de definición para mí. Lo arreglé usando define compile en su lugar.

+0

¿Por qué es esto mejor que la respuesta anterior que actualmente está marcada como correcta? –

+1

Debe usar variables de varias líneas, en lugar de \. Lo cual de nuevo sería "demasiado para simplemente editar esa respuesta" (por lo que he recibido reseñas hasta ahora) – JonnyJD

+0

Y explicar las variables de líneas múltiples es demasiado para hacer un comentario. Pero no tienes que estar de acuerdo, por supuesto. – JonnyJD

36

Está buscando 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) 

Si puede reestructurar su Makefile un poco, sin embargo, usted debe ver si se puede usar make 's conditionals en lugar de sh' s.

+1

¡Gracias, esto funcionó! :) No veo directamente cómo puedo usar los condicionales de make para hacer lo mismo que lo que quiero. Al menos no sin una gran cantidad de reestructuraciones. Por supuesto, esto podría deberse a que no tengo mucha experiencia escribiendo Makefiles ... –

+0

Este es un buen ejemplo en el que debes usar [variables de varias líneas] (http://www.gnu.org/software/make /manual/html_node/Multi_002dLine.html). – JonnyJD