1 #!/usr/bin/env python3.2
3 # ***** BEGIN GPL LICENSE BLOCK *****
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # Contributor(s): Campbell Barton
21 # ***** END GPL LICENSE BLOCK *****
26 if not sys.version.startswith("3"):
27 print("\nPython3.x needed, found %s.\nAborting!\n" %
28 sys.version.partition(" ")[0])
31 from cmake_consistency_check_config import IGNORE, UTF8_CHECK, SOURCE_DIR
34 from os.path import join, dirname, normpath, splitext
36 print("Scanning:", SOURCE_DIR)
43 def replace_line(f, i, text, keep_indent=True):
44 file_handle = open(f, 'r')
45 data = file_handle.readlines()
49 ws = l[:len(l) - len(l.lstrip())]
51 data[i] = "%s%s\n" % (ws, text)
53 file_handle = open(f, 'w')
54 file_handle.writelines(data)
58 def source_list(path, filename_check=None):
59 for dirpath, dirnames, filenames in os.walk(path):
62 if dirpath.startswith("."):
65 for filename in filenames:
66 if filename_check is None or filename_check(filename):
67 yield os.path.join(dirpath, filename)
71 def is_cmake(filename):
72 ext = splitext(filename)[1]
73 return (ext == ".cmake") or (filename == "CMakeLists.txt")
76 def is_c_header(filename):
77 ext = splitext(filename)[1]
78 return (ext in (".h", ".hpp", ".hxx"))
82 ext = splitext(filename)[1]
83 return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"))
86 def is_c_any(filename):
87 return is_c(filename) or is_c_header(filename)
95 filen = open(f, "r", encoding="utf8")
101 def is_definition(l, f, i, name):
102 if l.startswith("unset("):
105 if ('set(%s' % name) in l or ('set(' in l and l.endswith(name)):
106 if len(l.split()) > 1:
107 raise Exception("strict formatting not kept 'set(%s*' %s:%d" % (name, f, i))
110 if ("list(APPEND %s" % name) in l or ('list(APPEND ' in l and l.endswith(name)):
112 raise Exception("strict formatting not kept 'list(APPEND %s...)' on 1 line %s:%d" % (name, f, i))
115 while it is not None:
117 while it is not None:
121 except StopIteration:
125 if not l.startswith("#"):
126 found = is_definition(l, f, i, "SRC")
130 found = is_definition(l, f, i, "INC")
136 cmake_base = dirname(f)
138 while it is not None:
142 except StopIteration:
148 if not l.startswith("#"):
152 raise Exception("strict formatting not kept '*)' %s:%d" % (f, i))
156 l = l.replace("${CMAKE_CURRENT_SOURCE_DIR}", cmake_base)
160 elif l.startswith("$"):
161 if context_name == "SRC":
162 # assume if it ends with context_name we know about it
163 if not l.split("}")[0].endswith(context_name):
164 print("Can't use var '%s' %s:%d" % (l, f, i))
165 elif len(l.split()) > 1:
166 raise Exception("Multi-line define '%s' %s:%d" % (l, f, i))
168 new_file = normpath(join(cmake_base, l))
170 if context_name == "SRC":
171 if is_c_header(new_file):
172 sources_h.append(new_file)
173 global_refs.setdefault(new_file, []).append((f, i))
175 sources_c.append(new_file)
176 global_refs.setdefault(new_file, []).append((f, i))
177 elif l in ("PARENT_SCOPE", ):
180 elif new_file.endswith(".list"):
182 elif new_file.endswith(".def"):
184 elif new_file.endswith(".cl"): # opencl
186 elif new_file.endswith(".cu"): # cuda
188 elif new_file.endswith(".osl"): # open shading language
191 raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
193 elif context_name == "INC":
194 if os.path.isdir(new_file):
195 new_path_rel = os.path.relpath(new_file, cmake_base)
197 if new_path_rel != l:
198 print("overly relative path:\n %s:%d\n %s\n %s" % (f, i, l, new_path_rel))
200 ## Save time. just replace the line
201 # replace_line(f, i - 1, new_path_rel)
204 raise Exception("non existant include %s:%d -> %s" % (f, i, new_file))
208 global_h.update(set(sources_h))
209 global_c.update(set(sources_c))
211 if not sources_h and not sources_c:
212 raise Exception("No sources %s" % f)
214 sources_h_fs = list(source_list(cmake_base, is_c_header))
215 sources_c_fs = list(source_list(cmake_base, is_c))
217 # find missing C files:
219 for ff in sources_c_fs:
220 if ff not in sources_c:
221 print(" missing: " + ff)
231 for cmake in source_list(SOURCE_DIR, is_cmake):
242 # First do stupid check, do these files exist?
243 print("\nChecking for missing references:")
246 for f in (global_h | global_c):
247 if f.endswith("dna.c"):
250 if not os.path.exists(f):
251 refs = global_refs[f]
256 raise Exception("CMake referenecs missing, internal error, aborting!")
262 print("%s:%d" % (cf, i))
263 # Write a 'sed' script, useful if we get a lot of these
264 # print("sed '%dd' '%s' > '%s.tmp' ; mv '%s.tmp' '%s'" % (i, cf, cf, cf, cf))
268 raise Exception("CMake referenecs missing files, aborting!")
272 # now check on files not accounted for.
273 print("\nC/C++ Files CMake doesnt know about...")
274 for cf in sorted(source_list(SOURCE_DIR, is_c)):
275 if not is_ignore(cf):
276 if cf not in global_c:
277 print("missing_c: ", cf)
279 # check if automake builds a corrasponding .o file.
282 out1 = os.path.splitext(cf)[0] + ".o"
283 out2 = os.path.splitext(cf)[0] + ".Po"
284 out2_dir, out2_file = out2 = os.path.split(out2)
285 out2 = os.path.join(out2_dir, ".deps", out2_file)
286 if not os.path.exists(out1) and not os.path.exists(out2):
290 print("\nC/C++ Headers CMake doesnt know about...")
291 for hf in sorted(source_list(SOURCE_DIR, is_c_header)):
292 if not is_ignore(hf):
293 if hf not in global_h:
294 print("missing_h: ", hf)
299 for files in (global_c, global_h):
300 for f in sorted(files):
301 if os.path.exists(f):
302 # ignore outside of our source tree
303 if "extern" not in f:
306 for l in open(f, "r", encoding="utf8"):
309 print("Non utf8: %s:%d" % (f, i))
311 traceback.print_exc()