Fix for bugs 402 and 2082 - implement scanner for windows resource files.
authorbdbaddog <bdbaddog@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 25 Sep 2008 19:44:49 +0000 (19:44 +0000)
committerbdbaddog <bdbaddog@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 25 Sep 2008 19:44:49 +0000 (19:44 +0000)
Basic unittest included

git-svn-id: http://scons.tigris.org/svn/scons/trunk@3475 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/engine/SCons/Scanner/RC.py [new file with mode: 0644]
src/engine/SCons/Scanner/RCTests.py [new file with mode: 0644]
src/engine/SCons/Tool/msvc.py

diff --git a/src/engine/SCons/Scanner/RC.py b/src/engine/SCons/Scanner/RC.py
new file mode 100644 (file)
index 0000000..d7c6870
--- /dev/null
@@ -0,0 +1,49 @@
+"""SCons.Scanner.RC
+
+This module implements the depenency scanner for RC (Interface
+Definition Language) files.
+
+"""
+
+#
+# __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 SCons.Node.FS
+import SCons.Scanner
+import re
+
+def RCScan():
+    """Return a prototype Scanner instance for scanning RC source files"""
+    res_re= r'^(?:\s*#\s*(?:include)|' \
+            '.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY)' \
+            '\s*.*?)' \
+            '\s*(<|"| )([^>" \Z\t]+)(?:[>" ])*$'
+    resScanner = SCons.Scanner.ClassicCPP( "ResourceScanner",
+                                           "$RCSUFFIXES",
+                                           "CPPPATH",
+                                           res_re )
+    
+    return resScanner
diff --git a/src/engine/SCons/Scanner/RCTests.py b/src/engine/SCons/Scanner/RCTests.py
new file mode 100644 (file)
index 0000000..0101742
--- /dev/null
@@ -0,0 +1,156 @@
+#
+# __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 TestCmd
+import SCons.Scanner.RC
+import unittest
+import sys
+import os
+import os.path
+import SCons.Node.FS
+import SCons.Warnings
+import UserDict
+
+test = TestCmd.TestCmd(workdir = '')
+
+os.chdir(test.workpath(''))
+
+# create some source files and headers:
+
+test.write('t1.rc','''
+#include "t1.h"
+''')
+
+test.write('t2.rc',"""
+#include "t1.h"
+ICO_TEST               ICON    DISCARDABLE     "abc.ico"
+BMP_TEST               BITMAP  DISCARDABLE     "def.bmp"
+cursor1 CURSOR "bullseye.cur"
+ID_RESPONSE_ERROR_PAGE  HTML  "responseerrorpage.htm"
+5 FONT  "cmroman.fnt"
+1  MESSAGETABLE "MSG00409.bin"
+1  MESSAGETABLE MSG00410.bin
+1 TYPELIB "testtypelib.tlb"
+TEST_REGIS   REGISTRY MOVEABLE PURE  "testregis.rgs"
+""")
+
+
+# Create dummy include files
+headers = ['t1.h',
+           'abc.ico','def.bmp','bullseye.cur','responseerrorpage.htm','cmroman.fnt',
+           'MSG00409.bin','MSG00410.bin','testtypelib.tlb','testregis.rgs']
+
+for h in headers:
+    test.write(h, " ")
+
+
+# define some helpers:
+
+class DummyEnvironment(UserDict.UserDict):
+    def __init__(self,**kw):
+        UserDict.UserDict.__init__(self)
+        self.data.update(kw)
+        self.fs = SCons.Node.FS.FS(test.workpath(''))
+        
+    def Dictionary(self, *args):
+        return self.data
+
+    def subst(self, arg, target=None, source=None, conv=None):
+        if strSubst[0] == '$':
+            return self.data[strSubst[1:]]
+        return strSubst
+
+    def subst_path(self, path, target=None, source=None, conv=None):
+        if type(path) != type([]):
+            path = [path]
+        return map(self.subst, path)
+
+    def has_key(self, key):
+        return self.Dictionary().has_key(key)
+
+    def get_calculator(self):
+        return None
+
+    def get_factory(self, factory):
+        return factory or self.fs.File
+
+    def Dir(self, filename):
+        return self.fs.Dir(filename)
+
+    def File(self, filename):
+        return self.fs.File(filename)
+
+global my_normpath
+my_normpath = os.path.normpath
+
+if os.path.normcase('foo') == os.path.normcase('FOO'):
+    my_normpath = os.path.normcase
+
+def deps_match(self, deps, headers):
+    scanned = map(my_normpath, map(str, deps))
+    expect = map(my_normpath, headers)
+    self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+
+# define some tests:
+
+class RCScannerTestCase1(unittest.TestCase):
+    def runTest(self):
+        env = DummyEnvironment(RCSUFFIXES=['.rc','.rc2'],
+                               CPPPATH=sys.path)
+        s = SCons.Scanner.RC.RCScan()
+        path = s.path(env)
+        deps = s(env.File('t1.rc'), env, path)
+        headers = ['t1.h']
+        deps_match(self, deps, headers)
+
+class RCScannerTestCase2(unittest.TestCase):
+    def runTest(self):
+        env = DummyEnvironment(RCSUFFIXES=['.rc','.rc2'],
+                               CPPPATH=sys.path)
+        s = SCons.Scanner.RC.RCScan()
+        path = s.path(env)
+        deps = s(env.File('t2.rc'), env, path)
+        headers = ['MSG00410.bin',
+                   'abc.ico','bullseye.cur',
+                   'cmroman.fnt','def.bmp',
+                   'MSG00409.bin',
+                   'responseerrorpage.htm',
+                   't1.h',
+                   'testregis.rgs','testtypelib.tlb']
+        deps_match(self, deps, headers)
+
+        
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(RCScannerTestCase1())
+    suite.addTest(RCScannerTestCase2())
+    return suite
+
+if __name__ == "__main__":
+    runner = unittest.TextTestRunner()
+    result = runner.run(suite())
+    if not result.wasSuccessful():
+        sys.exit(1)
index 8828d7da355b4e3d776c0360bcb269d3c94f1c8a..036501ba6e05fbfa41ed2d264b82ab8bb50aacf2 100644 (file)
@@ -660,13 +660,17 @@ pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR')
 pch_builder = SCons.Builder.Builder(action=pch_action, suffix='.pch',
                                     emitter=pch_emitter,
                                     source_scanner=SCons.Tool.SourceFileScanner)
-res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
+
+
+# Logic to build .rc files into .res files (resource files)
+res_scanner = SCons.Scanner.RCScan()
+res_action  = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
 res_builder = SCons.Builder.Builder(action=res_action,
                                     src_suffix='.rc',
                                     suffix='.res',
                                     src_builder=[],
-                                    source_scanner=SCons.Tool.SourceFileScanner)
-SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan)
+                                    source_scanner=res_scanner)
+
 
 def generate(env):
     """Add Builders and construction variables for MSVC++ to an Environment."""
@@ -711,6 +715,7 @@ def generate(env):
 
     env['RC'] = 'rc'
     env['RCFLAGS'] = SCons.Util.CLVar('')
+    env['RCSUFFIXES']=['.rc','.rc2']
     env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
     env['BUILDERS']['RES'] = res_builder
     env['OBJPREFIX']      = ''