修改Makefile以获取2个可执行文件的简单表单

时间:2017-10-04 16:18:46

标签: makefile

到目前为止,我使用以下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变量与&#34; $<&#34;结合使用的基本表单。变量

我试图像上面那样制作上面的等效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

但不幸的是,输入&#34; make&#34;产生:

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

我不知道如何规避这个错误。也许我应该使用依赖.f90.o:,但我不清楚知道放在哪里。很抱歉,如果这是初学者问题,欢迎任何帮助。

更新1:

根据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的预期行为吗?谢谢你的帮助

更新2:

我想我可以使用以下规则:

%.o: %.f90
    $(GFORTRAN) -o $@ -c $< 

但问题是我必须使用*.f90编译一些$(MPI_FORTRAN)个文件。我不知道如何区分2个obj文件(* .o)(使用gfortan编译器和mpif90编译器)

更新3:

我几乎得到了解决方案。我做了:

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次&#34; make&#34;连续获得2个可执行文件。这是这些3&#34;输出&#34;的输出。 :

首先&#34;制作&#34; :

$ 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

第二&#34;制作&#34; :

$ 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

第三&#34;制作&#34; :

$ 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

是否可以只做一个简单的&#34; make&#34;编译所有而不是必须键入3次&#34; make&#34; ?

我怀疑行cp -pf $(SRC_SEQ) $@cp -pf $(SRC_PAR) $@导致相对于$(DIR_SEQ)/%.f90$(DIR_PAR)/%.f90依赖的问题。

谢谢,也许我会开始赏金。

1 个答案:

答案 0 :(得分:0)

双重编译的问题来自规则:

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

$<仅列出第一个先决条件,在所有情况下都是explicitSeq.f90 - 您的其他对象文件根本没有更新,因为他们的食谱不会创建目标!

对于你的第二个问题:这是一个棘手的问题。一个非常棘手的一个恕我直言。实际上,您要求的是一个多架构构建,其复杂性要求两个架构构建在一个makefile中。我不够精通布局多方解决方案,更不用说堆栈溢出的答案,但是目前我想出了一个违反Paul's third rule的解决方案。 为了进一步阅读,我推荐你Paul's Multiarchitecture Builds,它有很多好消息。

现在解决方案:你需要一种方法来指定由#34;另一个&#34;编译的文件。编译器。由于文件名结尾显然没有选项我不知道你是否有必要用一个以及另一个编译器编译同一个文件,我建议对象使用不同的目录文件。由于我没有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在哪里找到编译所需的源文件。