3 This module implements the depenency scanner for C/C++ code.
8 # Copyright (c) 2001, 2002 Steven Knight
10 # Permission is hereby granted, free of charge, to any person obtaining
11 # a copy of this software and associated documentation files (the
12 # "Software"), to deal in the Software without restriction, including
13 # without limitation the rights to use, copy, modify, merge, publish,
14 # distribute, sublicense, and/or sell copies of the Software, and to
15 # permit persons to whom the Software is furnished to do so, subject to
16 # the following conditions:
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
22 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
23 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
43 include_re = re.compile('^[ \t]*#[ \t]*include[ \t]+(<|")([^>"]+)(>|")', re.M)
45 def CScan(fs = SCons.Node.FS.default_fs):
46 """Return a prototype Scanner instance for scanning source files
47 that use the C pre-processor"""
48 cs = SCons.Scanner.Current(scan, "CScan", fs,
49 [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
50 ".h", ".H", ".hxx", ".hpp", ".hh",
51 ".F", ".fpp", ".FPP"],
56 def path(env, dir, fs = SCons.Node.FS.default_fs):
58 cpppath = env['CPPPATH']
61 return tuple(fs.Rsearchall(SCons.Util.mapPaths(cpppath, dir, env),
62 clazz = SCons.Node.FS.Dir,
65 def scan(node, env, cpppath = (), fs = SCons.Node.FS.default_fs):
67 scan(node, Environment) -> [node]
69 the C/C++ dependency scanner function
71 This function is intentionally simple. There are two rules it
74 1) #include <foo.h> - search for foo.h in CPPPATH followed by the
75 directory 'filename' is in
76 2) #include \"foo.h\" - search for foo.h in the directory 'filename' is
77 in followed by CPPPATH
79 These rules approximate the behaviour of most C/C++ compilers.
81 This scanner also ignores #ifdef and other preprocessor conditionals, so
82 it may find more depencies than there really are, but it never misses
88 # This function caches the following information:
89 # node.includes - the result of include_re.findall()
94 # cache the includes list in node so we only scan it once:
95 if node.includes != None:
96 includes = node.includes
98 includes = include_re.findall(node.get_contents())
99 node.includes = includes
102 source_dir = node.get_dir()
103 for include in includes:
104 if include[0] == '"':
105 n = SCons.Node.FS.find_file(include[1],
106 (source_dir,) + cpppath,
109 n = SCons.Node.FS.find_file(include[1],
110 cpppath + (source_dir,),
116 SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
117 "No dependency generated for file: %s (included from: %s) -- file not found" % (include[1], node))
119 # Schwartzian transform from the Python FAQ Wizard
120 def st(List, Metric):
121 def pairing(element, M = Metric):
122 return (M(element), element)
125 paired = map(pairing, List)
127 return map(stripit, paired)
130 # We don't want the order of includes to be
131 # modified by case changes on case insensitive OSes, so
132 # normalize the case of the filename here:
133 # (see test/win32pathmadness.py for a test of this)
134 return SCons.Node.FS._my_normcase(str(node))
136 return st(nodes, normalize)