summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2005-08-21 01:06:51 (GMT)
committerSteven Knight <knight@baldmt.com>2005-08-21 01:06:51 (GMT)
commit93e408515a55593b0c27f39220e4aa37131d1f0d (patch)
tree84159b19bcf3c181e22e142162b06487f2a2f61b
parentc5f5ba58f1c8b4927ee22e3781a19c334352aa45 (diff)
downloadSCons-93e408515a55593b0c27f39220e4aa37131d1f0d.zip
SCons-93e408515a55593b0c27f39220e4aa37131d1f0d.tar.gz
SCons-93e408515a55593b0c27f39220e4aa37131d1f0d.tar.bz2
Handle Fortran MODULE definitions in the same file. (Craig Scott)
-rw-r--r--src/CHANGES.txt3
-rw-r--r--src/engine/SCons/Scanner/Fortran.py43
-rw-r--r--test/Fortran/USE-MODULE.py92
3 files changed, 134 insertions, 4 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index b62fbef..93846b5 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -592,6 +592,9 @@ RELEASE 0.97 - XXX
file when they're one of the many synonyms for a default True or
False value.
+ - Fix the Fortran Scanner's ability to handle a module being used
+ in the same file in which it is defined.
+
From Jeff Squyres:
- Documentation changes: Use $CPPDEFINES instead of $CCFLAGS in man
diff --git a/src/engine/SCons/Scanner/Fortran.py b/src/engine/SCons/Scanner/Fortran.py
index 66bec0c..8f7a6ce 100644
--- a/src/engine/SCons/Scanner/Fortran.py
+++ b/src/engine/SCons/Scanner/Fortran.py
@@ -54,11 +54,12 @@ class F90Scanner(SCons.Scanner.Classic):
smart thing to do.
"""
- def __init__(self, name, suffixes, path_variable, use_regex,
- incl_regex, *args, **kw):
+ def __init__(self, name, suffixes, path_variable,
+ use_regex, incl_regex, def_regex, *args, **kw):
self.cre_use = re.compile(use_regex, re.M)
self.cre_incl = re.compile(incl_regex, re.M)
+ self.cre_def = re.compile(def_regex, re.M)
def _scan(node, env, path, self=self):
node = node.rfile()
@@ -78,7 +79,7 @@ class F90Scanner(SCons.Scanner.Classic):
def scan(self, node, env, path=()):
"__cacheable__"
-
+
# cache the includes list in node so we only scan it once:
if node.includes != None:
mods_and_includes = node.includes
@@ -87,6 +88,15 @@ class F90Scanner(SCons.Scanner.Classic):
includes = self.cre_incl.findall(node.get_contents())
# retrieve all USE'd module names
modules = self.cre_use.findall(node.get_contents())
+ # retrieve all defined module names
+ defmodules = self.cre_def.findall(node.get_contents())
+
+ # Remove all USE'd module names that are defined in the same file
+ d = {}
+ for m in defmodules:
+ d[m] = 1
+ modules = filter(lambda m, d=d: not d.has_key(m), modules)
+ #modules = self.undefinedModules(modules, defmodules)
# Convert module name to a .mod filename
suffix = env.subst('$FORTRANMODSUFFIX')
@@ -270,9 +280,34 @@ def FortranScan(path_variable="FORTRANPATH"):
include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
+# The MODULE statement regex finds module definitions by matching
+# the following:
+#
+# MODULE module_name
+#
+# but *not* the following:
+#
+# MODULE PROCEDURE procedure_name
+#
+# Here is a breakdown of the regex:
+#
+# (?i) : regex is case insensitive
+# ^\s* : any amount of white space
+# MODULE : match the string MODULE, case insensitive
+# \s+ : match one or more white space characters
+# (?!PROCEDURE) : but *don't* match if the next word matches
+# PROCEDURE (negative lookahead assertion),
+# case insensitive
+# (\w+) : match one or more alphanumeric characters
+# that make up the defined module name and
+# save it in a group
+
+ def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
+
scanner = F90Scanner("FortranScan",
"$FORTRANSUFFIXES",
path_variable,
use_regex,
- include_regex)
+ include_regex,
+ def_regex)
return scanner
diff --git a/test/Fortran/USE-MODULE.py b/test/Fortran/USE-MODULE.py
new file mode 100644
index 0000000..541c457
--- /dev/null
+++ b/test/Fortran/USE-MODULE.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import string
+import sys
+import TestSCons
+
+python = TestSCons.python
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+
+
+test.write('myfortran.py', r"""
+import os.path
+import re
+import string
+import sys
+mod_regex = "(?im)^\\s*MODULE\\s+(?!PROCEDURE)(\\w+)"
+contents = open(sys.argv[1]).read()
+modules = re.findall(mod_regex, contents)
+modules = map(lambda m: string.lower(m)+'.mod', modules)
+for t in sys.argv[2:] + modules:
+ open(t, 'wb').write('myfortran.py wrote %s\n' % os.path.split(t)[1])
+sys.exit(0)
+""")
+
+test.write('SConstruct', """
+env = Environment(FORTRANCOM = r'%(python)s myfortran.py $SOURCE $TARGET')
+env.Object(target = 'test1.obj', source = 'test1.f')
+""" % locals())
+
+test.write('test1.f', """\
+ PROGRAM TEST
+ USE MOD_FOO
+ USE MOD_BAR
+ PRINT *,'TEST.f'
+ CALL P
+ STOP
+ END
+ MODULE MOD_FOO
+ IMPLICIT NONE
+ CONTAINS
+ SUBROUTINE P
+ PRINT *,'mod_foo'
+ END SUBROUTINE P
+ END MODULE MOD_FOO
+ MODULE PROCEDURE MOD_BAR
+ IMPLICIT NONE
+ CONTAINS
+ SUBROUTINE P
+ PRINT *,'mod_bar'
+ END SUBROUTINE P
+ END MODULE MOD_BAR
+""")
+
+test.run(arguments = '.', stderr = None)
+
+test.must_match('test1.obj', "myfortran.py wrote test1.obj\n")
+test.must_match('mod_foo.mod', "myfortran.py wrote mod_foo.mod\n")
+test.must_not_exist('mod_bar.mod')
+
+test.up_to_date(arguments = '.')
+
+
+
+test.pass_test()