Makefile与Fortran - src和bin目录

时间:2013-05-17 00:16:37

标签: makefile fortran

我在理解如何设计makefile以按照我想要的方式构建项目时遇到了一些麻烦。具体来说,我无法弄清楚如何将所有源文件保存在src目录中,同时将所有二进制文件放在bin目录中,但链接的可执行文件除外,该目录位于项目根目录中。

这是我的makefile:

# Compiler options
FC          :=  mpif90
FFLAGS      :=  -O3 -g -Wall -Warray-bounds -ffixed-line-length-none -fbounds-check 
VPATH       :=  src
BINDIR      :=  bin

# Define file extensions
.SUFFIXES:
.SUFFIXES: .f .o .mod 

# All modules
OBJS        :=  $(BINDIR)/ratecoeffs.o $(BINDIR)/interpolation.o $(BINDIR)/io.o $(BINDIR)/eedf.o $(BINDIR)/single_particle.o $(BINDIR)/physics.o $(BINDIR)/random.o $(BINDIR)/mpi.o $(BINDIR)/precision.o $(BINDIR)/populations.o 

# Build rules
all: runner | $(BINDIR)

$(BINDIR):
    mkdir -p $(BINDIR)

$(BINDIR)/%.o: $(VPATH)/%.f | $(BINDIR)
    $(FC) $(FFLAGS) -c $^ -o $@

runner: $(OBJS)

clean:
    @rm -rf $(BINDIR)

正在运行make构建所有内容 - 它会在src中找到所有源文件,并将所有.o个文件放入bin - 但模块文件(.mod )由编译器生成的文件放在项目根目录中,而不是放在bin目录中。我意识到我可以指定一个规则将它们放在那里,但是that messes with the build order, and will sometimes break the build

获得此行为的“正确”方式是什么?

是的,我看过autotools和automake,但我之前从未使用过它们,这对于这个项目来说似乎有些过分。因为我找不到关于它们如何工作的任何好的教程(不,我不喜欢the tutorial on gnu.org)我更愿意,如果我可以避免必须学习这个工具只是为了让这项工作...

2 个答案:

答案 0 :(得分:1)

假设您的基础Fortran编译器是gfortran,请使用-J命令行选项。

$(FC) $(FFLAGS) -c $^ -o $@ -J$(BINDIR)

着眼未来,您可能最好创建一个MODDIR或类似的变量,而不是使用BINDIR。对象代码(* .o)和mod文件在以后的编译和链接步骤中具有不同的角色 - 在较大的项目中,它们通常是分开的。

答案 1 :(得分:0)

make系统可能会更改为obj目录并从那里进行编译。通过VPATH选项,您可以让make自动查找源文件。您可以从右侧目录中以递归方式轻松调用makefile。下面是一个简单的例子,可以直接适应你的情况。请注意,它只适用于GNU make。

ifeq (1,$(RECURSED))
VPATH = $(SRCDIR)
########################################################################
# Project specific makefile
########################################################################
FC = gfortran
FCOPTS = 
LN = $(FC)
LNOPTS = 

OBJS = accuracy.o eqsolver.o io.o linsolve.o

linsolve: $(OBJS)
    $(LN) $(LNOPTS) -o $@ $^

%.o: %.f90
    $(FC) $(FCOPTS) -c $<

.PHONY: clean realclean
clean:
    rm -f *.mod *.o
realclean: clean
    rm -f linsolve


accuracy.o:
eqsolver.o: accuracy.o
io.o: accuracy.o
linsolve.o: accuracy.o eqsolver.o io.o

else
########################################################################
# Recusive invokation
########################################################################
BUILDDIR = _build
LOCALGOALS = $(BUILDDIR) distclean
RECURSIVEGOALS = $(filter-out $(LOCALGOALS), $(MAKECMDGOALS))
.PHONY: all $(RECURSIVE_GOALS) distclean
all $(RECURSIVEGOALS): $(BUILDDIR)
    +$(MAKE) -C $(BUILDDIR) -f $(CURDIR)/GNUmakefile SRCDIR=$(CURDIR) \
            RECURSED=1 $(RECURSIVEGOALS)
$(BUILDDIR):
    mkdir $(BUILDDIR)
distclean:
    rm -rf $(BUILDDIR)
endif

原则很简单:

  • 在第一部分中,您将编写正常的makefile,就好像您将在源目录中创建目标文件一样。但是,另外添加VPATH选项以确保找到源文件(当make文件的这一部分被处理时,make将位于目录BUILDDIR中)。

  • 在第二部分(首先执行,当时尚未设置变量RECURSED)时,您将切换到BUILDIR目录并从那里调用您的makefile。你传递了一些辅助变量(例如当前目录)和所有make目标,除了那些必须从外部BUILDDIR执行的目标(例如,distclean和创建BUILDDIR本身的目标)。您在第二部分中指定的目标规则。