web-dev-qa-db-fra.com

Fonctions dans Makefile

J'écris un Makefile avec beaucoup de choses répétitives, par ex.

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

où la cible 'syst' est définie, la variable 'UNAME' est définie (et est généralement Linux, mais peut aussi être par Cygwin ou OSF1) et les variables 'difort' et 'err_Arch' sont également définies. Ce bloc de code est utilisé très souvent pour différentes cibles de compilateur (en utilisant une convention de nom de ''). Puisqu'il s'agit d'une énorme quantité de code redondant, j'aimerais pouvoir l'écrire de manière plus simple. Par exemple, je voudrais faire quelque chose comme ceci:

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

où la compilation peut être une fonction faisant le code ci-dessus en fonction des arguments. Quelqu'un a-t-il une idée de comment je pourrais accomplir cela?

48
Karl Yngve Lervåg

Il existe 3 concepts liés:

  1. fonction call
  2. variables multilignes
  3. conditionnelles

Le résultat refactorisé pourrait ressembler à ceci:

ifeq ($(UNAME),Linux)
    compile = $(MAKE) FC=$(1) FFLAGS=$(2) PETSC_FFLAGS=$(3) \
                      TARGET=$@ LEXT="$(1)_$(UNAME)" -e syst
else
    define compile =
        echo $(err_Arch)
        exit 1
    endef
endif


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

Celui \ Qui reste est de continuer la ligne $(MAKE) pour le Shell. Aucune variable multiligne n'est nécessaire ici, car il s'agit d'une seule ligne de code Shell. Les variables multilignes ne sont utilisées que dans le bloc else.

Si vous n'avez pas besoin de paramètres, vous pouvez utiliser: = affectation et simplement développer la méthode avec $(compile) (voir recettes en conserve )

[Modifier] Remarque: En utilisant make avant la version 3.82, le = n'était pas reconnu à la fin de la définition déclaration pour moi. J'ai corrigé cela en utilisant à la place define compile.

37
JonnyJD

Vous recherchez la fonction call .

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

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

Si vous pouvez restructurer un peu votre Makefile, vous devriez voir si vous pouvez utiliser les conditionnelles de make au lieu de sh.

38
ephemient