bugfix [#26094] Going to Bone Roll menu brings up python error
[blender-staging.git] / build_files / cmake / cmake_consistency_check.py
1 #!/usr/bin/env python
2
3 # $Id$
4 # ***** BEGIN GPL LICENSE BLOCK *****
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software Foundation,
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #
20 # Contributor(s): Campbell Barton
21 #
22 # ***** END GPL LICENSE BLOCK *****
23
24 # <pep8 compliant>
25
26 IGNORE = \
27     "/test/",\
28     "/decimate_glut_test/",\
29     "/BSP_GhostTest/",\
30     "/release/",\
31     "/xembed/",\
32     "/decimation/intern/future/",\
33     "/TerraplayNetwork/",\
34     "/ik_glut_test/"
35
36 import os
37 from os.path import join, dirname, normpath, abspath
38
39 base = join(os.path.dirname(__file__), "..", "..")
40 base = normpath(base)
41 base = abspath(base)
42
43 print("Scanning:", base)
44
45 global_h = set()
46 global_c = set()
47
48 import os
49 from os.path import  splitext
50
51
52 def source_list(path, filename_check=None):
53     for dirpath, dirnames, filenames in os.walk(path):
54
55         # skip '.svn'
56         if dirpath.startswith("."):
57             continue
58
59         for filename in filenames:
60             if filename_check is None or filename_check(filename):
61                 yield os.path.join(dirpath, filename)
62
63
64 # extension checking
65 def is_cmake(filename):
66     ext = splitext(filename)[1]
67     return (ext == ".cmake") or (filename == "CMakeLists.txt")
68
69
70 def is_c_header(filename):
71     ext = splitext(filename)[1]
72     return (ext in (".h", ".hpp", ".hxx"))
73
74
75 def is_c(filename):
76     ext = splitext(filename)[1]
77     return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc"))
78
79
80 def is_c_any(filename):
81     return is_c(filename) or is_c_header(filename)
82
83
84 def cmake_get_src(f):
85
86     sources_h = []
87     sources_c = []
88
89     filen = open(f, "r", encoding="utf8")
90     it = iter(filen)
91     found = False
92     i = 0
93     # print(f)
94     while it is not None:
95         while it is not None:
96             i += 1
97             try:
98                 l = next(it)
99             except StopIteration:
100                 it = None
101                 break
102             l = l.strip()
103             if not l.startswith("#"):
104                 if 'set(SRC' in l or ('set(' in l and l.endswith("SRC")):
105                     if len(l.split()) > 1:
106                         raise Exception("strict formatting not kept 'set(SRC*' %s:%d" % (f, i))
107                     found = True
108                     break
109
110                 if "list(APPEND SRC" in l:
111                     if l.endswith(")"):
112                         raise Exception("strict formatting not kept 'list(APPEND SRC...)' on 1 line %s:%d" % (f, i))
113                     found = True
114                     break
115
116         if found:
117             cmake_base = dirname(f)
118
119             while it is not None:
120                 i += 1
121                 try:
122                     l = next(it)
123                 except StopIteration:
124                     it = None
125                     break
126
127                 l = l.strip()
128
129                 if not l.startswith("#"):
130
131                     if ")" in l:
132                         if l.strip() != ")":
133                             raise Exception("strict formatting not kept '*)' %s:%d" % (f, i))
134                         break
135
136                     # replace dirs
137                     l = l.replace("${CMAKE_CURRENT_SOURCE_DIR}", cmake_base)
138
139                     if not l:
140                         pass
141                     elif l.startswith("$"):
142                         print("Cant use var '%s' %s:%d" % (l, f, i))
143                     elif len(l.split()) > 1:
144                         raise Exception("Multi-line define '%s' %s:%d" % (l, f, i))
145                     else:
146                         new_file = normpath(join(cmake_base, l))
147
148                         if is_c_header(new_file):
149                             sources_h.append(new_file)
150                         elif is_c(new_file):
151                             sources_c.append(new_file)
152                         elif l in ("PARENT_SCOPE", ):
153                             # cmake var, ignore
154                             pass
155                         else:
156                             raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
157
158                         # print(new_file)
159
160             global_h.update(set(sources_h))
161             global_c.update(set(sources_c))
162             '''
163             if not sources_h and not sources_c:
164                 raise Exception("No sources %s" % f)
165
166             sources_h_fs = list(source_list(cmake_base, is_c_header))
167             sources_c_fs = list(source_list(cmake_base, is_c))
168             '''
169             # find missing C files:
170             '''
171             for ff in sources_c_fs:
172                 if ff not in sources_c:
173                     print("  missing: " + ff)
174             '''
175
176     filen.close()
177
178
179 for cmake in source_list(base, is_cmake):
180     cmake_get_src(cmake)
181
182
183 def is_ignore(f):
184     for ig in IGNORE:
185         if ig in f:
186             return True
187     return False
188
189 # First do stupid check, do these files exist?
190 for f in (global_h | global_c):
191     if f.endswith("dna.c"):
192         continue
193
194     if not os.path.exists(f):
195         raise Exception("CMake referenced file missing: " + f)
196
197
198 # now check on files not accounted for.
199 print("\nC/C++ Files CMake doesnt know about...")
200 for cf in sorted(source_list(base, is_c)):
201     if not is_ignore(cf):
202         if cf not in global_c:
203             print("missing_c: ", cf)
204 print("\nC/C++ Headers CMake doesnt know about...")
205 for hf in sorted(source_list(base, is_c_header)):
206     if not is_ignore(hf):
207         if hf not in global_h:
208             print("missing_h: ", hf)
209
210 # test encoding
211 import traceback
212 for files in (global_c, global_h):
213     for f in sorted(files):
214         if os.path.exists(f):
215             # ignore outside of our source tree
216             if "extern" not in f:
217                 i = 1
218                 try:
219                     for l in open(f, "r", encoding="utf8"):
220                         i += 1
221                 except:
222                     print("Non utf8: %s:%d" % (f, i))
223                     if i > 1:
224                         traceback.print_exc()