修改 Makefile 以获得 2 个可执行文件的简单形式

问题描述 投票:0回答:1

到目前为止,我使用以下

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:
,但我不知道把它放在哪里。

更新 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)
文件。我不知道如何区分 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 次“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
依赖引起问题。

makefile
1个回答
0
投票

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

$(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 在哪里可以找到编译所需的源文件。

© www.soinside.com 2019 - 2024. All rights reserved.