script to generate qtcreator project files, advantage is they include all source...
[blender.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 IGNORE = \
25     "/test/",\
26     "/decimate_glut_test/",\
27     "/BSP_GhostTest/",\
28     "/release/",\
29     "/xembed/",\
30     "/decimation/intern/future/",\
31     "/TerraplayNetwork/",\
32     "/ik_glut_test/"
33
34 import os
35 from os.path import join, dirname, normpath, abspath
36
37 base = join(os.path.dirname(__file__), "..", "..")
38 base = normpath(base)
39 base = abspath(base)
40
41 print("Scanning:", base)
42
43 global_h = set()
44 global_c = set()
45
46 import os
47 from os.path import  splitext
48 def source_list(path, filename_check=None):
49     for dirpath, dirnames, filenames in os.walk(path):
50
51         # skip '.svn'
52         if dirpath.startswith("."):
53             continue
54
55         for filename in filenames:
56             if filename_check is None or filename_check(filename):
57                 yield os.path.join(dirpath, filename)
58
59 # extension checking
60 def is_c_header(filename):
61     ext = splitext(filename)[1]
62     return (ext in (".h", ".hpp", ".hxx"))
63
64 def is_cmake(filename):
65     ext = splitext(filename)[1]
66     return (ext == ".cmake") or (filename == "CMakeLists.txt")
67
68 def is_c_header(filename):
69     ext = splitext(filename)[1]
70     return (ext in (".h", ".hpp", ".hxx"))
71
72 def is_c(filename):
73     ext = splitext(filename)[1]
74     return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc"))
75
76 def is_c_any(filename):
77     return is_c(filename) or is_c_header(filename)
78
79 def cmake_get_src(f):
80     
81     sources_h = []
82     sources_c = []
83     
84     filen = open(f, "r", encoding="utf8")
85     it = iter(filen)
86     found = False
87     i = 0
88     # print(f)
89     while it is not None:
90         while it is not None:
91             i += 1
92             try:
93                 l = next(it)
94             except StopIteration:
95                 it = None
96                 break
97             l = l.strip()
98             if not l.startswith("#"):
99                 if 'set(SRC' in l or ('set(' in l and l.endswith("SRC")):
100                     if len(l.split()) > 1:
101                         raise Exception("strict formatting not kept 'set(SRC*' %s:%d" % (f, i))
102                     found = True
103                     break
104                 
105                 if "list(APPEND SRC" in l:
106                     if l.endswith(")"):
107                         raise Exception("strict formatting not kept 'list(APPEND SRC...)' on 1 line %s:%d" % (f, i))
108                     found = True
109                     break
110
111         if found:
112             cmake_base = dirname(f)
113
114             while it is not None:
115                 i += 1
116                 try:
117                     l = next(it)
118                 except StopIteration:
119                     it = None
120                     break
121                     
122                 l = l.strip()
123
124                 if not l.startswith("#"):
125                         
126                     if ")" in l:
127                         if l.strip() != ")":
128                             raise Exception("strict formatting not kept '*)' %s:%d" % (f, i))
129                         break
130
131                     if not l:
132                         pass
133                     elif l.startswith("$"):
134                         print("Cant use var '%s' %s:%d" % (l, f, i))
135                     elif len(l.split()) > 1:
136                         raise Exception("Multi-line define '%s' %s:%d" % (l, f, i))
137                     else:
138                         new_file = normpath(join(cmake_base, l))
139                         
140                         if is_c_header(new_file):
141                             sources_h.append(new_file)
142                         elif is_c(new_file):
143                             sources_c.append(new_file)
144                         else:
145                             raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
146
147                         # print(new_file)
148
149             global_h.update(set(sources_h))
150             global_c.update(set(sources_c))
151             '''
152             if not sources_h and not sources_c:
153                 raise Exception("No sources %s" % f)
154
155             sources_h_fs = list(source_list(cmake_base, is_c_header))
156             sources_c_fs = list(source_list(cmake_base, is_c))
157             '''
158             # find missing C files:
159             '''
160             for ff in sources_c_fs:
161                 if ff not in sources_c:
162                     print("  missing: " + ff)
163             '''
164     
165     filen.close()
166
167
168 for cmake in source_list(base, is_cmake):
169     cmake_get_src(cmake)
170
171 def is_ignore(f):
172     for ig in IGNORE:
173         if ig in f:
174             return True
175     return False
176     
177 # First do stupid check, do these files exist?
178 for f in (global_h | global_c):
179     if f.endswith("dna.c"):
180         continue
181
182     if not os.path.exists(f):
183         raise Exception("CMake referenced file missing: " + f)
184
185     
186 # now check on files not accounted for.
187 print("\nC/C++ Files CMake doesnt know about...")
188 for cf in sorted(source_list(base, is_c)):
189     if not is_ignore(cf):
190         if cf not in global_c:
191             print("missing_c: ", cf)
192 print("\nC/C++ Headers CMake doesnt know about...")
193 for hf in sorted(source_list(base, is_c_header)):
194     if not is_ignore(hf):
195         if hf not in global_h:
196             print("missing_h: ", hf)
197
198 # test encoding
199 import traceback
200 for files in (global_c, global_h):
201     for f in sorted(files):
202         i = 1
203         try:
204             for l in open(f, "r", encoding="utf8"):
205                 i += 1
206         except:
207             print("Non utf8: %s:%d" % (f, i))
208             if i > 1:
209                 traceback.print_exc()