[Cook] cook and Fortran 90/95 USE/MODULE statements

Larry Wagner wagner at weru.ksu.edu
Sat Dec 6 08:46:16 EST 2003


I am having some issues with cook and Fortran 90/95 USE and
MODULE statements.  Some I have worked through and some
I have gotten stumped on.

Currently, the problem I am having is getting cook to correctly
build my code from scratch.  Currently I have had to resort to
creating a build script to compile the src code containing the
Fortran module definitions first in the correct order.

I know it has something to do with my cookfile not knowing that
the src files containing the module definitions must be compiled
first so that the module files themselves exist for the other src
files to "USE" them.  The Cook User's Manual mentions "dependencies
on derived files", which is what the Fortran module files are,
but it doesn't provide enough of an explanation for me to figure
out how to fix my problem.

I get the following warning message(s) once I have "manually" created
the intermediate module files first, which obviously is telling me
that I don't have something correct.  Here is an example:

cook:  warning: the ``prog1/main.obj: subroutine1.mod;'' recipe is only in 
prog1/main.f95.d

If someone can provide some pointers on how to correctly handle
Fortran MODULES with cook, or had example cook code that they use, 
I'd appreciate it.

I've included as an attachment the cookfile and an example Fortran
source tree which I've been using as a test case.  It works under
the Cygwin environment on a PC using the Lahey Fortran 95 compiler.



Additional info for those interested ...

As best I can explain, Fortran 90/95 code can encapsulate data and
procedures into "modules".  Code containing a MODULE statement
will produce both a Fortran MODULE file and an object file
when compiled.  Any Fortran 90/95 source file can access the
data or procedures if they include a "USE module_name" statement.

So, a Fortran 90/95 src file may be dependent upon INCLUDE and/or
MODULE files (if INCLUDE and/or USE statements exist in the src file)
to be compileable.  However, the Fortran 90/95 src file containing
the module definition (contains MODULE module_name statements) must
have been compiled first so that the module filename exists for the
src file "USE"ing it can be compiled.

I have tried to create a recipe describing the dependency between
the module filename and it's Fortran 90/95 src file as such and
putting it ahead of the object file recipe, e.g:

M = .mod;	!module filename extension
F = .f95;	!Fortran 95 src filename extension
O = .obj;	!object filename extension
I = .inc;	!include filename extension
D = .dep;	!cook dependency filename extension

/* Note that compiler is putting all module files into the root dir */
%1[M]: [match_mask %%0%/%1[F] [module_src_files]];
{
	run compiler to create both the object and module files
}

%0%[O]: %0%[F]
{
	run compiler to create object files
}

In addition, I've created recipes to create and maintain the
following cook dependency files:

%0%[F][D]: %0%[F]
	set nocascade
{
	create dependency file for src files (both INCLUDE and USE)
}

%0%[I][D]: %0%[I]
	set nocascade
{
	create dependency file for include files
}


One thing that I was wondering about is if I can consolidate
any recipes together where the dependent src file can have
multiple targets, e.g. an object file and possibly a module
file.  If so, and if it would be a better approach, how would I
do this?  

Thanks,

LEW

Larry Wagner, Agricultural Engineer | E-mail: wagner at weru.ksu.edu
USDA-ARS Wind Erosion Research Unit | phone:  (785) 537-5544
1515 College Ave.                   | fax:    (785) 537-5507
Manhattan, KS 66502                 | URL:    http://www.weru.ksu.edu
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/octet-stream
Size: 4931 bytes
Desc: example.tar.gz
URL: <http://lists.auug.org.au/pipermail/cook-users/attachments/20031205/34f93b70/attachment.obj>
-------------- next part --------------
/* Example cookfile */
/* Currently runs with Lahey Fortran 95 compiler under Cygwin environment */

/* Lahey Fortran Compiler (Windows version 5.7) */
	fc = lf95;			/* Fortran 95 compiler */
	fc_flags = -nco;		/* do not display compiler option settings */
	fc_flags += -chk;		/* subscript bounds checking */
	fc_flags += -stchk;		/* stack checking */
	fc_flags += -in;		/* declare type of all symbols */
	fc_flags += -w;			/* issue warnings and informational messages */
	fc_flags += -trace;		/* generate traceback if error */
	fc_dflags = ;			/* compiler debug flags */

	ar = lm;			/* Library archiver */
	ar_flags = ;			/* archiver flags */

	ld = lf95;			/* Linker */
	ld_flags = -nobanner;		/* operate linker quietly */
	ld_flags += -twocase;		/* enables case-sensitive symbols */
	ld_flags += -nomap;		/* no link map generated */
	ld_flags += -warn;		/* enable warnings */
	ld_dflags = ;			/* linker debug flags */
	ld_libs = ;

	/* Filename extension suffixes (and prefixes) */
	LIB = ;				/* Library filename prefix */
	A = .lib;			/* Library files */
	O = .obj;			/* Object files */
	E = .exe;			/* Executable files */
        F = .f95;			/* Fortran 95 source files */
        D = .d;				/* cook created dependency files */
        I = .inc;			/* Fortran 95 INCLUDE files */
        M = .mod;			/* Fortran 95 MODULE files */


