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__"
41 include_re = re.compile('^[ \t]*#[ \t]*include[ \t]+(<|")([^>"]+)(>|")', re.M)
43 def CScan(fs = SCons.Node.FS.default_fs):
44 """Return a prototype Scanner instance for scanning source files
45 that use the C pre-processor"""
46 cs = SCons.Scanner.Current(scan, "CScan", fs,
47 [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
48 ".h", ".H", ".hxx", ".hpp", ".hh",
49 ".F", ".fpp", ".FPP"],
54 def path(env, dir, fs = SCons.Node.FS.default_fs):
56 cpppath = env['CPPPATH']
59 return tuple(fs.Rsearchall(SCons.Util.mapPaths(cpppath, dir, env),
60 clazz = SCons.Node.FS.Dir,
63 def scan(node, env, cpppath = (), fs = SCons.Node.FS.default_fs):
65 scan(node, Environment) -> [node]
67 the C/C++ dependency scanner function
69 This function is intentionally simple. There are two rules it
72 1) #include <foo.h> - search for foo.h in CPPPATH followed by the
73 directory 'filename' is in
74 2) #include \"foo.h\" - search for foo.h in the directory 'filename' is
75 in followed by CPPPATH
77 These rules approximate the behaviour of most C/C++ compilers.
79 This scanner also ignores #ifdef and other preprocessor conditionals, so
80 it may find more depencies than there really are, but it never misses
86 # This function caches the following information:
87 # node.includes - the result of include_re.findall()
92 # cache the includes list in node so we only scan it once:
93 if node.includes != None:
94 includes = node.includes
96 includes = include_re.findall(node.get_contents())
97 node.includes = includes
100 source_dir = node.get_dir()
101 for include in includes:
102 if include[0] == '"':
103 n = SCons.Node.FS.find_file(include[1],
104 (source_dir,) + cpppath,
107 n = SCons.Node.FS.find_file(include[1],
108 cpppath + (source_dir,),
114 SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
115 "No dependency generated for file: %s (included from: %s) -- file not found" % (include[1], node))
117 # Schwartzian transform from the Python FAQ Wizard
118 def st(List, Metric):
119 def pairing(element, M = Metric):
120 return (M(element), element)
123 paired = map(pairing, List)
125 return map(stripit, paired)
128 # We don't want the order of includes to be
129 # modified by case changes on case insensitive OSes, so
130 # normalize the case of the filename here:
131 # (see test/win32pathmadness.py for a test of this)
132 return SCons.Node.FS._my_normcase(str(node))
134 return st(nodes, normalize)