Кто-нибудь знает, что может быть причиной такого поведения?
Я нашел причину: если я заменю "mod" на "o" везде в моем Makefile, проблема исчезнет. Однако я не совсем понимаю, почему.
Единственное правдоподобное объяснение состоит в том, что временные метки существующих .mod
файлов не обновляются при пересборке исходных кодов. Я предполагаю, что это распространяется только до тех пор, пока интерфейс модуля неизменен, т. е. никакие функции или подпрограммы не добавляются, не удаляются или не изменяются таким образом, который влияет на их внешний интерфейс, и аналогичным образом никакие переменные модуля не добавляются, не удаляются или не изменяются в типе. .
Я вижу, что желательно избегать обновления .mod
файлов, когда в них ничего не изменилось, особенно в сочетании с реализациями модулей, хранящимися во внешних библиотеках. Однако, насколько мне известно, не существует общей стандартизации даже существования файлов .mod
, не говоря уже об обстоятельствах, при которых они создаются или обновляются. Ваш компилятор может предложить опцию, которая заставляет их обновляться при компиляции соответствующего исходного кода; если это так, то добавление этой опции в ваши команды компиляции должно решить вашу проблему.
В противном случае ваш компилятор делает наверняка обещает, что если вы попросите его скомпилировать исходный файл в объектный файл, то в случае успеха он напишет новый объектный файл. Более того, хотя я не обязательно догадался бы, что то же самое будет неверно для файлов .mod
, важно понимать, что последние обычно описывают интерфейсы к вашим модулям, а не их реализации< /strong>, поэтому ваше основное правило семантически неверно:
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-файл while следующим образом:
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-файл).
Альтернативой является создание отдельных объектов, а затем их связывание на отдельном шаге. Ваш исходный файл makefile, кажется, склоняется в этом направлении, но затем он отбрасывает его с помощью основного правила. Если вы хотите использовать такой подход, то он усложняется тем фактом, что
- на самом деле это модуль interfaces, от которого зависят отдельные объекты (в дополнение к их собственным источникам), поэтому выражение предварительных условий в терминах других объектных файлов в этих случаях некорректно;
- оба файла
.o
и .mod
создаются одним и тем же процессом (т.е. он имеет несколько выходных данных);
- и, по-видимому, этот процесс использует другую логику, чем
make
, чтобы определить, устарели ли файлы .mod
.
Проблема с несколькими выходами, вероятно, самая сложная; вы можете найти обсуждение и альтернативные решения различной строгости в Automake документации (но не для Automake).
Вот способ, которым вы могли бы подойти к этому, вдохновленный документами Automake, но с учетом особенности, которую вы обнаружили в своей реализации Fortran:
# 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
файлов. Но это должно быть единовременно, а не при каждой последующей сборке.
person
John Bollinger
schedule
13.05.2019