/* obtain list of all files in project (*.f95 *.inc, etc.) */
manifest = [fromto ./%0% %0% [collect find . ! -type d -print] ];
	/* function print "manifest list is: " [manifest]; */

/* obtain list of all src files */
all_src = [match_mask %0%[F] [manifest]];
	/* function print "all source files are: " [all_src]; */


/* obtain list of all Fortran module src files */
mod_src = [shell grep -i -l '"^[ 	]*MODULE"' [all_src] ];
	/* function print "all module source files are: " [mod_src]; */

	/* function print "module src filename:module name(s) pairs:" */
        /* function print [shell grep -i '"^[ 	]*MODULE"' [all_src] ]; */

/* find all Fortran module names */
mod_names = [shell
		grep -i '"^[ 	]*MODULE"' [mod_src]
                |
                sed -e '"s,[ 	]*\!.*,,"'
                    -e '"s,^.*:[ 	]*,,"'
                    -e '"s,[Mm][Oo][Dd][Uu][Ll][Ee][ 	]*,,"'
                -
               ];
	/* function print "all module names are: " [mod_names]; */

/* create list of module filenames based on module names */
mod_files = [addsuffix [M] [mod_names]];
	/* function print "all module files are: " [mod_files]; */


/* find the dependency files from the manifest */
/* and "magically include them (#include-cooked) */
dep-files =
	[addsuffix [D]
		[match_mask %0%[F] [manifest] ]
		[match_mask %0%[I] [manifest] ]
	];
	/* function print "dependency files are: " [dep-files]; */
#include-cooked [dep-files]


/* find all the object files from the manifest */
all_obj = [fromto %0%[F] %0%[O] [match_mask %0%[F] [manifest] ] ];
	/* function print "all object files are: " [all_obj]; */


/* find all the library object files from the manifest */
libf/[LIB]libf[A]_obj =
	[fromto %0%[F] %0%[O]
		[match_mask libf/%0%[F] [manifest] ]
	];
	/* function print "library obj files: " [libf/[LIB]libf[A]_obj]; */


/* find all the program files from the manifest */
programs =
	[fromto %/main[F] %[E]		/* add .exe extension if necessary */
		[match_mask %/main[F] [manifest] ]
	];
	/* function print "The program files are: " [programs]; */

program_roots = [fromto %0%[E] %0% [programs]];	/* remove .exe extension */
	/* function print "The program file roots are: " [program_roots]; */

/* determine all the src files (and libraries) */
/* needed for each program (exe) file from the manifest */
/* Note the need for temporary variables as they get destroyed in the loop */

tmp_program_list = [program_roots];	/* no .exe extension */
loop
{
	tmp_program = [head [tmp_program_list]];
	if [not [count [tmp_program]]] then
		loopstop;
	/* remove first (leading) program from list each time through loop */
	tmp_program_list = [tail [tmp_program_list]];

	bin/[tmp_program]_obj =
		[fromto %0%[F] %0%[O]
			[match_mask [tmp_program]/%0%[F] [manifest]]
		]
		libf/[LIB]libf[A]  /* lib and it's path now include in recipe */
		;
	
	
	/* function print "obj and lib files for each program are: " [bin/[tmp_program]_obj]; */
}


/************** RECIPE section *********************/

/* recipe to build f95 "dependency" files (with USE statements) */
%0%[F][D]: %0%[F]
	set nocascade
{
        sed -e '"s,[U,u][S,s][E,e][ 	]*\\([a-z,_,A-Z,0-9,\.,\-,=,\,]*\\),include \\1.mod,"' %0%[F] |
	c_incl -nc -ns -nrec -asm "--l=optimistic"
		-I. -I [dirname %0%[F]] -Iinclude
		-prefix "'cascade %0%'"[F]"' ='"
		-suffix "';'"
		-o [target] -;
}

/* 
/* This is for when c_incl gets extended to handle USE statements */
%0%[F][D]: %0%[F]
	set nocascade
{
	c_incl -nc -ns -nrec -asm "--l=f95"
		-I [dirname %0%[F]] -Iinclude
		%0%[F]
		-prefix "'cascade %0%'"[F]"' ='"
		-suffix "';'"
		-o [target];
}
*/

/* recipe to build include "dependency" files */
/* Not worrying about "USE" statements include files right now */
%0%[I][D]: %0%[I]
	set nocascade
{
	c_incl -nc -ns -nrec "--l=optimistic"
		-I. -I[dirname %0%[I]] -Iinclude
		%0%[I]
		-prefix "'cascade %0%'"[I]"' ='"
		-suffix "';'"
		-o [target];
}

