2013-05-17 2 views
2

У меня возникли проблемы с пониманием того, как создать мой make-файл для создания моего проекта так, как я хочу. В частности, я не могу понять, как хранить все исходные файлы в каталоге 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 строит все Allright - он находит все исходные файлы в src и помещает все .o файлы в bin - но модуль файлов (.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'.Как я могу указать, что они есть? –

+0

Кроме того, что касается создания 'MODDIR' - я бы сделал, если бы этот проект был больше, но это всего лишь около 15 исходных файлов (и не будет расти намного больше), поэтому один каталог со мной. –

+0

Странно, но - первый файл строит ОК; он не имеет зависимостей. Второй зависит от первого, но строит ОК. Третий зависит как от первого, так и от второго, и терпит неудачу, потому что он не может найти пару переменных, определенных во втором модуле, - но файлы есть, а переменная определена (правильно указана в исходном файле, упомянутом в файле мод , хотя я не знаю формат мода, поэтому не могу сказать, что там что-то не так ...). [Вот файл мод] (http://paste.ubuntu.com/5673502/) - символы, которые не могут быть найдены, это 'rnk' и' nproc'. –

0

Возможно, это было бы скорее в том смысле, что система make изменится в каталог obj и сделает компиляцию оттуда. С помощью опции VPATH вы можете позволить автоматически найти исходные файлы. Вы можете легко вызывать ваш make-файл рекурсивно из нужного каталога. Ниже вы найдете тривиальный пример, который будет легко адаптировать к вашему делу. Обратите внимание, что он работает только с 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 будет находиться в каталоге BUILDDIR при обработке этой части файла makefile).

  • Во второй части (которая выполняется первой, когда переменная RECURSED еще не установлена), вы переходите в каталог BUILDIR и вызываете свой файл makefile оттуда. Вы передаете некоторые вспомогательные переменные (например, текущий каталог) и все цели, кроме тех, которые должны выполняться извне BUILDDIR (например, distclean и тот, который сам создает BUILDDIR). Правила для тех целей, которые вы указали и во второй части.

Смежные вопросы