JiscMail Logo
Email discussion lists for the UK Education and Research communities

Help for COMP-FORTRAN-90 Archives


COMP-FORTRAN-90 Archives

COMP-FORTRAN-90 Archives


COMP-FORTRAN-90@JISCMAIL.AC.UK


View:

Message:

[

First

|

Previous

|

Next

|

Last

]

By Topic:

[

First

|

Previous

|

Next

|

Last

]

By Author:

[

First

|

Previous

|

Next

|

Last

]

Font:

Monospaced Font

LISTSERV Archives

LISTSERV Archives

COMP-FORTRAN-90 Home

COMP-FORTRAN-90 Home

COMP-FORTRAN-90  2003

COMP-FORTRAN-90 2003

Options

Subscribe or Unsubscribe

Subscribe or Unsubscribe

Log In

Log In

Get Password

Get Password

Subject:

Re: autodependencies of fortran code on include, modules, etc.

From:

Ted Stern <[log in to unmask]>

Reply-To:

Fortran 90 List <[log in to unmask]>

Date:

Thu, 3 Apr 2003 08:37:55 -0800

Content-Type:

multipart/mixed

Parts/Attachments:

Parts/Attachments

text/plain (41 lines) , mkdepf90.perl (429 lines)

On 3 Apr 2003, Bennie F. Blackwell wrote:
>I recently ported a F77 code from a unix (Sun OS) to a PC (cygwin with
>Absoft compiler). The code uses "include" to bring in the common blocks.
>While the make utility on the Sun side was smart enough to recompile when
>you touched one of the include files, the gnu make on the pc was not. The
>make file does not have any explicit dependence of the .f files on the
>include files. This got me to thinking that I will have exactly the same
>problem with some F90 code using modules I am developing. For c code, I
>found the following two web sites that document how to solve this problem:
>
>http://www.cs.berkeley.edu/~smcpeak/autodepend/autodepend.html
><http://www.cs.berkeley.edu/~smcpeak/autodepend/autodepend.html>
>http://make.paulandlesley.org/autodep.html
><http://make.paulandlesley.org/autodep.html>
>
>Is anyone aware of a similar work around for F77/F90 code? Of course, you
>can hard-code the make file with the proper dependencies of every routine
>but this would be very error prone.
>
>Thanks,
>
>Ben

Hi Ben,

See the attached mkdepf90.perl file. I have an idiosyncratic way of using GNU
make, but you should probably be able to figure out what I'm doing with it
once you try it on a couple of examples.

See also the various references in the comments at the top of the file.

Ted
--
 Ted Stern Engineering Applications
 Cray Inc. office: 206-701-2182
 411 First Avenue South, Suite 600 cell: 206-383-1049
 Seattle, WA 98104-2860 FAX: 206-701-2500
 Debuggers' motto: Frango ut patefaciam -- I break in order to reveal



