【问题标题】:Store object files in separate directory using make使用 make 将目标文件存储在单独的目录中
【发布时间】:2015-01-24 01:01:09
【问题描述】:

我正在 Windows 上使用 mingw 运行生成文件。我看过很多关于这个主题的 SO 链接,但它们似乎都是针对 C 或 c++ 的。我不确定是否适用相同的规则,并且由于我使用的是 Windows,因此语法似乎也有些不同。以下是其他一些参考资料:

How to place object files in separate subdirectory(我认为最有希望)

Using a make file to compile files in separate directories

Flat object file directory structure output with GNU Make

我目前拥有的是(逐字)

VPATH =\
    user \
    static \
    computations \
    solvers\\steadyState \
    solvers\\transient \
    solvers\\transient\\momentum \
    solvers\\transient\\induction

FC      = gfortran
TOP_DIR = .
MOD_DIR = $(TOP_DIR)\\mod
OBJ_DIR = $(TOP_DIR)\\obj

FCFLAGS = -g
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized

TARGET = parametricStudy

SRCS_F =\
    user\\constants.f90 \
    static\\myExceptions.f90 \
    static\\myDebug.f90 \
    static\\scalarField.f90 \
    static\\vectorField.f90 \
    static\\myIO.f90 \
    user\\simParams.f90 \
    static\\solverSettings.f90 \
    static\\myTime.f90 \
    computations\\myError.f90 \
    static\\coordinates.f90 \
    user\\griddata.f90 \
    static\\myAllocate.f90 \
    static\\BCs.f90 \
    user\\rundata.f90 \
    computations\\myDel.f90 \
    computations\\vectorOps.f90 \
    static\\myExport.f90 \
    computations\\applyBCs.f90 \
    solvers\\steadyState\\mySOR.f90 \
    solvers\\steadyState\\myPoisson.f90 \
    solvers\\transient\\induction\\initializeBBCs.f90 \
    solvers\\transient\\induction\\initializeBfield.f90 \
    solvers\\transient\\induction\\initializeSigmaMu.f90 \
    solvers\\transient\\momentum\\initializeUBCs.f90 \
    solvers\\transient\\momentum\\initializeUfield.f90 \
    solvers\\transient\\inductionSolver.f90 \
    solvers\\transient\\momentumSolver.f90 \
    solvers\\transient\\MHDSolver.f90 \
    user\\MOONS.f90 \
    parametricStudy.f90

OBJS_F = $(patsubst %.f90,$(OBJ_DIR)\\%.o,$(notdir $(SRCS_F)))

all: $(TARGET)

$(TARGET): $(OBJS_F)
    $(FC) -o $@ $(FCFLAGS) $(OBJS_F)

$(OBJ_DIR)\\%.o: %.f90
    $(FC) $(FCFLAGS) -c -o $@ $<
clean:
    del $(OBJ_DIR)\\*.o $(MOD_DIR)\\*.mod parametricStudy.exe
list:;  @echo " "
    @echo " "
    @echo "Source files:"
    @echo $(SRCS_F)
    @echo " "
    @echo "Object files:"
    @echo $(OBJS_F)
    @echo " "
    @echo "Compiler          : $(FC)"
    @echo "Include directory : $(INC_DIR)"
    @echo "Root directory    : $(ROOT_DIR)"
    @echo "Bin directory     : $(BIN_DIR)"
    @echo "Modules directory : $(MOD_DIR)"
    @echo "Modules directory : $(MOD_DIR)"
    @echo "Object directory  : $(OBJ_DIR)"
    @echo " "

使用它,我可以执行以下(再次逐字)

C:\Users\Charlie\Desktop\development\FORTRAN_LIB>gmake
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\const
ants.o user/constants.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myExc
eptions.o static/myExceptions.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myDeb
ug.o static/myDebug.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\scala
rField.o static/scalarField.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\vecto
rField.o static/vectorField.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myIO.
o static/myIO.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\simPa
rams.o user/simParams.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\solve
rSettings.o static/solverSettings.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myTim
e.o static/myTime.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myErr
or.o computations/myError.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\coord
inates.o static/coordinates.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\gridd
ata.o user/griddata.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myAll
ocate.o static/myAllocate.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\BCs.o
 static/BCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\runda
