+ WITH_BF_OPENAL=0 should now actually not need OpenAL stuff
[blender.git] / tools / Blender.py
1 #!/usr/bin/env python
2
3 """
4 tools.BlenderEnvironment
5
6 This environment builds on SCons.Script.SConscript.SConsEnvironment
7
8 * library repository
9 * custom printout
10 * wrapper functions
11
12 TODO: clean up and sanitise code - crosscheck with btools and SConstruct
13 to kill any code duplication
14 """
15
16 import os.path
17 import string
18 import glob
19 import time
20 import sys
21
22 from SCons.Script.SConscript import SConsEnvironment
23 import SCons.Action
24 import SCons.Util
25 import SCons.Builder
26 import SCons.Tool
27 import bcolors
28 bc = bcolors.bcolors()
29
30 Split = SCons.Util.Split
31 Action = SCons.Action.Action
32 Builder = SCons.Builder.Builder
33 GetBuildPath = SConsEnvironment.GetBuildPath
34
35 # a few globals
36 root_build_dir = ''
37 quickie = None # Anything else than None if BF_QUICK has been passed
38 quicklist = [] # The list of libraries/programs to compile during a quickie
39 program_list = [] # A list holding Nodes to final binaries, used to create installs
40 arguments = None
41 targets = None
42
43 #some internals
44 blenderdeps = [] # don't manipulate this one outside this module!
45
46 ##### LIB STUFF ##########
47
48 possible_types = ['core'] # can be set in ie. SConstruct
49 libs = {}
50 def init_lib_dict():
51     for pt in possible_types:
52         libs[pt] = {}
53
54 # helper func for add_lib_to_dict
55 def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
56     if not libname in dict[libtype]:
57         done = None
58         while not done:
59             if dict[libtype].has_key(priority):
60                 priority = priority + 1
61             else:
62                 done = True
63         dict[libtype][priority] = libname
64
65 # libtype and priority can both be lists, for defining lib in multiple places
66 def add_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
67     if not dict or not libtype or not libname:
68         print "Passed wrong arg"
69         Exit()
70
71     if type(libtype) is str and type(priority) is int:
72         internal_lib_to_dict(dict, libtype, libname, priority)
73     elif type(libtype) is list and type(priority) is list:
74         if len(libtype)==len(priority):
75             for lt, p in zip(libtype, priority):
76                 internal_lib_to_dict(dict, lt, libname, p)
77         else:
78             print "libtype and priority lists are unequal in length"
79             Exit()
80     else:
81         print "Wrong type combinations for libtype and priority. Only str and int or list and list"
82         Exit()
83
84 #libs = init_lib_dict(libs)
85
86 def create_blender_liblist(lenv = None, libtype = None):
87     if not lenv or not libtype:
88         print "missing arg"
89
90     lst = []
91     if libtype in possible_types:
92         sortlist = []
93         for k,v in libs[libtype].iteritems():
94             sortlist.append(k)
95         sortlist.sort()
96         curlib = libs[libtype]
97         for sk in sortlist:
98             v = curlib[sk]
99         #for k,v in sorted(libs[libtype].iteritems()):
100             lst.append('#' + root_build_dir + 'lib/'+lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
101
102     return lst
103
104 ## TODO: static linking
105 def setup_staticlibs(lenv):
106     statlibs = [
107         #here libs for static linking
108     ]
109     libincs = [
110         '/usr/lib',
111         lenv['BF_PYTHON_LIBPATH'],
112         lenv['BF_OPENGL_LIBPATH'],
113         lenv['BF_SDL_LIBPATH'],
114         lenv['BF_JPEG_LIBPATH'],
115         lenv['BF_TIFF_LIBPATH'],
116         lenv['BF_PNG_LIBPATH'],
117         lenv['BF_GETTEXT_LIBPATH'],
118         lenv['BF_ZLIB_LIBPATH'],
119         lenv['BF_FREETYPE_LIBPATH'],
120 #        lenv['BF_QUICKTIME_LIBPATH'],
121         lenv['BF_ICONV_LIBPATH']
122         ]
123     libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
124
125     if lenv['WITH_BF_OPENAL']:
126         lenv['BF_OPENAL_LIBPATH']
127
128     return statlibs, libincs
129
130 def setup_syslibs(lenv):
131     syslibs = [
132         lenv['BF_PYTHON_LIB'],
133         lenv['BF_JPEG_LIB'],
134         lenv['BF_PNG_LIB'],
135         lenv['BF_ZLIB_LIB'],
136         lenv['BF_FREETYPE_LIB'],
137         lenv['BF_GETTEXT_LIB']
138         ]
139     if lenv['WITH_BF_OPENAL']:
140        lenv['BF_OPENAL_LIB'],
141     if lenv['OURPLATFORM']=='win32vc':
142             syslibs += Split(lenv['BF_ICONV_LIB'])
143     syslibs += Split(lenv['BF_TIFF_LIB'])
144     syslibs += Split(lenv['BF_OPENEXR_LIB'])
145     syslibs += Split(lenv['BF_SDL_LIB'])
146     syslibs += Split(lenv['BF_OPENGL_LIB'])
147     syslibs += Split(lenv['LLIBS'])
148
149     return syslibs
150
151 def propose_priorities():
152     print bc.OKBLUE+"Priorities:"+bc.ENDC
153     for t in possible_types:
154         print bc.OKGREEN+"\t"+t+bc.ENDC
155         new_priority = 0
156         sortlist = []
157         for k,v in libs[t].iteritems():
158             sortlist.append(k)
159         sortlist.sort()
160         curlib = libs[t]
161         for sk in sortlist:
162             v = curlib[sk]
163             #for p,v in sorted(libs[t].iteritems()):
164             print "\t\t",new_priority, v
165             new_priority += 5
166
167 ## TODO: see if this can be made in an emitter
168 def buildinfo(lenv, build_type):
169     """
170     Generate a buildinfo object
171     """
172     build_date = time.strftime ("%Y-%m-%d")
173     build_time = time.strftime ("%H:%M:%S")
174     obj = []
175     if lenv['BF_BUILDINFO']==1: #user_options_dict['USE_BUILDINFO'] == 1:
176         if sys.platform=='win32':
177             build_info_file = open("source/creator/winbuildinfo.h", 'w')
178             build_info_file.write("char *build_date=\"%s\";\n"%build_date)
179             build_info_file.write("char *build_time=\"%s\";\n"%build_time)
180             build_info_file.write("char *build_platform=\"win32\";\n")
181             build_info_file.write("char *build_type=\"dynamic\";\n")
182             build_info_file.close()
183             lenv.Append (CPPDEFINES = ['NAN_BUILDINFO', 'BUILD_DATE'])
184         else:
185             lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
186                                         'BUILD_DATE=\'"%s"\''%(build_date),
187                                         'BUILD_TYPE=\'"dynamic"\'',
188                                         'NAN_BUILDINFO',
189                                         'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
190         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
191                         [root_build_dir+'source/creator/buildinfo.c'])]
192     return obj
193
194 ##### END LIB STUFF ############
195
196 ##### ACTION STUFF #############
197
198 def my_compile_print(target, source, env):
199     a = '%s' % (source[0])
200     d, f = os.path.split(a)
201     return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
202
203 def my_moc_print(target, source, env):
204     a = '%s' % (source[0])
205     d, f = os.path.split(a)
206     return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
207
208 def my_linking_print(target, source, env):
209     t = '%s' % (target[0])
210     d, f = os.path.split(t)
211     return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
212
213 def my_program_print(target, source, env):
214     t = '%s' % (target[0])
215     d, f = os.path.split(t)
216     return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
217
218 def msvc_hack(env):
219     static_lib = SCons.Tool.createStaticLibBuilder(env)
220     program = SCons.Tool.createProgBuilder(env)
221     
222     env['BUILDERS']['Library'] = static_lib
223     env['BUILDERS']['StaticLibrary'] = static_lib
224     env['BUILDERS']['Program'] = program
225         
226 def set_quiet_output(env):
227     mycaction = Action("$CCCOM", strfunction=my_compile_print)
228     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
229     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
230     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
231     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
232     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
233
234     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
235     static_ob.add_action('.c', mycaction)
236     static_ob.add_action('.cpp', mycppaction)
237     shared_ob.add_action('.c', myshcaction)
238     shared_ob.add_action('.cpp', myshcppaction)
239
240     static_lib = SCons.Builder.Builder(action = mylibaction,
241                                        emitter = '$LIBEMITTER',
242                                        prefix = '$LIBPREFIX',
243                                        suffix = '$LIBSUFFIX',
244                                        src_suffix = '$OBJSUFFIX',
245                                        src_builder = 'StaticObject')
246
247     program = SCons.Builder.Builder(action = mylinkaction,
248                                     emitter = '$PROGEMITTER',
249                                     prefix = '$PROGPREFIX',
250                                     suffix = '$PROGSUFFIX',
251                                     src_suffix = '$OBJSUFFIX',
252                                     src_builder = 'Object',
253                                     target_scanner = SCons.Defaults.ProgScan)
254
255     env['BUILDERS']['Object'] = static_ob
256     env['BUILDERS']['StaticObject'] = static_ob
257     env['BUILDERS']['StaticLibrary'] = static_lib
258     env['BUILDERS']['Library'] = static_lib
259     env['BUILDERS']['Program'] = program
260
261
262 #### END ACTION STUFF #########
263
264 class BlenderEnvironment(SConsEnvironment):
265
266     def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None):
267         if not self or not libname or not sources:
268             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
269             Exit()
270         if libname in quickie or len(quickie)==0:
271             print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
272             lenv = self.Copy()
273             lenv.Append(CPPPATH=includes)
274             lenv.Append(CPPDEFINES=defines)
275             if lenv['WITH_BF_GAMEENGINE']:
276                     lenv.Append(CPPDEFINES=['GAMEBLENDER=1'])
277             if lenv['BF_DEBUG']:
278                     lenv.Append(CFLAGS = lenv['BF_DEBUG_FLAGS'], CCFLAGS = lenv['BF_DEBUG_FLAGS'])
279             else:
280                     lenv.Append(CFLAGS = lenv['REL_CFLAGS'], CCFLAGS = lenv['REL_CCFLAGS'])
281             if lenv['BF_PROFILE']:
282                     lenv.Append(CFLAGS = lenv['BF_PROFILE_FLAGS'], CCFLAGS = lenv['BF_PROFILE_FLAGS'])
283             if compileflags:
284                 lenv.Append(CFLAGS = compileflags)
285                 lenv.Append(CCFLAGS = compileflags)
286             lenv.Append(CFLAGS = Split(lenv['C_WARN']))
287             lenv.Append(CCFLAGS = Split(lenv['CC_WARN']))
288             lib = lenv.Library(target= '#'+root_build_dir+'lib/'+libname, source=sources)
289             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
290         else:
291             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
292         # note: libs is a global
293         add_lib_to_dict(libs, libtype, libname, priority)
294
295     def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None):
296         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
297         lenv = self.Copy()
298         if lenv['OURPLATFORM']=='win32-vc':
299             lenv.Append(LINKFLAGS = Split(lenv['PLATFORM_LINKFLAGS']))
300         if  lenv['OURPLATFORM']=='darwin':
301             lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
302             lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
303             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
304         lenv.Append(CPPPATH=includes)
305         lenv.Append(LIBPATH=libpath)
306         lenv.Append(LIBS=libs)
307         if lenv['WITH_BF_QUICKTIME']:
308              lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
309              lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
310         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
311         SConsEnvironment.Default(self, prog)
312         program_list.append(prog)
313
314 ## TODO: have register for libs/programs, so that we test only that
315 #  which have expressed their need to be tested in their own sconscript
316     def BlenderUnitTest(env, source, **kwargs):
317         test = env.Program(source, **kwargs)
318         env.AddPostAction(test, test[0].abspath)
319         env.Alias('check', test)
320         env.AlwaysBuild(test)
321         return test
322
323     def Glob(lenv, pattern):
324         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
325         files = []
326         for i in glob.glob(path + pattern):
327             files.append(string.replace(i, path, ''))
328         return files