7a3ac9eaa7904e81b3822c0ff9127a67b76647ad
[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                         elif l in ("PARENT_SCOPE", ):
145                             # cmake var, ignore
146                             pass
147                         else:
148                             raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
149
150                         # print(new_file)
151
152             global_h.update(set(sources_h))
153             global_c.update(set(sources_c))
154             '''
155             if not sources_h and not sources_c:
156                 raise Exception("No sources %s" % f)
157
158             sources_h_fs = list(source_list(cmake_base, is_c_header))
159             sources_c_fs = list(source_list(cmake_base, is_c))
160             '''
161             # find missing C files:
162             '''
163             for ff in sources_c_fs:
164                 if ff not in sources_c:
165                     print("  missing: " + ff)
166             '''
167     
168     filen.close()
169
170
171 for cmake in source_list(base, is_cmake):
172     cmake_get_src(cmake)
173
174 def is_ignore(f):
175     for ig in IGNORE:
176         if ig in f:
177             return True
178     return False
179     
180 # First do stupid check, do these files exist?
181 for f in (global_h | global_c):
182     if f.endswith("dna.c"):
183         continue
184
185     if not os.path.exists(f):
186         raise Exception("CMake referenced file missing: " + f)
187
188     
189 # now check on files not accounted for.
190 print("\nC/C++ Files CMake doesnt know about...")
191 for cf in sorted(source_list(base, is_c)):
192     if not is_ignore(cf):
193         if cf not in global_c:
194             print("missing_c: ", cf)
195 print("\nC/C++ Headers CMake doesnt know about...")
196 for hf in sorted(source_list(base, is_c_header)):
197     if not is_ignore(hf):
198         if hf not in global_h:
199             print("missing_h: ", hf)
200
201 # test encoding
202 import traceback
203 for files in (global_c, global_h):
204     for f in sorted(files):
205         i = 1
206         try:
207             for l in open(f, "r", encoding="utf8"):
208                 i += 1
209         except:
210             print("Non utf8: %s:%d" % (f, i))
211             if i > 1:
212                 traceback.print_exc()