ta.o user/rundata.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myDel
.o computations/myDel.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\vecto
rOps.o computations/vectorOps.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myExp
ort.o static/myExport.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\apply
BCs.o computations/applyBCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\mySOR
.o solvers\\steadyState/mySOR.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myPoi
sson.o solvers\\steadyState/myPoisson.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeBBCs.o solvers\\transient\\induction/initializeBBCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeBfield.o solvers\\transient\\induction/initializeBfield.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeSigmaMu.o solvers\\transient\\induction/initializeSigmaMu.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeUBCs.o solvers\\transient\\momentum/initializeUBCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeUfield.o solvers\\transient\\momentum/initializeUfield.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\induc
tionSolver.o solvers\\transient\\induction/inductionSolver.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\momen
tumSolver.o solvers\\transient\\momentum/momentumSolver.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\MHDSo
lver.o solvers\\transient/MHDSolver.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\MOONS
.o user/MOONS.f90
gmake: *** No rule to make target `.\\obj\parametricStudy.o', needed by `paramet
ricStudy'.  Stop.

C:\Users\Charlie\Desktop\development\FORTRAN_LIB>gfortran -g -J.\\mod -fopenmp -
c -o .\\obj\parametricStudy.o parametricStudy.f90

C:\Users\Charlie\Desktop\development\FORTRAN_LIB>gmake
gfortran -o parametricStudy -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized
 .\\obj\constants.o .\\obj\myExceptions.o .\\obj\myDebug.o .\\obj\scalarField.o
.\\obj\vectorField.o .\\obj\myIO.o .\\obj\simParams.o .\\obj\solverSettings.o .\
\obj\myTime.o .\\obj\myError.o .\\obj\coordinates.o .\\obj\griddata.o .\\obj\myA
llocate.o .\\obj\BCs.o .\\obj\rundata.o .\\obj\myDel.o .\\obj\vectorOps.o .\\obj
\myExport.o .\\obj\applyBCs.o .\\obj\mySOR.o .\\obj\myPoisson.o .\\obj\initializ
eBBCs.o .\\obj\initializeBfield.o .\\obj\initializeSigmaMu.o .\\obj\initializeUB
Cs.o .\\obj\initializeUfield.o .\\obj\inductionSolver.o .\\obj\momentumSolver.o
.\\obj\MHDSolver.o .\\obj\MOONS.o .\\obj\parametricStudy.o

请注意,收到错误后,我可以在错误后显式编译 parametricStudy.f90:

 gfortran -g -J.\\mod -fopenmp -c -o .\\obj\parametricStudy.o parametricStudy.f90

然后输入

 gmake

同样,这不会导致错误。我很困惑。

这是我目录的截图:

也许它与目标有关?似乎最后一个文件的路径有些错误。非常感谢任何帮助!

【问题讨论】:

  • 您使用的是 Cygwin 或 MinGW 的 GNU make 吗?
  • 我实际上在使用 mingw
  • 我想。我用 gmake 或 mingw32-make 运行 makefe
  • 你仍然没有规则来制作parametricStudy.o吗?如果是这样,请在包含 makefile 的目录中运行 dir 并发布输出。
  • 是的,我是。前几天我更新了这个问题。它应该是最新的。我会在今天下午 1:30 仔细检查。

标签: makefile fortran mingw gfortran


【解决方案1】:

我认为下面的 makefile 风格可以解决问题。我用样品 C 测试了它 项目,而不是 fortran,但这对 make 问题和解决方案无关紧要。

# VPATH: Tell `make` to look for in `user` for prerequisites it can't find here
VPATH = user
# If e.g. you also want `make` to look for for prerequisites in `../include`, then:
# VPATH = user:../include
FC      = gfortran
TOP_DIR = .
MOD_DIR = $(TOP_DIR)\\mod
OBJ_DIR = $(TOP_DIR)\\obj

FCFLAGS = -g
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized

TARGET = parametricStudy

SRCS_F =\
    user\\constants.f90 \
    ...
    parametricStudy.f90

OBJS_T1 = $(patsubst %.f90,%.o,$(SRCS_F))
OBJS_T2 = $(notdir $(OBJS_T1))
# The object files are all to be obj\<name>.o
OBJS_F = $(patsubst %.o,$(OBJ_DIR)\\%.o,$(OBJS_T2))

all: $(TARGET)

$(TARGET): $(OBJS_F)
    $(FC) -o $@ $(FCFLAGS) $(OBJS_F)

# How to make an obj\*.o from the matching *.f90. `make` considers the VPATH
$(OBJ_DIR)\\%.o: %.f90
    $(FC) $(FCFLAGS) -c -o $@ $<
clean:
    del $(OBJ_DIR)\\*.o $(MOD_DIR)\\*.mod parametricStudy.exe

使用相对路径 TOP_DIR = . 而不是绝对路径 ROOT_DIR 是已经提供的好建议 @Wintermute。

启用所需的模式规则:

$(OBJ_DIR)\\%.o: %.f90

要开始,您必须让make 看到任何先决条件*.f90 就在这里,按照模式, 不在其他目录中,例如user\constants.f90 那就是VPATH 达到。

后续开发继续

我还没有看到 makefile 所在目录的列表 只能冒险一个假设,但我所看到的假设是:

