Reverting my windows build fix because it breaks the bug fix committed in r40995
[blender.git] / build_files / cmake / project_source_info.py
1 # $Id$
2 # ***** BEGIN GPL LICENSE BLOCK *****
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 #
18 # Contributor(s): Campbell Barton
19 #
20 # ***** END GPL LICENSE BLOCK *****
21
22 # <pep8 compliant>
23
24 __all__ = (
25     "build_info",
26     "SOURCE_DIR",
27     )
28
29 import os
30 from os.path import join, dirname, normpath, abspath
31
32 SOURCE_DIR = join(dirname(__file__), "..", "..")
33 SOURCE_DIR = normpath(SOURCE_DIR)
34 SOURCE_DIR = abspath(SOURCE_DIR)
35
36
37 def is_c_header(filename):
38     ext = os.path.splitext(filename)[1]
39     return (ext in (".h", ".hpp", ".hxx"))
40
41
42 def is_c(filename):
43     ext = os.path.splitext(filename)[1]
44     return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc"))
45
46
47 def is_c_any(filename):
48     return os.path.s_c(filename) or is_c_header(filename)
49
50
51 # copied from project_info.py
52 CMAKE_DIR = "."
53
54
55 def cmake_cache_var(var):
56     cache_file = open(join(CMAKE_DIR, "CMakeCache.txt"))
57     lines = [l_strip for l in cache_file for l_strip in (l.strip(),) if l_strip if not l_strip.startswith("//") if not l_strip.startswith("#")]
58     cache_file.close()
59
60     for l in lines:
61         if l.split(":")[0] == var:
62             return l.split("=", 1)[-1]
63     return None
64
65
66 def do_ignore(filepath, ignore_prefix_list):
67     if ignore_prefix_list is None:
68         return False
69
70     relpath = os.path.relpath(filepath, SOURCE_DIR)
71     return any([relpath.startswith(prefix) for prefix in ignore_prefix_list])
72
73
74 def makefile_log():
75     import subprocess
76     import time
77     # Check blender is not 2.5x until it supports playback again
78     print("running make with --dry-run ...")
79     process = subprocess.Popen(["make", "--always-make", "--dry-run", "--keep-going", "VERBOSE=1"],
80                                 stdout=subprocess.PIPE,
81                                 )
82
83     while process.poll():
84         time.sleep(1)
85
86     out = process.stdout.read()
87     process.stdout.close()
88     print("done!", len(out), "bytes")
89     return out.decode("ascii").split("\n")
90
91
92 def build_info(use_c=True, use_cxx=True, ignore_prefix_list=None):
93
94     makelog = makefile_log()
95
96     source = []
97
98     compilers = []
99     if use_c:
100         compilers.append(cmake_cache_var("CMAKE_C_COMPILER"))
101     if use_cxx:
102         compilers.append(cmake_cache_var("CMAKE_CXX_COMPILER"))
103
104     print("compilers:", " ".join(compilers))
105
106     fake_compiler = "%COMPILER%"
107
108     print("parsing make log ...")
109
110     for line in makelog:
111
112         args = line.split()
113
114         if not any([(c in args) for c in compilers]):
115             continue
116
117         # join args incase they are not.
118         args = ' '.join(args)
119         args = args.replace(" -isystem", " -I")
120         args = args.replace(" -D ", " -D")
121         args = args.replace(" -I ", " -I")
122
123         for c in compilers:
124             args = args.replace(c, fake_compiler)
125         args = args.split()
126         # end
127
128         # remove compiler
129         args[:args.index(fake_compiler) + 1] = []
130
131         c_files = [f for f in args if is_c(f)]
132         inc_dirs = [f[2:].strip() for f in args if f.startswith('-I')]
133         defs = [f[2:].strip() for f in args if f.startswith('-D')]
134         for c in sorted(c_files):
135
136             if do_ignore(c, ignore_prefix_list):
137                 continue
138
139             source.append((c, inc_dirs, defs))
140
141         # safety check that our includes are ok
142         for f in inc_dirs:
143             if not os.path.exists(f):
144                 raise Exception("%s missing" % f)
145
146     print("done!")
147
148     return source
149
150
151 # could be moved elsewhere!, this just happens to be used by scripts that also
152 # use this module.
153 def queue_processes(process_funcs, job_total=-1):
154     """ Takes a list of function arg pairs, each function must return a process
155     """
156     import sys
157
158     if job_total == -1:
159         import multiprocessing
160         job_total = multiprocessing.cpu_count()
161         del multiprocessing
162
163     if job_total == 1:
164         for func, args in process_funcs:
165             sys.stdout.flush()
166             sys.stderr.flush()
167
168             process = func(*args)
169             process.wait()
170     else:
171         import time
172
173         processes = []
174         for func, args in process_funcs:
175             # wait until a thread is free
176             while 1:
177                 processes[:] = [p for p in processes if p.poll() is None]
178
179                 if len(processes) <= job_total:
180                     break
181                 else:
182                     time.sleep(0.1)
183
184             sys.stdout.flush()
185             sys.stderr.flush()
186
187             processes.append(func(*args))
188
189
190 def main():
191     if not os.path.exists(join(CMAKE_DIR, "CMakeCache.txt")):
192         print("This script must run from the cmake build dir")
193         return
194
195     for s in build_info():
196         print(s)
197
198 if __name__ == "__main__":
199     main()