到目前为止,我使用以下
Makefile
在同一目录中获取所有源的 2 个可执行文件:
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 $@ 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 $@ explicitPar.o explUtilPar.o updateBound.o readParam.o
.f90.o:
$(MPI_FORTRAN) -c $(*F).f90
clean :
/bin/rm -f *.o explicitSeq explicitPar
一切正常。现在,我想使用一个使用
%.o
和 %.f90
变量结合“$<
”变量的基本形式。
我试着像上面这样制作等价的
Makefile
:
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 $@ $<
OBJ_SEQ: SRC_SEQ
$(GFORTRAN) -c $<
explicitPar : OBJ_PAR
$(MPI_FORTRAN) -o $@ $<
OBJ_PAR: SRC_PAR
$(MPI_FORTRAN) -c $<
clean :
/bin/rm -f *.o explicitSeq explicitPar
但不幸的是,输入“make”会产生:
make: *** No rule to make target `SRC_SEQ', needed by `OBJ_SEQ'. Stop.
我不知道如何规避这个错误。也许我应该使用依赖
.f90.o:
,但我不知道把它放在哪里。
根据 Vroomfondel 的建议,我做了以下修改:
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 $@ $<
$(OBJ_SEQ): $(SRC_SEQ)
$(GFORTRAN) -c $<
explicitPar : $(OBJ_PAR)
$(MPI_FORTRAN) -o $@ $<
$(OBJ_PAR): $(SRC_PAR)
$(MPI_FORTRAN) -c $<
clean :
/bin/rm -f *.o explicitSeq explicitPar
我得到了错误:
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
如您所见,文件
explicitSeq.f90
被编译了 2 次:这是修改后的 Makefile 的预期行为吗?
我想我可以使用以下规则:
%.o: %.f90
$(GFORTRAN) -o $@ -c $<
但问题是我还必须用
*.f90
编译一些$(MPI_FORTRAN)
文件。我不知道如何区分 obj 文件 (*.o) 的两种情况(使用 gfortan 编译器和 mpif90 编译器)
我几乎得到了解决方案。我做到了:
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 $@ $^
$(DIR_SEQ)/%.o: $(DIR_SEQ)/%.f90
$(GFORTRAN) -c $< -o $@
explicitPar: $(OBJ_PAR)
$(MPI_FORTRAN) -o $@ $^
$(DIR_PAR)/%.o: $(DIR_PAR)/%.f90
$(MPI_FORTRAN) -c $< -o $@
$(OBJ_SEQ): | $(DIR_SEQ)
$(OBJ_PAR): | $(DIR_PAR)
$(DIR_SEQ):
mkdir $@
cp -pf $(SRC_SEQ) $@
$(DIR_PAR):
mkdir $@
cp -pf $(SRC_PAR) $@
clean:
rm -f *.o explicitSeq explicitPar
rm -f $(DIR_SEQ)/*
rmdir $(DIR_SEQ)
rm -f $(DIR_PAR)/*
rmdir $(DIR_PAR)
不幸的是,我必须连续输入 3 次“make”才能获得 2 个可执行文件。这是这 3 个“make”的输出:
第一个“制作”:
$ 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
第二个“制作”:
$ 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
第三个“制作”:
$ 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
是否可以只做一个简单的“make”来编译所有而不是必须键入 3 次“make”?
我怀疑线
cp -pf $(SRC_SEQ) $@
和cp -pf $(SRC_PAR) $@
相对于$(DIR_SEQ)/%.f90
和$(DIR_PAR)/%.f90
依赖引起问题。
双重编译的问题来自规则:
$(OBJ_SEQ): $(SRC_SEQ)
$(GFORTRAN) -c $<
$<
仅命名第一个先决条件,在所有情况下都是explicitSeq.f90
- 您的其他目标文件根本没有更新,因为它们的配方没有创建目标!
对于你的第二个问题:这是一个棘手的问题。一个非常棘手一个恕我直言。实际上,您要求的是一个多架构构建,您希望 both 架构构建在一个 makefile 中。我还不够熟练,无法制定多架构解决方案,更不用说 stackoverflow 的答案了,但目前我想出了一个违反 Paul 的第三条规则 的解决方案,尽管它很简单。 如需进一步阅读,我建议您参阅 Paul 的多架构构建,其中包含大量有用的信息。
现在解决方案:您需要一种方法来指定应由“其他”编译器编译的文件。由于文件名结尾显然没有选择 and 我不知道您是否有必要用一个和另一个编译器编译同一个文件,我建议目标文件使用不同的目录。由于我没有 Fortran 源代码或编译器,我使用 C 和 C++ 来接管顺序和并行代码的角色。我认为您可以轻松地使其适应您的系统:
.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 $@ $<
$(PROC_DIR)/%.o: %.c
gcc -c -o $@ $<
# targets for the binaries
objectoriented: $(OBJECT)
@echo linking $^
-gcc -o $@ $^
procedural: $(PROCED)
@echo linking $^
-gcc -o $@ $^
# create destination directories, if not present
$(OBJECT): | $(OBJ_DIR)
$(PROCED): | $(PROC_DIR)
$(OBJ_DIR):
mkdir $@
$(PROC_DIR):
mkdir $@
还有一件事:我使用 VPATH 来定位源文件:
make VPATH=srcdir_a:srcdir_b:othersrcdir
告诉 make 在哪里可以找到编译所需的源文件。