/* --------------------------------------------------------------- */

/* compilation, library and link build recipes */

/* recipe to build "mod" files */
%1[M]: [match_mask %%0%%/%1[F] [mod_src]]
{
	/*
        function print "in mod recipe: " %1[M];
        function print "[match_mask %%0%%/%1[F] [mod_src]]:" [match_mask %%0%%/%1[F] [mod_src]];
        function print "in mod recipe [target]:" [target];
	*/
        src_file = [match_mask %%0%%/%1[F] [mod_src]];
        if [matches [target] [mod_files]] then
        {
	   [fc] [fc_flags]
		-I \"[dos-path [dirname [src_file]]]\;include\"
		-c [src_file] 
		-o [addsuffix [O] [basename [src_file]]];
        }
}

/* recipe to build "mod" files - Doesn't work */
/* [need] expands to include both the f95 src file AND any modules "USED" in the src file */
/* (can't compile a .mod file) */
/*
%1[M]: [match_mask %%0%%/%1[F] [mod_src]]
{
        function print "in mod recipe: " %1[M];
        function print "[match_mask %%0%%/%1[F] [mod_src]]:" [match_mask %%0%%/%1[F] [mod_src]];
        function print "in mod recipe [target]:" [target];
        function print "in mod recipe [resolve [need]]:" [resolve [need]];
        function print "in mod recipe: " [mod_files];
        if [matches [target] [mod_files]] then
        {
	   [fc] [fc_flags]
		-I \"[dos-path [dirname [resolve [need]]]]\;include\"
		-c [resolve [need]] 
		-o [addsuffix [O] [basename [resolve [need]]]];
        }
}
*/

/* recipe to build "mod" files - works, but one above is cleaner  */
/*
%1[M]:
{
	/*
        function print "in mod recipe: " %1[M];
        function print "in mod recipe: " [target];
        function print "in mod recipe: " [mod_files];
	*/
        if [matches [target] [mod_files]] then
        {
           src_file = [word [in [target] [mod_files]] [mod_src]];
           obj_file = [addsuffix [O] [basename [src_file]]];
           /* function print "in mod recipe: " [src_file] [obj_file]; */

	   [fc] [fc_flags]
		-I \"[dos-path [dirname [src_file]]]\;include\"
		-c [src_file] 
		-o [obj_file];
        }
}
*/

/* recipe to build "obj" files */
%0%[O]: %0%[F]
{
        /* function print "in obj build recipe: " [target]; */
	[fc] [fc_flags]
		-I \"[dos-path [dirname %0]]\;include\"
		-c %0%[F]
		-o [target];
}

/* recipe to build "library" files */
/* had to add "libf" to keep from accessing non-existant variables */
/* Used loop to add object files to library to keep commandline from getting too long */
libf/[LIB]%[A]: [[target]_obj]
	set unlink
{
        /* function print "in library build recipe"; */
	tmp_target_obj_list = [[target]_obj];
	loop
	{
		tmp_target_obj = [head [tmp_target_obj_list]];
		if [not [count [tmp_target_obj]]] then
			loopstop;
		/* remove first (leading) obj from list each time through loop */
		tmp_target_obj_list = [tail [tmp_target_obj_list]];

		[ar] [subst \\ \\\\ [dos-path [target]]] -+[tmp_target_obj]\\\;;
	}
}

/* recipe to build "binary" files (programs) */
bin/%: [[target]_obj] libf/[LIB]libf[A]
	set mkdir
{
	 function print "In binary build recipe";
	 function print "[[target]_obj]:" [[target]_obj]; 
	 function print "[target]:" [target]; 
	[fc] [fc_flags]
		[ld_flags]
		 -out [target][E] [[target]_obj]
		/* currently [[target]_obj] includes the library */
		/* thus, libf/[LIB]libf[A] is redundant as an ingredient */
		/* don't know if that is what I really want though */
		/*
		 -libpath libf
		 -lib [LIB]libf[A]
		*/
	;
}	

/************** TARGET section *********************/

/* tell cook to build all "programs" */

all: [addprefix bin/ [program_roots]];

test:
{
	function print "[addprefix bin/ [programs]] " [addprefix bin/ [programs]];
	function print "[addprefix bin/ [program_roots]] " [addprefix bin/ [program_roots]];
}


clean:			/* get all intermediate and binary files */
{
	rm -f [addprefix bin/ [programs]] [all_obj] [mod_files]
	set clearstat;
}

clobber: clean	/* get those dependency files as well */
{
	rm -f [dep-files] libf/[LIB]libf[A]
	set clearstat;
}


More information about the Cook-users mailing list