2017-10-04 6 views
0

Jusqu'à présent, je l'Makefile suivante pour obtenir 2 executables avec toutes les sources dans le même répertoire:Modifier Makefile pour obtenir un formulaire simple pour 2 executables

GFORTRAN = gfortran -Wall 
CC   = gcc -Wall 
MPI_FORTRAN = mpif90 -Wall 
MPI_CC  = mpicc -Wall 
LD = -lm 

.SUFFIXES : .o .f90 

all: explicitSeq explicitPar 

explicitSeq : explicitSeq.o explUtilSeq.o 
     $(GFORTRAN) -o [email protected] explicitSeq.o explUtilSeq.o 

explicitSeq.o : explicitSeq.f90 
     $(GFORTRAN) -c $(*F).f90 

explUtilSeq.o : explUtilSeq.f90 
     $(GFORTRAN) -c $(*F).f90 

explicitPar : explicitPar.o explUtilPar.o updateBound.o readParam.o 
     $(MPI_FORTRAN) -o [email protected] explicitPar.o explUtilPar.o updateBound.o readParam.o 

.f90.o: 
     $(MPI_FORTRAN) -c $(*F).f90 

clean : 
     /bin/rm -f *.o explicitSeq explicitPar 

Tout fonctionne très bien. Maintenant, je voudrais utiliser un formulaire de base en utilisant %.o et %.f90 variables combinées avec "$<" variable.

J'ai essayé de faire l'équivalent de Makefile ci-dessus comme ceci:

GFORTRAN = gfortran -Wall 
CC   = gcc -Wall 
MPI_FORTRAN = mpif90 -Wall 
MPI_CC  = mpicc -Wall 
LD = -lm 

SRC_SEQ = explicitSeq.f90 explUtilSeq.f90 
OBJ_SEQ = explicitSeq.o explUtilSeq.o 
SRC_PAR = explicitPar.f90 explUtilPar.f90 updateBound.f90 readParam.f90 
OBJ_PAR = explicitPar.o explUtilPar.o updateBound.o readParam.o 

all: explicitSeq explicitPar 

explicitSeq : OBJ_SEQ 
     $(GFORTRAN) -o [email protected] $< 

OBJ_SEQ: SRC_SEQ 
     $(GFORTRAN) -c $< 

explicitPar : OBJ_PAR 
     $(MPI_FORTRAN) -o [email protected] $< 

OBJ_PAR: SRC_PAR 
     $(MPI_FORTRAN) -c $< 

clean : 
     /bin/rm -f *.o explicitSeq explicitPar 

Mais malheureusement, en tapant "make" produit:

make: *** No rule to make target `SRC_SEQ', needed by `OBJ_SEQ'. Stop. 

Je ne sais pas comment contourner cette erreur. Peut-être que je devrais utiliser la dépendance .f90.o: mais je ne sais pas clairement où le mettre. Désolé si c'est un problème débutant mais toute aide est la bienvenue.

MISE À JOUR 1:

De l'avis de Vroomfondel, je l'ai fait les modifications suivantes:

GFORTRAN = gfortran-mp-4.9 -Wall 
CC   = gcc -Wall 
MPI_FORTRAN = mpif90 -Wall 
MPI_CC  = mpicc -Wall 
LD = -lm 

SRC_SEQ = explicitSeq.f90 explUtilSeq.f90 
OBJ_SEQ = explicitSeq.o explUtilSeq.o 
SRC_PAR = explicitPar.f90 explUtilPar.f90 updateBound.f90 readParam.f90 
OBJ_PAR = explicitPar.o explUtilPar.o updateBound.o readParam.o 

all: explicitSeq explicitPar 

explicitSeq : $(OBJ_SEQ) 
     $(GFORTRAN) -o [email protected] $< 

$(OBJ_SEQ): $(SRC_SEQ) 
     $(GFORTRAN) -c $< 