该目录实际上并不包含名为parametricStudy.f90 的文件, 但是一个名为parametricStudy.F90的文件,如果它被重命名为parametricStudy.f90, 然后makefile会找到并编译它。

是吗?

这如何解释事实:模式规则:

$(OBJ_DIR)\\%.o: %.f90

无法匹配任何parametricStudy.f90,因此没有这样的文件。但是你说:

gfortran -g -J.\\mod -fopenmp -c -o .\\obj\parametricStudy.o parametricStudy.f90

成功编译。

您是在 Windows 上构建的,因此工具链订阅了 Windows 的文件处理协议。 文件名不区分大小写:parametricStudy.f90 将识别 parametricStudy.F90,如果它存在, 和 .F90 将被 gfortran(在 Windows 或其他任何地方)解释为表示 Fortran 90 源文件。至此命令行编译成功。

但是模式规则与文件处理协议无关。这只是一个模式 匹配规则,不变量.f90.F90不匹配。

【讨论】:

  • 这非常接近完全工作!除最后一个 (parametricStudy.f90) 之外的所有文件都编译为 .object 文件。最后一个 .f90 文件位于绝对路径中会非常好(我想将我的代码和模拟结果分开)。有没有办法让 VPATH 包含根目录? (我试过“。”,但没有奏效)。如果我可以让 VPATH 包含绝对路径,那就更好了。此外,由于最后一个文件没有成功制作,因此没有制作可执行文件。
  • parametricStudy.f90 没有被编译? makefile 中肯定还有错误。建议您按原样发布。
  • P.S.我是否正确地假设 parametricStudy.f90 您正在运行 make 的目录中?
  • 为了确定,parametricStudy.f90 你正在运行 make 的目录中?
  • 是的,我有 makefile、parametricStudy、用户(文件夹)等。
【解决方案2】:

你面临的问题是

ROOT_DIR = "C:\Users\Charlie\"
OBJ_DIR = $(ROOT_DIR)\obj

规则

$(OBJ_DIR)/%.o: %.f90

扩展到

"C:\Users\Charlie\"obj/%.o: %.f90

被解析为静态模式规则

"C: \Users\Charlie\"obj/%.o: %.f90

也就是说,有目标"C,目标模式\Users\Charlie\"obj/%.o和前提模式%.f90。 make 抱怨 "C 与模式 \Users\Charlie\"obj/%.o 不匹配。

GNU make 中有一些 hacky 代码(至少在 MinGW 中;我认为 Cygwin 的行为不同,因为它希望您使用它的 unix-ish 目录结构)来识别绝对 Windows 路径,但它不处理引用。只要您的 OBJ_DIR 不包含空格,使用

ROOT_DIR = C:\Users\Charlie\

应该会启动 Windows 路径识别。

但是...在手工制作的 Makefile 中看到绝对路径是相当不寻常的。你确定要这样做吗?更常见的方法是使用相对路径,以便在将源代码复制到不同目录时不必更改 Makefile。假设 Makefile 在根目录中,那将是

ROOT_DIR = .

或者只是完全取消 ROOT_DIR 变量并说

MOD_DIR = mod
OBJ_DIR = obj

哦,回答下一个即将出现的问题:为了使make 使用

$(OBJ_DIR)/%.o: %.f90

规则,您需要使$(TARGET) 具有匹配$(OBJ_DIR)/%.o 模式的先决条件。那可能是

OBJS_F = $(patsubst %.f90,$(OBJ_DIR)/%.o,$(notdir $(SRCS_F)))

【讨论】:

  • 当我尝试你的建议时,我收到错误“gmake: *** No rule to make target obj/constants.o', needed by parametricStudy' . Stop.”
  • 我想我不明白的是你所说的 $(TARGET) 具有与 $(OBJ_DIR)%.o 模式匹配的先决条件。这是否意味着主程序需要是在.o目录中?..
  • 主程序在哪里并不重要,但它的先决条件必须与知道如何制作它们的规则的模式相匹配。嗯...我想我看到了问题。对于(OBJ_DIR)/%.o : %.f90.f90 文件必须直接位于工作目录中,但情况并非如此。并且很难重构特定%.o 所依赖的%.f90。但是,您的原始 makefile 也不会这样做,因此您至少应该能够使用 $(OBJ_DIR)/%.o: $(SRCS_F) 重现旧行为(当一个 .f90 更改时所有内容都会重新编译)
  • 我对使用 make 文件真的很陌生。我希望在对 .f90 文件进行更改时只编译需要编译的文件。我可以重新发布这个问题不同的,更合适的标题,并通过我尝试过的每种形式的 make 文件来解决错误和问题..
猜你喜欢
  • 2012-01-29
  • 2023-03-22
  • 1970-01-01
  • 2011-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-05
相关资源
最近更新 更多