1. When a file containing a module is compiled,
a "module interface file" (which may or may not
be ASCII) is created, along with the object
file.
2. Other files that "use" the module only have to
be recompiled if this interface file changes;
for example, if the internal coding of module
routines is altered without altering the interfaces,
files containing procedures that USE the module
should not have to be recompiled, but the application
does have to be relinked with the new module object
file.
UNIX systems generally follow the above model; other OS's
may or may not. In any event, we assume in the following
solution that simple UNIX utilities are available.
The key to the solution is as follows. We assume we know
the name of the module interface file(s) that will be created;
these are, in general, OS- and compiler-version- dependent.
If any change is made to a module source file, then, before
recompiling this file, we move its interface file(s) to a
temporary location. After compiling the module source, we
see whether the interface file has changed, by checking the
new against the old one. If it has changed, we remove the
old one. If it has not changed, we overwrite the new one
with the old one, retaining the old creation date. This
prevents files that USE the associated module from being
recompiled.
I should mention that the method proposed here does not work
for parallel makes, since it requires sequential making of
the targets to avoid extra work. In addition, there is
the assumption that the dependencies of a target are made
by "make" in the order listed on the dependency line.
Below, please find the texts of four files:
Makefile
update: script to instantiate old or new module file
try.f90: source for a PROGRAM that USEs MODULE xmod
xmod.f90: source for MODULE xmod
The Makefile is set up to work on SGI machines using the
version 7.2 compilers. On other systems you may have to
alter the Makefile macro definitions.
Following the files, I give instructions for demonstrating to
yourself that this works. It would be interesting to know
if it fails on some systems, and, if so, why.
--------- start Makefile ---------------
MAKESHELL = /bin/sh
SHELL = /bin/sh
FFLAGS = -g -n32
FC = f90
F = f90
X_MOD = XMOD.mod
### Important: module files must come *before* files that
### USE the MODULEs on the program's dependency line:
try: xmod.o try.o
@echo making program try
$(FC) $(FFLAGS) -o try try.o xmod.o
try.o: try.$F $(X_MOD)
@echo making try.o
$(FC) $(FFLAGS) -c try.$F
xmod.o: xmod.$F
@echo making xmod.o
@-mv $(X_MOD) temp > /dev/null 2>&1
$(FC) $(FFLAGS) -c xmod.$F
@-update $(X_MOD) temp
$(X_MOD):
@echo making $(X_MOD)
@-mv $(X_MOD) temp > /dev/null 2>&1
$(FC) $(FFLAGS) -c xmod.$F
@-update $(X_MOD) temp
clean:
rm *.o *.mod
--------- end Makefile ---------------
--------- start update ---------------
#! /bin/sh
# mv the second arg to the first arg if they differ; else do nothing
if cmp $1 $2 > /dev/null 2>&1; then
echo using old $1
mv $2 $1 > /dev/null 2>&1
else
echo using new $1
rm $2 > /dev/null 2>&1
fi
--------- end update ---------------
--------- start try.f90 ---------------
PROGRAM try
USE xmod
WRITE( 6, '(A,F5.3)' )'try: x= ', x
END PROGRAM try
--------- end try.f90 ---------------
--------- start xmod.f90 ---------------
MODULE xmod
REAL :: x=0.123
END MODULE xmod
--------- end xmod.f90 ---------------
To demonstrate:
1. Make from virgin source: from a directory containing
only the above 4 files, say "make". You should see:
making XMOD.mod
*** Error code 2 (bu21) (ignored)
f90 -g -n32 -c xmod.f90
using new XMOD.mod
*** Error code 2 (bu21) (ignored)
making try.o
f90 -g -n32 -c try.f90
making program try
f90 -g -n32 -o try try.o xmod.o
That is, we have made xmod.o, try.o and the program try.
2. Issue the command "touch xmod.f90", then "make". You should see:
making xmod.o
f90 -g -n32 -c xmod.f90
using old XMOD.mod
making program try
f90 -g -n32 -o try try.o xmod.o
That is, since XMOD.mod has not changed, try.o is not remade.
(The "touch" simulates a change to xmod.f90 that does not
affect the interface file.)
3. Edit xmod.f90 and make a change which affects the interface;
for example, add a second variable called "y" to the global
data. Then say "make". You should see:
making xmod.o
f90 -g -n32 -c xmod.f90
using new XMOD.mod
making try.o
f90 -g -n32 -c try.f90
making program try
f90 -g -n32 -o try try.o xmod.o
That is, XMOD.mod has changed, so try.o is remade.
Comments welcome.
-P.
--
**** I used to think the glass was half-full, but now I think it's NT. ****
* Peter S. Shenkin; Chemistry, Columbia U.; 3000 Broadway, Mail Code 3153 *
** NY, NY 10027; she...@columbia.edu; (212)854-5143; FAX: 678-9039 ***
*MacroModel WWW page: http://www.columbia.edu/cu/chemistry/mmod/mmod.html *
>A recurring topic in this newsgroup has been the difficulty
>of using "make" to correctly handle F90 programs that USE
>MODULEe. Here, a method is proposed that achieves this. The
>method isn't terribly pretty, but it works, if the modules
>are handled by the compilation system in the following
>general manner:
[ ... ]
I tried your example and was very surprised that it worked. I just
tried a method very similar to this one the other day and could not get
rid of spurious recompile of the source containing the module. I kept
making $(X_MOD) dependent on xmod.$F, which I realize now is not
necessary since make already builds $(X_MOD) while making xmod.o. I
guess that is also why you say that module files must come before files
that USE the MODULEs on the program's dependency line.
>xmod.o: xmod.$F
> @echo making xmod.o
> @-mv $(X_MOD) temp > /dev/null 2>&1
> $(FC) $(FFLAGS) -c xmod.$F
> @-update $(X_MOD) temp
>$(X_MOD):
> @echo making $(X_MOD)
> @-mv $(X_MOD) temp > /dev/null 2>&1
> $(FC) $(FFLAGS) -c xmod.$F
> @-update $(X_MOD) temp
This part can be shortened to
$(X_MOD):
@echo making $(X_MOD)
$(FC) $(FFLAGS) -c xmod.$F
because this will only run when $(X_MOD) does not exist.
> making XMOD.mod
> *** Error code 2 (bu21) (ignored)
> f90 -g -n32 -c xmod.f90
> using new XMOD.mod
> *** Error code 2 (bu21) (ignored)
If you want to get rid of these annoying error messages, you could
replace
@-mv $(X_MOD) temp > /dev/null 2>&1
with
@mv $(X_MOD) temp > /dev/null 2>&1 || :
since you are running the Bourne shell /bin/sh. This will run the
command ':' (which does nothing) if mv returns a non-zero return code.
Then the return code that make will see will be the one returned by ':',
which is always 0. You could do the same thing inside update.
--
Michel Beland bel...@CERCA.UMontreal.CA
professionnel de recherche tel: (514)369-5223 fax: (514)369-3880
CERCA (CEntre de Recherche en Calcul Applique)
5160, boul. Decarie, bureau 400(423), Montreal (Quebec), Canada, H3X 2H9
--
Michel Beland bel...@CERCA.UMontreal.CA
professionnel de recherche tel: (514)369-5223 fax: (514)369-3880
CERCA (CEntre de Recherche en Calcul Applique)
5160, boul. Decarie, bureau 400(423), Montreal (Quebec), Canada, H3X 2H9
:-), :-).
> >$(X_MOD):
> > @echo making $(X_MOD)
> > @-mv $(X_MOD) temp > /dev/null 2>&1
> > $(FC) $(FFLAGS) -c xmod.$F
> > @-update $(X_MOD) temp
>
> This part can be shortened to
>
> $(X_MOD):
> @echo making $(X_MOD)
> $(FC) $(FFLAGS) -c xmod.$F
>
> because this will only run when $(X_MOD) does not exist.
Yup; thanks.
> > making XMOD.mod
> > *** Error code 2 (bu21) (ignored)
> > f90 -g -n32 -c xmod.f90
> > using new XMOD.mod
> > *** Error code 2 (bu21) (ignored)
>
> If you want to get rid of these annoying error messages, you could
> replace
>
> @-mv $(X_MOD) temp > /dev/null 2>&1
>
> with
>
> @mv $(X_MOD) temp > /dev/null 2>&1 || :
>
> since you are running the Bourne shell /bin/sh. This will run the
> command ':' (which does nothing) if mv returns a non-zero return code.
> Then the return code that make will see will be the one returned by ':',
> which is always 0. You could do the same thing inside update.
Cool. Thanks for this, too.