explicitPar : $(OBJ_PAR) 
     $(MPI_FORTRAN) -o [email protected] $< 

$(OBJ_PAR): $(SRC_PAR) 
     $(MPI_FORTRAN) -c $< 

clean : 
     /bin/rm -f *.o explicitSeq explicitPar 

et je reçois les erreurs:

gfortran-mp-4.9 -Wall -c explicitSeq.f90 
gfortran-mp-4.9 -Wall -c explicitSeq.f90 
gfortran-mp-4.9 -Wall -o explicitSeq explicitSeq.o 
Undefined symbols for architecture x86_64: 
    "_computenext_", referenced from: 
     _MAIN__ in explicitSeq.o 
    "_initvalues_", referenced from: 
     _MAIN__ in explicitSeq.o 
ld: symbol(s) not found for architecture x86_64 
collect2: error: ld returned 1 exit status 
make: *** [explicitSeq] Error 1 

Comme vous pouvez le voir, le fichier explicitSeq.f90 est compilé 2 fois: est-ce le comportement attendu du fichier Makefile modifié? Merci pour votre aide

MISE À JOUR 2:

Je pense que je pourrais utiliser la règle suivante:

%.o: %.f90 
    $(GFORTRAN) -o [email protected] -c $< 

mais le problème est que je dois compiler aussi quelques *.f90 fichiers avec $(MPI_FORTRAN). Je ne sais pas comment différencier les 2 cas de fichiers OBJ (* .o) (avec le compilateur et gfortan compilateur mpif90)

MISE À JOUR 3:

J'ai presque la solution. J'ai fait:

GFORTRAN = gfortran -Wall 
CC   = gcc -Wall 
MPI_FORTRAN = mpif90 -Wall 
MPI_CC  = mpicc -Wall 
LD = -lm 

DIR_SEQ = tmpSeqDir 
DIR_PAR = tmpParDir 
SRC_SEQ = explicitSeq.f90 explUtilSeq.f90 
OBJ_SEQ = $(addprefix $(DIR_SEQ)/,$(SRC_SEQ:.f90=.o)) 
SRC_PAR = explicitPar.f90 explUtilPar.f90 updateBound.f90 readParam.f90 
OBJ_PAR = $(addprefix $(DIR_PAR)/,$(SRC_PAR:.f90=.o)) 

all: explicitSeq explicitPar 

explicitSeq: $(OBJ_SEQ) 
     $(GFORTRAN) -o [email protected] $^ 

$(DIR_SEQ)/%.o: $(DIR_SEQ)/%.f90 
     $(GFORTRAN) -c $< -o [email protected] 

explicitPar: $(OBJ_PAR) 
     $(MPI_FORTRAN) -o [email protected] $^ 

$(DIR_PAR)/%.o: $(DIR_PAR)/%.f90 
     $(MPI_FORTRAN) -c $< -o [email protected] 

$(OBJ_SEQ): | $(DIR_SEQ) 
$(OBJ_PAR): | $(DIR_PAR) 

$(DIR_SEQ): 
     mkdir [email protected] 
     cp -pf $(SRC_SEQ) [email protected] 

$(DIR_PAR): 
     mkdir [email protected] 
     cp -pf $(SRC_PAR) [email protected] 

