3 # Copyright 2007, Google Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
8 # 1. Redistributions of source code must retain the above copyright notice,
9 # this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright notice,
11 # this list of conditions and the following disclaimer in the documentation
12 # and/or other materials provided with the distribution.
13 # 3. Neither the name of Google Inc. nor the names of its contributors may be
14 # used to endorse or promote products derived from this software without
15 # specific prior written permission.
17 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 """A really crappy C/C++ dependency generator (TM).
30 usage: %s target source
32 Print a list of all dependencies of source, in a form suitable for including
35 target : source dep1 dep2 dep3...
37 We make a couple simplifying assumptions here:
38 1. We are only executed from the top-level source directory
39 2. We assume that our include search path is really simple (in fact, it is
41 3. We ignore the fact that some include files may be conditional (#ifdef)
48 SEARCH_DIRS
=['', '..']
52 return open(f
, 'r').read()
55 def grepForIncludes(file_contents
):
56 return re
.findall('#include\s+"(.*)"', file_contents
)
59 def getIncludes(filename
):
60 return grepForIncludes(readAllLines(filename
))
63 def resolve(filename
, f_fileexists
=os
.path
.exists
):
65 Scan the file system for a given file, trying each of the directories in
66 SEARCH_DIRS. If found, return the name of the file, otherwise return None.
68 for search_dir
in SEARCH_DIRS
:
69 resolved_filename
= os
.path
.join(search_dir
, filename
)
70 if f_fileexists(resolved_filename
):
71 return resolved_filename
76 def getResolvedIncludes(filename
, f_resolver
=resolve
, f_getIncludes
=getIncludes
):
79 f_getIncludes(filename
)))
82 def getDependencies(filenames
, f_getIncludes
=getResolvedIncludes
):
84 Return all the dependencies of the files in the list "filenames" by recursively
85 applying the function f_getIncludes.
88 includes
.extend(filenames
)
89 for filename
in filenames
:
90 for fname_include
in f_getIncludes(filename
):
91 includes
.extend(getDependencies([fname_include
], f_getIncludes
))
95 def sortAndRemoveDupes(list):
104 def printDependencies(deps
, target
, f_writer
=sys
.stdout
.write
):
105 f_writer("%s : " % target
)
107 f_writer(os
.path
.normpath(dep
) + ' ')
110 def checkArgs(argv
, usage_string
, f_writer
=sys
.stderr
.write
):
112 f_writer(usage_string
% argv
[0])
117 def sortDependencies(deps
):
119 Return first element (the .cc file) + sort of remaining elements (the header files).
121 return [deps
[0]] + sortAndRemoveDupes(deps
[1:])
124 if __name__
== '__main__':
125 if (not checkArgs(sys
.argv
, __doc__
)):
128 printDependencies(sortDependencies(getDependencies([sys
.argv
[1]])),