#!/usr/bin/perl -w
#
# $Id: mkdepf90.perl,v 1.29 2002/04/17 19:31:57 stern Exp $
# Author: Ted Stern <[log in to unmask]>
#
# Usage:
#
# mkdepf90.perl \
# -src srcfile \
# [-uc] \
# [-objdir objdir] \
# [-moddir moddir] \
# [-depdir depdir] \
# [-mdeps mdepsfile] \
# [-odeps odepsfile]
#
# - Intended for use with GNU Make versions 3.79.1 and higher.
#
# - Generates macros, target rules, and dependency listings for f90 files
# that USE or define modules.
#
# - Intended for one source file at a time. For example, use in a Makefile
# with the following pattern rule and include statement:
#
# $(OBJDIR)/%.f90mdeps $(OBJDIR)/%.f90odeps: $(SRCDIR)/%.f90
# $(PERL) -w mkdepf90.perl -src $< -objdir $(@D)
#
# # include module and object macro definitions and
# # module dependencies:
# include $(F90_objs:.o=.f90mdeps)
#
# # include extra object dependencies:
# include $(F90_objs:.o=.f90odeps)
#
# - It doesn't matter if the object directory has a trailing slash or not.
#
# - Use "-uc" option to upcase module basenames. Default is to downcase.
# The only platform that requires -uc, to my knowledge, is Cray UNICOS.
#
# - "mdeps" stands for module dependency listings,
# "odeps" stands for object dependency listings.
# These are separated just in case objects are not all placed in a single
# directory. If mdeps files are all read in before odeps files, all
# required macro definitions will have been made for the odeps dependencies
# to resolve correctly.
#
# - Order of arguments is unimportant.
#
# - NOTE: if -objdir is provided, objdir is the default directory in which
# the module and object dependency files will be created, unless their
# output locations are specified explicitly using -mdeps and/or
# -odeps.
#
# Acknowledgements:
# Cribbed basic dependency text-processing logic from makemake.perl[1],
# with argument parsing idea from fmkmf[4] but with clearer switch construct.
# [2] provided the idea of using macros for the object and module names, and
# Daniel Grimwood[2] also helped by providing feedback, counterexamples, and
# tests of various schemes.
#
# References:
# [1] http://www.fortran.com/makemake.perl
# [2] http://www.theochem.uwa.edu.au/fortran/recompile/
# [3] http://www.helsinki.fi/~eedelman/makedepf90.html
# [4] http://www.met.ed.ac.uk/~hcp/fmkmf.html
# [5] http://www.gfdl.gov/~vb/mkmf.html
# [6] http://www.canb.auug.org.au/~millerp/rmch/recu-make-cons-harm.html
# [7] http://www.paulandlesley.org/gmake/
#
#-----------------------------------------------------------------------
# Implementation comments:
#
# A GNU MAKE target-specific variable $(byproduct) is defined so that an
# f90 object knows what its module byproduct files are.
#
# Example of simple output for no OBJDIR and no modules created:
#
# mkdepf90.perl -src filename.f90
#
# output in filename.f90rule:
#
# # Variable containing the full path to the object:
# filename.o := filename.o
#
# output in filename.f90deps:
#
# # Extra dependencies of the obj file:
# $(filename.o): $(A_DEF.mod) file1.h file2.inc
#
# Example of complex case with -objdir specified, multiple modules created,
# and multiple module and include dependencies:
#
# mkdepf90.perl -uc -src complex_def.f90 -objdir $(OBJDIR)/indep/c/
#
# output in $(OBJDIR)/indep/c/complex_def.f90mdeps:
#
# # Using objdir $(OBJDIR)/indep/c/ from cmd line
# # Variable containing the full path to the object:
# complex_def.o := $(OBJDIR)/indep/c/complex_def.o
#
# # For each defined module, define the dir-stripped module name
# # as the full path to the generated module:
# A_DEF.mod := $(OBJDIR)/indep/c/A_DEF.mod
#
# B_DEF.mod := $(OBJDIR)/indep/c/B_DEF.mod
#
# # Variable containing the complete list of generated modules:
# complex_def.o.mods := $(A_DEF.mod) $(B_DEF.mod)
#
# # Target-specific variable:
# # byproduct = modules associated with the main object:
# $(complex_def.o) : byproduct := $(complex_def.o.mods)
#
# output in $(OBJDIR)/indep/c/complex_def.f90odeps:
#
# # Extra dependencies of the obj file:
# $(complex_def.o): $(C_DEF.mod) $(D_DEF.mod) $(E_DEF.mod) \
# $(F_DEF.mod) file1.h file2.inc file3.inc
#
#-----------------------------------------------------------------------
# Argument parsing. Set defaults:
$argerr=0;
$argerr=1 if ($#ARGV+1==0);

undef $filename;
undef $mdepsfile;
undef $odepsfile;

$ModCase=DnCase; # default is to dncase .mod file basename
$objdir = "";
$moddir = "";
$depdir = "";
$mod_ext="mod";

while (@ARGV) {
    $arg=shift;
    SWITCH: for ($arg) {
        /^-uc$/ && do { $ModCase=UpCase; last; };
        /^-src$/ && do { $filename=shift; last; };
        /^-objdir$/ && do { $objdir=shift; last; };
        /^-moddir$/ && do { $moddir=shift; last; };
        /^-depdir$/ && do { $depdir=shift; last; };
        /^-mdeps$/ && do { $mdepsfile=shift; last; };
        /^-odeps$/ && do { $odepsfile=shift; last; };
        /^-mod_ext$/ && do { $mod_ext=shift; last; };
        $argerr=1;
        warn "\nUnexpected arg $arg\n";
    }
}

defined $filename || do {
    $argerr=1; warn "\nError : -src filename not supplied.\n"
};

# We need the filename, at least!
if ( $argerr==1 ) {
    die(
        "\nUsage :\n",
        "\t perl -w ./mkdepf90.perl -src srcfile \\\n",
        "\t\t[-uc] \\\n",
        "\t\t[-mod_ext ext] \\\n",
        "\t\t[-objdir objdir] \\\n",
        "\t\t[-moddir moddir] \\\n",
        "\t\t[-depdir depdir] \\\n",
        "\t\t[-mdeps mdepsfile] \\\n",
        "\t\t[-odeps odeps_file],\n",
        "\n",
        "Where :\n",
        "\t-src srcfile\t: \"srcfile\" is the source file to be parsed.\n",
        "\t-uc\t\t: .mod filenames are to be uppercased (e.g., for UNICOS).\n",
        "\t-mod_ext ext\t: \"ext\" is the module file extension.\n",
        "\t\t\t Default extension is \"mod\".\n",
        "\t-objdir objdir\t: \"objdir\" is the object file location,\n",
        "\t\t\t and the default directory destination for module files\n",
        "\t\t\t and dependency files output by this script.\n",
        "\t\t\t A trailing slash may be included but is not required.\n",
        "\t-moddir moddir\t: \"moddir\" is the module file location,\n",
        "\t-depdir depdir\t: \"depdir\" is the default destination directory for\n",
        "\t\t\t the dependency files output by this script.\n",
        "\t-mdeps mdepsfile: \"mdepsfile\" is the module dependency file.\n",
        "\t-odeps odepsfile: \"odepsfile\" is the object dependency file.\n",
        "\n",
        "Notes :\n",
        "\tDependency output is split into two files:\n",
        "\t\tmdepsfile (module & object macros + module dependencies), and\n",
        "\t\todepsfile (object dependencies).\n",
        "\n",
        "\tDefault mdeps and odeps files are sent to objdir with same base\n",
        "\tas src file, with .f90mdeps and .f90odeps extensions, respectively.\n",
        "\tIf you don't like those extensions, use -mdeps and/or -odeps.\n",
        "\n",
        "\tYou can change the dependency file destination directory using\n",
        "\tthe -depdir option, or specify the destination files explicitly\n",
        "\tusing the -mdeps or -odeps options.\n",
        "\n",
        "\t-mdeps and -odeps specifications override -depdir.\n",
        "\n");
}

# Get the base part of the filename (remove everything after last .):
($base = $filename) =~ s/\.[^\.]+$//;
# Strip everything up to last slash:
$base =~ s/^.*\///;

# Extract the object directory prefix from what was passed in:
$objdir = &SetPrefix($objdir);

# Set the module directory prefix, using the object directory as the default
if ( $moddir ) {
    $moddir = &SetPrefix($moddir);
} else {
    $moddir = $objdir;
}

# Set the dependency file prefix, using the object directory as the default
if ( $depdir ) {
    $depdir = &SetPrefix($depdir);
} else {
    $depdir = $objdir;
}

# Define default mdeps filename if not provided
defined $mdepsfile || do {
    ($mdepsfile = $base) =~ s/.*/$depdir$&.f90mdeps/;
};

# Define default odeps filename if not provided
defined $odepsfile || do {
    ($odepsfile = $base) =~ s/.*/$depdir$&.f90odeps/;
};

# $objbase defined as the directory-stripped object file name with
# a .o extension:
($objbase = $base) =~ s/$/.o/;

# $objfile defined as $objbase prefixed with the objdir.
# $objfile = $objbase;
# defined $prefix && do { $objfile =~ s/^/$prefix/; };
($objfile = $objbase) =~ s/^/$objdir/;

open(FILE, $filename) or die "Cannot open -src file $filename: $!\n";

unlink $mdepsfile;
open(OUTFILE,">" . $mdepsfile) or
    die "Can't write module dependencies file \n\t$mdepsfile -- check directory or perms.\n";

# Search for includes and USE calls:
undef @incs;
undef @modules;
undef @moddefs;

while (<FILE>) {
    /^\s*(\#|\?\?)*\s*include\s+[\"\']([^\"\']+)[\"\']/i && push(@incs, $2);
    /^\s*use\s+([^\s,!]+)/i && push(@modules, &$ModCase($1));
    # Make sure we don't mistakenly grab "module procedure" lines:
    /^\s*module\s+([^\s,!]+)/i &&
        (lc($1) ne "procedure") &&
        push(@moddefs, &$ModCase($1));
}

# Define the MAKE macro $($objbase) as the full path to
# the object. E.g., 'foo.o = /path/to/foo.o'
print OUTFILE
    "# MAKE variable containing full path to object:\n",
    "$objbase := $objfile\n\n";

# If modules are defined, create macros for modules and
# a combined object+module target rule:
undef @modlist;

defined @moddefs && do {
    # @modlist stores module names with .mod on the end
    foreach $module (&Uniq(sort(@moddefs))) {
        ($name = $module) =~ s/$/.$mod_ext/;
        push(@modlist, $name);
    }

    # Redefine @moddefs to the new @modlist
    @moddefs = @modlist;

    # Redefine @modlist with each element of @moddefs surrounded by
    # MAKE parens:
    undef @modlist;
    foreach $module (@moddefs) {
      ($name = $module) =~ s/.*/\$\($&\)/;
      push(@modlist, $name);
    }

    print OUTFILE "# For each module, define dir-stripped module name\n";
    print OUTFILE "# as the full path to the generated module:\n";
    foreach $module (@moddefs) {
        # Define the MAKE macro $(modnamebase.mod) as the full path to the
        # module
        print OUTFILE "$module := $moddir$module\n\n";
    }

    # This defines the macro $(objbase.o.mods) as the list of
    # modules dependent on the object.
    print OUTFILE "# MAKE Variable containing list of generated modules:\n";
    print OUTFILE "$objbase.mods := ";
    $j = length($objbase) + 9;

    &PrintWords($j, 0, @modlist);
    print OUTFILE "\n\n";

    # Make sure .mod files depend on the object file:
    print OUTFILE "# Define main obj as prereq for module files:\n";
    print OUTFILE "\$($objbase.mods): \$($objbase)\n\n";

    # Print out a target specific variable:
    print OUTFILE "# Target-specific variable:\n";
    print OUTFILE "# byproduct := modules associated with the main obj:\n";
    print OUTFILE "\$($objbase): byproduct := \$($objbase.mods)\n\n";
};

# Stop writing to mdeps file, start writing to odeps file:
close(OUTFILE);
unlink $odepsfile;
open(OUTFILE,">" . $odepsfile) or
    die "Can't write object dependencies file\n\t$odepsfile -- check directory or perms.\n";

# Print out extra dependencies for the object file beyond the default:
undef @dependencies;

defined @modules && do {
    foreach $module (&Uniq(sort(@modules))) {
        ($name = $module) =~ s/.*/\$\($&.$mod_ext\)/;
        push(@dependencies, $name);
    }
};

defined @incs && do {
    push(@dependencies, &Uniq(sort(@incs)));
};

defined @dependencies && do {
    print OUTFILE "# Extra dependencies of the obj file:\n";
    print OUTFILE "\$($objbase): ";
    $j = length($objbase) + 5;
    &PrintWords($j, 0, @dependencies);
};

print OUTFILE "\n"; # Add newline to .deps file
close(OUTFILE);

# End of processing. Below are utility routines:
#-----------------------------------------------------------------------
# Internal text formatting functions, copied (with some modifications)
# from makemake.perl.
#-----------------------------------------------------------------------
# &PrintWords(current output column, extra tab?, word list); --- print words
# nicely
#
sub PrintWords {
    my $columns = 78 - shift(@_);
    my $extratab = shift(@_);
    my $wordlength;
    #
    print OUTFILE "$_[0]";
    $columns -= length(shift(@_));
    foreach $word (@_) {
        $wordlength = length($word);
        if ($wordlength + 1 < $columns) {
            print OUTFILE " $word";
            $columns -= $wordlength + 1;
        }
        elsif ($extratab) {
            #
            # Continue onto a new line
            #
            print OUTFILE " \\\n\t\t$word";
            $columns = 62 - $wordlength;
        }
        else {
            print OUTFILE " \\\n\t$word";
            $columns = 70 - $wordlength;
        }
    }
}

# The only reason to define the following routines is so that I can
# set up a function pointer to them. If you know how to set up a function
# pointer to a perl intrinsic, please let me know! -- Ted

#-----------------------------------------------------------------------
# &UpCase(string); --- convert string to upper case
#
sub UpCase {
    return uc($_[0]);
}

#-----------------------------------------------------------------------
# &DnCase(string); --- convert string to lower case
#
sub DnCase {
    return lc($_[0]);
}

#-----------------------------------------------------------------------
# &Uniq(sorted word list); --- remove adjacent duplicate words
#
sub Uniq {
    my @words = (shift(@_)); # initialize @words with first argument
    foreach $word (@_) {
        if ($word ne $words[$#words]) {
            push(@words, $word);
        }
    }
    return @words;
}

#-----------------------------------------------------------------------
# &SetPrefix(directory); --- cleans up directory for use as a prefix
#
sub SetPrefix {
    my $dir = $_[0];
    my $prefix = "";
    if ( $dir ) {
        $dir =~ s/\/*\.$//; # ignore trailing "/."
        $dir =~ s/^\.\/*//; # ignore leading "./"
        $dir =~ s/\/*$//; # remove trailing slashes
        $dir =~ s/^\.$//; # ignore "." directory
        # set $prefix to the object directory with a trailing slash
        if ( $dir ) { ($prefix = $dir) =~ s/$/\//; }
    }
    return $prefix;
}

Top of Message | Previous Page | Permalink

JiscMail Tools


RSS Feeds and Sharing


Advanced Options


Archives

December 2023
February 2023
November 2022
September 2022
February 2022
January 2022
June 2021
November 2020
September 2020
June 2020
May 2020
April 2020
December 2019
October 2019
September 2019
March 2019
February 2019
January 2019
November 2018
October 2018
September 2018
August 2018
July 2018
May 2018
April 2018
March 2018
February 2018
January 2018
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
December 2015
November 2015
October 2015
September 2015
August 2015
June 2015
April 2015
March 2015
January 2015
December 2014
November 2014
October 2014
August 2014
July 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013
July 2013
June 2013
May 2013
April 2013
February 2013
January 2013
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
April 2012
March 2012
February 2012
January 2012
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
December 2010
November 2010
October 2010
August 2010
July 2010
June 2010
March 2010
February 2010
January 2010
December 2009
October 2009
August 2009
July 2009
June 2009
March 2009
February 2009
January 2009
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
January 2007
2006
2005
2004
2003
2002
2001
2000
1999
1998
1997


JiscMail is a Jisc service.

View our service policies at https://www.jiscmail.ac.uk/policyandsecurity/ and Jisc's privacy policy at https://www.jisc.ac.uk/website/privacy-notice

For help and support help@jisc.ac.uk

Secured by F-Secure Anti-Virus CataList Email List Search Powered by the LISTSERV Email List Manager