clean: 
     rm -f *.o explicitSeq explicitPar 
     rm -f $(DIR_SEQ)/* 
     rmdir $(DIR_SEQ) 
     rm -f $(DIR_PAR)/* 
     rmdir $(DIR_PAR) 

Malheureusement, je dois taper 3 fois "make" pour obtenir les 2 exécutables.Voici la sortie de ces 3 "fait":

d'abord "faire":

$ make 
mkdir tmpSeqDir 
cp -pf explicitSeq.f90 explUtilSeq.f90 tmpSeqDir 
gfortran -Wall -o explicitSeq tmpSeqDir/explicitSeq.o tmpSeqDir/explUtilSeq.o 
gfortran: error: tmpSeqDir/explicitSeq.o: No such file or directory 
gfortran: error: tmpSeqDir/explUtilSeq.o: No such file or directory 
Makefile:17: recipe for target 'explicitSeq' failed 
make: *** [explicitSeq] Error 1 

deuxième "marque":

$ make 
gfortran -Wall -c tmpSeqDir/explicitSeq.f90 -o tmpSeqDir/explicitSeq.o 
gfortran -Wall -c tmpSeqDir/explUtilSeq.f90 -o tmpSeqDir/explUtilSeq.o 
gfortran -Wall -o explicitSeq tmpSeqDir/explicitSeq.o tmpSeqDir/explUtilSeq.o 
mkdir tmpParDir 
cp -pf explicitPar.f90 explUtilPar.f90 updateBound.f90 readParam.f90 tmpParDir 
mpif90 -Wall -o explicitPar tmpParDir/explicitPar.o tmpParDir/explUtilPar.o tmpParDir/updateBound.o tmpParDir/readParam.o 
gfortran: error: tmpParDir/explicitPar.o: No such file or directory 
gfortran: error: tmpParDir/explUtilPar.o: No such file or directory 
gfortran: error: tmpParDir/updateBound.o: No such file or directory 
gfortran: error: tmpParDir/readParam.o: No such file or directory 
Makefile:23: recipe for target 'explicitPar' failed 
make: *** [explicitPar] Error 1 

troisième "faire":

$ make 
mpif90 -Wall -c tmpParDir/explicitPar.f90 -o tmpParDir/explicitPar.o 
mpif90 -Wall -c tmpParDir/explUtilPar.f90 -o tmpParDir/explUtilPar.o 
mpif90 -Wall -c tmpParDir/updateBound.f90 -o tmpParDir/updateBound.o 
mpif90 -Wall -c tmpParDir/readParam.f90 -o tmpParDir/readParam.o 
mpif90 -Wall -o explicitPar tmpParDir/explicitPar.o tmpParDir/explUtilPar.o tmpParDir/updateBound.o tmpParDir/readParam.o 

Est-il possible de faire seulement un simple "make" pour compiler tout au lieu d'avoir à taper 3 fois "make"?

Je suspecte que les lignes cp -pf $(SRC_SEQ) [email protected] et cp -pf $(SRC_PAR) [email protected] causent des problèmes relativement aux dépendances $(DIR_SEQ)/%.f90 et $(DIR_PAR)/%.f90.

Merci, peut-être que je vais commencer une prime.

+0

Vous devez écrire vos noms de variables dans '$()' lorsque vous les lisez. Le formulaire sans '$()' n'est utilisé que dans les affectations. – Vroomfondel

+0

@Vroomfondel Pourriez-vous jeter un coup d'œil sur mes ** MISE À JOUR 1 ** et ** MISE À JOUR 2 **? – youpilat13

+0

La règle 'explicitSeq: $ (DIR_SEQ)/$ (OBJ_SEQ)' évaluera à 'explicitSeq: tmpSeqDir/explicitSeq.f90 explUtilSeq.f90' (notez le chemin manquant pour le second fichier) qui n'est pas ce que nous voulons. Pourquoi sa prétention de ne pas savoir comment faire cela je ne sais pas cependant. J'y reviendrai plus tard. BTW quelle marque utilisez-vous? – Vroomfondel

Répondre

0

Le problème de la double compilation provient de la règle:

$(OBJ_SEQ): $(SRC_SEQ) 
     $(GFORTRAN) -c $< 

$< noms ne la première condition qui dans tous les cas est explicitSeq.f90 - vos autres fichiers objets ne sont pas mis à jour parce que leurs recettes Ne créez pas la cible!

Pour votre deuxième question: c'est délicat. Un très difficile un IMHO. En effet, vous demandez une construction multi-architectures avec la complexité supplémentaire que vous voulez les deux architectures construisent dans un fichier makefile. Je ne suis pas assez compétent pour mettre en place une solution multi-arch, encore moins dans une réponse stackoverflow, mais pour l'instant je suis venu avec une solution qui viole Paul's third rule néanmoins c'est simple. Pour plus de lecture, je vous renvoie à Paul's Multiarchitecture Builds qui a une tonne de bonnes informations.

Maintenant à la solution: vous avez besoin d'un moyen de spécifier les fichiers qui doivent être compilés par "l'autre" compilateur. Comme la fin du nom de fichier n'est évidemment pas une option et Je ne sais pas si vous avez jamais besoin de compiler le même fichier avec l'un et l'autre compilateur, je recommande différents répertoires pour les fichiers objet. Comme je n'ai pas de source Fortran ni de compilateurs, j'ai utilisé C et C++ pour prendre en charge les rôles de code séquentiel et parallèle. Je pense que vous pouvez facilement l'adapter à votre système:

.PHONY: all  
all: objectoriented procedural 

PROC_DIR = proc 
OBJ_DIR = oo 

OBJ_SRC = cppbaz.c 
PROC_SRC = bar.c 
SHARED_SRC = foo.c 

# deduce the object files from the sources 
OBJECT = $(addprefix $(OBJ_DIR)/,$(OBJ_SRC:.c=.o) $(SHARED_SRC:.c=.o)) 
PROCED = $(addprefix $(PROC_DIR)/,$(PROC_SRC:.c=.o) $(SHARED_SRC:.c=.o)) 

# pattern rules for the compilation - as we violate Paul's 3rd rule, we 
# need to give these, otherwise make executes empty recipes: 
$(OBJ_DIR)/%.o: %.c 
    g++ -c -o [email protected] $< 

$(PROC_DIR)/%.o: %.c 
    gcc -c -o [email protected] $< 

# targets for the binaries 
objectoriented: $(OBJECT) 
    @echo linking $^ 
    -gcc -o [email protected] $^ 

procedural: $(PROCED) 
    @echo linking $^ 
    -gcc -o [email protected] $^ 

# create destination directories, if not present 
$(OBJECT): | $(OBJ_DIR) 
$(PROCED): | $(PROC_DIR)  
$(OBJ_DIR): 
    mkdir [email protected] 
$(PROC_DIR): 
    mkdir [email protected] 

Encore une chose: j'ai utilisé un VPATH pour localiser les fichiers source:

make VPATH=srcdir_a:srcdir_b:othersrcdir qui raconte faire où trouver les fichiers source qui sont nécessaires pour la compilation.

+0

- @ Vroomfondel merci pour votre aide. Je ne comprends pas les lignes '$ (OBJECT): | $ (OBJ_DIR) 'et' $ (PROCED): | $ (PROC_DIR) ': que font-ils? Je comprends la ligne '$ (OBJ_DIR): mkdir $ @': il crée le répertoire avec le nom $ (OBJ_DIR) mais je n'ai pas vu dans la documentation les deux lignes dans ce commentaire ci-dessus. Cordialement – youpilat13

+0

'target: | order-only-prerequisite' cela rend la cible dépendante de la _existence_ mais pas du _timestamp_ du pré-requis. La commande seulement devrait être renommée à l'IMHO d'existence seulement. Pour les répertoires, c'est exactement ce que nous voulons: si c'est là, bien, peu importe la dernière modification, sinon, créez-le. – Vroomfondel

+0

- @ Vroomfondel Je l'ai eu: comme vous pouvez le voir dans ** UPDATE 3 ** et dans votre solution, mon erreur est que je n'ai pas réalisé que la règle '$ (OBJ_DIR) /%. O:% .c' détermine automatiquement les bonnes sources '* .c' en fonction des fichiers objets' $ (OBJ_DIR) /%. o' définis: Je pensais que '% .c' correspondait à toutes les sources' * .c' (Seq et Par sources) de mon répertoire. Merci beaucoup ! – youpilat13