merge from trunk #37722
[blender.git] / build_files / cmake / project_info.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, M.G. Kishalmi
21 #
22 # ***** END GPL LICENSE BLOCK *****
23
24 # <pep8 compliant>
25
26 """
27 Example Win32 usage:
28  c:\Python32\python.exe c:\blender_dev\blender\build_files\cmake\cmake_qtcreator_project.py c:\blender_dev\cmake_build
29
30 example linux usage
31  python .~/blenderSVN/blender/build_files/cmake/cmake_qtcreator_project.py ~/blenderSVN/cmake
32 """
33
34 __all__ = (
35     "SIMPLE_PROJECTFILE",
36     "SOURCE_DIR",
37     "CMAKE_DIR",
38     "PROJECT_DIR",
39     "source_list",
40     "is_project_file",
41     "is_c_header",
42     "is_py",
43     "cmake_advanced_info",
44     "cmake_compiler_defines",
45 )
46
47 import sys
48 import os
49 from os.path import join, dirname, normpath, abspath, splitext, exists
50
51 SOURCE_DIR = join(dirname(__file__), "..", "..")
52 SOURCE_DIR = normpath(SOURCE_DIR)
53 SOURCE_DIR = abspath(SOURCE_DIR)
54
55 SIMPLE_PROJECTFILE = False
56
57 # get cmake path
58 CMAKE_DIR = sys.argv[-1]
59
60 if not exists(join(CMAKE_DIR, "CMakeCache.txt")):
61     CMAKE_DIR = os.getcwd()
62 if not exists(join(CMAKE_DIR, "CMakeCache.txt")):
63     print("CMakeCache.txt not found in %r or %r\n    Pass CMake build dir as an argument, or run from that dir, aborting" % (CMAKE_DIR, os.getcwd()))
64     sys.exit(1)
65
66
67 # could be either.
68 # PROJECT_DIR = SOURCE_DIR
69 PROJECT_DIR = CMAKE_DIR
70
71
72 def source_list(path, filename_check=None):
73     for dirpath, dirnames, filenames in os.walk(path):
74
75         # skip '.svn'
76         if dirpath.startswith("."):
77             continue
78
79         for filename in filenames:
80             filepath = join(dirpath, filename)
81             if filename_check is None or filename_check(filepath):
82                 yield filepath
83
84
85 # extension checking
86 def is_cmake(filename):
87     ext = splitext(filename)[1]
88     return (ext == ".cmake") or (filename.endswith("CMakeLists.txt"))
89
90
91 def is_c_header(filename):
92     ext = splitext(filename)[1]
93     return (ext in (".h", ".hpp", ".hxx"))
94
95
96 def is_py(filename):
97     ext = splitext(filename)[1]
98     return (ext == ".py")
99
100
101 def is_glsl(filename):
102     ext = splitext(filename)[1]
103     return (ext == ".glsl")
104
105
106 def is_c(filename):
107     ext = splitext(filename)[1]
108     return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc"))
109
110
111 def is_c_any(filename):
112     return is_c(filename) or is_c_header(filename)
113
114
115 def is_svn_file(filename):
116     dn, fn = os.path.split(filename)
117     filename_svn = join(dn, ".svn", "text-base", "%s.svn-base" % fn)
118     return exists(filename_svn)
119
120
121 def is_project_file(filename):
122     return (is_c_any(filename) or is_cmake(filename) or is_glsl(filename))  # and is_svn_file(filename)
123
124
125 def cmake_advanced_info():
126     """ Extracr includes and defines from cmake.
127     """
128
129     def create_eclipse_project(CMAKE_DIR):
130         print("CMAKE_DIR %r" % CMAKE_DIR)
131         if sys.platform == "win32":
132             cmd = 'cmake "%s" -G"Eclipse CDT4 - MinGW Makefiles"' % CMAKE_DIR
133         else:
134             cmd = 'cmake "%s" -G"Eclipse CDT4 - Unix Makefiles"' % CMAKE_DIR
135
136         os.system(cmd)
137
138     includes = []
139     defines = []
140
141     create_eclipse_project(CMAKE_DIR)
142
143     from xml.dom.minidom import parse
144     tree = parse(join(CMAKE_DIR, ".cproject"))
145     '''
146     f = open(".cproject_pretty", 'w')
147     f.write(tree.toprettyxml(indent="    ", newl=""))
148     '''
149     ELEMENT_NODE = tree.ELEMENT_NODE
150
151     cproject, = tree.getElementsByTagName("cproject")
152     for storage in cproject.childNodes:
153         if storage.nodeType != ELEMENT_NODE:
154             continue
155
156         if storage.attributes["moduleId"].value == "org.eclipse.cdt.core.settings":
157             cconfig = storage.getElementsByTagName("cconfiguration")[0]
158             for substorage in cconfig.childNodes:
159                 if substorage.nodeType != ELEMENT_NODE:
160                     continue
161
162                 moduleId = substorage.attributes["moduleId"].value
163
164                 # org.eclipse.cdt.core.settings
165                 # org.eclipse.cdt.core.language.mapping
166                 # org.eclipse.cdt.core.externalSettings
167                 # org.eclipse.cdt.core.pathentry
168                 # org.eclipse.cdt.make.core.buildtargets
169
170                 if moduleId == "org.eclipse.cdt.core.pathentry":
171                     for path in substorage.childNodes:
172                         if path.nodeType != ELEMENT_NODE:
173                             continue
174                         kind = path.attributes["kind"].value
175
176                         if kind == "mac":
177                             # <pathentry kind="mac" name="PREFIX" path="" value="&quot;/opt/blender25&quot;"/>
178                             defines.append((path.attributes["name"].value, path.attributes["value"].value))
179                         elif kind == "inc":
180                             # <pathentry include="/data/src/blender/blender/source/blender/editors/include" kind="inc" path="" system="true"/>
181                             includes.append(path.attributes["include"].value)
182                         else:
183                             pass
184
185     return includes, defines
186
187
188 def cmake_cache_var(var):
189     cache_file = open(join(CMAKE_DIR, "CMakeCache.txt"))
190     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("#")]
191     cache_file.close()
192
193     for l in lines:
194         if l.split(":")[0] == var:
195             return l.split("=", 1)[-1]
196     return None
197
198
199 def cmake_compiler_defines():
200     compiler = cmake_cache_var("CMAKE_C_COMPILER")  # could do CXX too
201
202     if compiler is None:
203         print("Couldn't find the compiler, os defines will be omitted...")
204         return
205
206     import tempfile
207     temp_c = tempfile.mkstemp(suffix=".c")[1]
208     temp_def = tempfile.mkstemp(suffix=".def")[1]
209
210     os.system("%s -dM -E %s > %s" % (compiler, temp_c, temp_def))
211
212     temp_def_file = open(temp_def)
213     lines = [l.strip() for l in temp_def_file if l.strip()]
214     temp_def_file.close()
215
216     os.remove(temp_c)
217     os.remove(temp_def)
218     return lines