Кто-нибудь знает, что причина такого поведения может быть?
Я нашел причину: если я заменю «мод» на «о» повсюду в моем
Makefile, проблема исчезает. Однако я не совсем понимаю
почему.
Единственное правдоподобное объяснение состоит в том, что временные метки существующих файлов .mod
не обновляются, когда исходные источники перестраиваются. Я предполагаю, что он распространяется только до тех пор, пока интерфейс модуля не изменяется - то есть никакие функции или подпрограммы не добавляются, не удаляются и не изменяются таким образом, что это влияет на их внешний интерфейс, и аналогично никакие переменные модуля не добавляются, не удаляются и не изменяются по типу. .
Я вижу, что было бы желательно избегать обновления файлов .mod
, если в них ничего не изменилось, особенно в связи с реализациями модулей, хранящимися во внешних библиотеках. Насколько мне известно, однако, нет общей стандартизации даже существования .mod
файлов, тем более обстоятельств, при которых они создаются или обновляются. Ваш компилятор может предложить опцию, которая заставляет их обновляться при компиляции соответствующего источника; если это так, то добавление этой опции в ваши команды компиляции должно решить вашу проблему.
В противном случае то, что ваш компилятор обещает , безусловно, обещает, что если вы попросите его скомпилировать исходный файл в объектный файл, то в случае успеха он запишет новый объектный файл. Более того, хотя я не обязательно догадывался, что то же самое было бы неверно для файлов .mod
, важно понимать, что последние обычно описывают интерфейсы для ваших модулей, а не их реализации , поэтому ваше главное правило семантически неверно:
polmob: polmob.f90 io.mod system.mod bands.mod parallel.mod
@echo [triggered by changes in $?]
mpifort -o polmob polmob.f90 io.f90 system.f90 bands.f90 parallel.f90
Вам необходимо перестроить, если какая-либо из реализаций изменится, независимо от того, изменятся ли интерфейсы модуля, и ваше правило не адекватно отражает это требование.
В этот момент я также замечаю, что когда вы перестраиваете с помощью этого правила, вы перестраиваете всех источников, что делает бессмысленными правила сборки для каждого источника. Если это то, что вы хотите, то более простым решением было бы переписать ваш make-файл в следующий момент:
SOURCES = polmob.f90 io.f90 system.f90 bands.f90 parallel.f90
polmob: $(SOURCES)
@echo [triggered by changes in $?]
mpifort -o $@ $(SOURCES)
clean:
find . ! -name 'Makefile' -a ! -name '*.f90' -type f -exec rm -f {} +
Там цель фактически строится из указанных предварительных условий, и рецепта сборки достаточно, чтобы построить цель из этих предпосылок. Однако, если какой-либо из источников изменится, он восстановит их все (аналогично тому, что делает ваш оригинальный make-файл).
Альтернатива состоит в том, чтобы создавать отдельные объекты и затем связывать их вместе в отдельном шаге. Ваш оригинальный make-файл, кажется, склоняется в этом направлении, но затем отбрасывает его с основным правилом. Если вы хотите принять такой подход, то он усложняется фактами, которые
- это действительно модуль интерфейсов , от которого зависят отдельные объекты (в дополнение к их собственным источникам), поэтому выражение предпосылок в терминах других объектных файлов в этих случаях некорректно;
- оба файла
.o
и .mod
создаются одним и тем же процессом (т. Е. Он имеет несколько выходов);
- и, очевидно, этот процесс использует логику, отличную от
make
, чтобы определить, устарели ли файлы .mod
.
Проблема с несколькими выходами, вероятно, самая веселая; Вы можете найти обсуждение и альтернативные решения различной строгости в документации Automake (но не только для Automake).
Вот способ, которым вы можете подойти к этому, вдохновленный документами Automake, но с учетом особенностей, которые вы обнаружили в своей реализации на Фортране:
# All the object files contributing to the program:
OBJECTS = bands.o const.o io.o parallel.o polmob.o system.o
# Link all the objects together to form the final program
# (.mod files are typically not needed for this step)
polmob: $(OBJECTS)
mpifort -o $@ $(OBJECTS)
# Rules for building the objects
bands.o : bands.f90 const.mod io.mod parallel.mod system.mod
mpifort -c bands.f90 -o $@
const.o : const.f90
mpifort -c const.f90 -o $@
io.o : io.f90 const.mod system.mod
mpifort -c io.f90 -o $@
parallel.o : parallel.f90
mpifort -c parallel.f90 -o $@
polmob.o : polmob.f90 bands.mod const.mod io.mod parallel.mod system.mod
mpifort -c polmob.f90 -o $@
system.o : system.f90 const.mod
mpifort -c system.f90 -o $@
# Rules for ensuring that .mod files are (re)created when needed, and
# that their timestamps do not fall behind those of their corresponding
# sources
bands.mod : bands.o
@if test -f $@; then touch $@; else \
rm -f bands.o; \
$(MAKE) bands.o; \
fi
const.mod : const.o
@if test -f $@; then touch $@; else \
rm -f const.o; \
$(MAKE) const.o; \
fi
io.mod : io.o
@if test -f $@; then touch $@; else \
rm -f io.o; \
$(MAKE) io.o; \
fi
parallel.mod : parallel.o
@if test -f $@; then touch $@; else \
rm -f parallel.o; \
$(MAKE) parallel.o; \
fi
system.mod : system.o
@if test -f $@; then touch $@; else \
rm -f system.o; \
$(MAKE) system.o; \
fi
####
clean:
find . ! -name 'Makefile' -a ! -name '*.f90' -type f -exec rm -f {} +
Это показывает правильные зависимости:
- Основная программа зависит (только) от всех объектов.
- Каждый объект зависит от его собственного источника и файлов
.mod
для тех модулей, которые он использует.
Он также учитывает тот факт, что один и тот же процесс компиляции генерирует как объектный файл, так и (при необходимости) соответствующий файл .mod
, и он заботится об обновлении .mod
отметок времени, когда это необходимо для удовлетворения make
, Это может иногда приводить к перестроению файлов, когда в этом нет особой необходимости, потому что это предотвратит любые попытки компилятора избежать обновления временных меток .mod
файлов. Но это должно быть на разовой основе, а не на каждой последующей сборке.