2013-05-17 87 views
2

我在理解如何設計我的生成文件以按照我想要的方式構建我的項目時遇到了一些麻煩。具體來說,我不知道如何將所有源文件保存在src目錄中,同時將所有二進制文件放在bin目錄中,但鏈接的可執行文件(該文件位於項目根目錄中)除外。Makefile與Fortran - 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 [email protected] 

runner: $(OBJS) 

clean: 
    @rm -rf $(BINDIR) 

運行make好吧建立的一切 - 它發現在src所有的源文件,並把在bin所有.o文件 - 而是由編譯器生成的模塊文件(.mod)放在項目根目錄中,而不是在bin目錄中。我意識到我可以指定一條規則將它們放置在那裏,但是that messes with the build order, and will sometimes break the build

什麼是「正確」的方式來獲得這種行爲?

是的,我看過autotools和automake,但我從未使用過它們,它們似乎對這個項目過度。因爲我找不到任何好的教程他們如何工作(不,我不喜歡the tutorial on gnu.org)我寧願如果我可以避免學習這個工具只是爲了得到這個工作...

回答

1

假設您的底層Fortran編譯器是gfortran,請使用-J命令行選項。

$(FC) $(FFLAGS) -c $^ -o [email protected] -J$(BINDIR) 

着眼於未來,你可能會更好創建MODDIR或類似的變量,您使用的,而不是BINDIR。對象代碼(* .o)和mod文件在後來的編譯和鏈接步驟中扮演着不同的角色 - 在較大的項目中,它們通常是分開的。

+0

'-J'選項似乎正是我要找的!所有文件最終都在我想要的地方=)然而,構建失敗,因爲'gfortran'不知道在'bin /'中查找'.mod's。我如何指定他們在那裏? –

+0

另外,關於創建'MODDIR' - 如果這個項目比較大,但它只有大約15個源文件(並且不會增長太多),所以一個目錄對我來說沒問題。 –

+0

雖然這很奇怪 - 第一個文件可以正常工作;它沒有依賴關係。第二個取決於第一個,但建立好。第三個依賴於第一個和第二個,並失敗,因爲它無法找到第二個模塊中定義的幾個變量 - 但是文件在那裏,變量被定義(在源文件中正確指定,在mod文件中提到,雖然我不知道mod的格式,所以我不能說如果有什麼錯誤...)。 [這裏是mod文件](http://paste.ubuntu.com/5673502/) - 無法找到的符號是'rnk'和'nproc'。 –

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 [email protected] $^ 

%.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將在處理makefile的這部分內容時位於目錄BUILDDIR中)。

  • 在第二部分(首先執行,當變量RECURSED尚未設置時),您切換到BUILDIR目錄並從那裏調用您的makefile。你傳遞一些幫助變量(例如當前目錄)和所有的目標,除了那些必須從BUILDDIR之外執行的目標(例如distclean和創建目標BUILDDIR本身)。第二部分也提供了您指定的目標規則。