- removed redundant code
[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        syslibs += Split(lenv['BF_OPENAL_LIB'])
141     if lenv['OURPLATFORM']=='win32vc':
142             syslibs += Split(lenv['BF_ICONV_LIB'])
143     syslibs += Split(lenv['BF_TIFF_LIB'])
144     if lenv['WITH_BF_OPENEXR']:
145         syslibs += Split(lenv['BF_OPENEXR_LIB'])
146     syslibs += Split(lenv['BF_SDL_LIB'])
147     syslibs += Split(lenv['BF_OPENGL_LIB'])
148     syslibs += Split(lenv['LLIBS'])
149
150     return syslibs
151
152 def propose_priorities():
153     print bc.OKBLUE+"Priorities:"+bc.ENDC
154     for t in possible_types:
155         print bc.OKGREEN+"\t"+t+bc.ENDC
156         new_priority = 0
157         sortlist = []
158         for k,v in libs[t].iteritems():
159             sortlist.append(k)
160         sortlist.sort()
161         curlib = libs[t]
162         for sk in sortlist:
163             v = curlib[sk]
164             #for p,v in sorted(libs[t].iteritems()):
165             print "\t\t",new_priority, v
166             new_priority += 5
167
168 ## TODO: see if this can be made in an emitter
169 def buildinfo(lenv, build_type):
170     """
171     Generate a buildinfo object
172     """
173     build_date = time.strftime ("%Y-%m-%d")
174     build_time = time.strftime ("%H:%M:%S")
175     obj = []
176     if lenv['BF_BUILDINFO']==1: #user_options_dict['USE_BUILDINFO'] == 1:
177         if sys.platform=='win32':
178             build_info_file = open("source/creator/winbuildinfo.h", 'w')
179             build_info_file.write("char *build_date=\"%s\";\n"%build_date)
180             build_info_file.write("char *build_time=\"%s\";\n"%build_time)
181             build_info_file.write("char *build_platform=\"win32\";\n")
182             build_info_file.write("char *build_type=\"dynamic\";\n")
183             build_info_file.close()
184             lenv.Append (CPPDEFINES = ['NAN_BUILDINFO', 'BUILD_DATE'])
185         else:
186             lenv.Append (CPPDEFINES = ['BUILD_TIME=\'"%s"\''%(build_time),
187                                         'BUILD_DATE=\'"%s"\''%(build_date),
188                                         'BUILD_TYPE=\'"dynamic"\'',
189                                         'NAN_BUILDINFO',
190                                         'BUILD_PLATFORM=\'"%s"\''%(sys.platform)])
191         obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type,
192                         [root_build_dir+'source/creator/buildinfo.c'])]
193     return obj
194
195 ##### END LIB STUFF ############
196
197 ##### ACTION STUFF #############
198
199 def my_compile_print(target, source, env):
200     a = '%s' % (source[0])
201     d, f = os.path.split(a)
202     return bc.OKBLUE+"Compiling"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
203
204 def my_moc_print(target, source, env):
205     a = '%s' % (source[0])
206     d, f = os.path.split(a)
207     return bc.OKBLUE+"Creating MOC"+bc.ENDC+ " ==> '"+bc.OKGREEN+"%s" %(f) + "'"+bc.ENDC
208
209 def my_linking_print(target, source, env):
210     t = '%s' % (target[0])
211     d, f = os.path.split(t)
212     return bc.OKBLUE+"Linking library"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
213
214 def my_program_print(target, source, env):
215     t = '%s' % (target[0])
216     d, f = os.path.split(t)
217     return bc.OKBLUE+"Linking program"+bc.ENDC +" ==> '"+bc.OKGREEN+"%s" % (f) + "'"+bc.ENDC
218
219 def msvc_hack(env):
220     static_lib = SCons.Tool.createStaticLibBuilder(env)
221     program = SCons.Tool.createProgBuilder(env)
222     
223     env['BUILDERS']['Library'] = static_lib
224     env['BUILDERS']['StaticLibrary'] = static_lib
225     env['BUILDERS']['Program'] = program
226         
227 def set_quiet_output(env):
228     mycaction = Action("$CCCOM", strfunction=my_compile_print)
229     myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
230     mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
231     myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
232     mylibaction = Action("$ARCOM", strfunction=my_linking_print)
233     mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
234
235     static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
236     static_ob.add_action('.c', mycaction)
237     static_ob.add_action('.cpp', mycppaction)
238     shared_ob.add_action('.c', myshcaction)
239     shared_ob.add_action('.cpp', myshcppaction)
240
241     static_lib = SCons.Builder.Builder(action = mylibaction,
242                                        emitter = '$LIBEMITTER',
243                                        prefix = '$LIBPREFIX',
244                                        suffix = '$LIBSUFFIX',
245                                        src_suffix = '$OBJSUFFIX',
246                                        src_builder = 'StaticObject')
247
248     program = SCons.Builder.Builder(action = mylinkaction,
249                                     emitter = '$PROGEMITTER',
250                                     prefix = '$PROGPREFIX',
251                                     suffix = '$PROGSUFFIX',
252                                     src_suffix = '$OBJSUFFIX',
253                                     src_builder = 'Object',
254                                     target_scanner = SCons.Defaults.ProgScan)
255
256     env['BUILDERS']['Object'] = static_ob
257     env['BUILDERS']['StaticObject'] = static_ob
258     env['BUILDERS']['StaticLibrary'] = static_lib
259     env['BUILDERS']['Library'] = static_lib
260     env['BUILDERS']['Program'] = program
261
262 def  my_appit_print(target, source, env):
263     a = '%s' % (target[0])
264     d, f = os.path.split(a)
265     return "making bundle for " + f
266
267 def AppIt(target=None, source=None, env=None):
268     import shutil
269     import commands
270     import os.path
271     
272     a = '%s' % (target[0])
273     builddir, b = os.path.split(a)
274     bldroot = env.Dir('.').abspath
275     binary = env['BINARYKIND']
276     
277     sourcedir = bldroot + '/source/darwin/%s.app'%binary
278     sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
279     targetinfo = builddir +'/' + "%s.app/Contents/Info.plist"%binary
280     cmd = builddir + '/' +'%s.app'%binary
281     
282     if os.path.isdir(cmd):
283         shutil.rmtree(cmd)
284     shutil.copytree(sourcedir, cmd)
285     cmd = "cat %s | sed s/VERSION/`cat release/VERSION`/ | sed s/DATE/`date +'%%Y-%%b-%%d'`/ > %s"%(sourceinfo,targetinfo)
286     commands.getoutput(cmd)
287     cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,builddir, binary, binary)
288     commands.getoutput(cmd)
289     cmd = 'mkdir %s/%s.app/Contents/MacOS/.blender/'%(builddir, binary)
290     print cmd
291     commands.getoutput(cmd)
292     cmd = builddir + '/%s.app/Contents/MacOS/.blender'%binary
293     shutil.copy(bldroot + '/bin/.blender/.bfont.ttf', cmd)
294     shutil.copy(bldroot + '/bin/.blender/.Blanguages', cmd)
295     cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/Resources/'%(bldroot,builddir,binary)
296     commands.getoutput(cmd) 
297     cmd = 'cp -R %s/bin/.blender/locale %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
298     commands.getoutput(cmd) 
299     cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/.blender/'%(bldroot,builddir,binary)
300     commands.getoutput(cmd)
301     cmd = 'chmod +x  %s/%s.app/Contents/MacOS/%s'%(builddir,binary, binary)
302     commands.getoutput(cmd)
303     cmd = 'find %s/%s.app -name CVS -prune -exec rm -rf {} \;'%(builddir, binary)
304     commands.getoutput(cmd)
305     cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(builddir, binary)
306     commands.getoutput(cmd)
307
308 #### END ACTION STUFF #########
309
310 class BlenderEnvironment(SConsEnvironment):
311
312
313     def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None):
314         if not self or not libname or not sources:
315             print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
316             Exit()
317         if libname in quickie or len(quickie)==0:
318             print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
319             lenv = self.Copy()
320             lenv.Append(CPPPATH=includes)
321             lenv.Append(CPPDEFINES=defines)
322             if lenv['WITH_BF_GAMEENGINE']:
323                     lenv.Append(CPPDEFINES=['GAMEBLENDER=1'])
324             if lenv['BF_DEBUG']:
325                     lenv.Append(CFLAGS = lenv['BF_DEBUG_FLAGS'], CCFLAGS = lenv['BF_DEBUG_FLAGS'])
326             else:
327                     lenv.Append(CFLAGS = lenv['REL_CFLAGS'], CCFLAGS = lenv['REL_CCFLAGS'])
328             if lenv['BF_PROFILE']:
329                     lenv.Append(CFLAGS = lenv['BF_PROFILE_FLAGS'], CCFLAGS = lenv['BF_PROFILE_FLAGS'])
330             if compileflags:
331                 lenv.Append(CFLAGS = compileflags)
332                 lenv.Append(CCFLAGS = compileflags)
333             lenv.Append(CFLAGS = Split(lenv['C_WARN']))
334             lenv.Append(CCFLAGS = Split(lenv['CC_WARN']))
335             lib = lenv.Library(target= '#'+root_build_dir+'lib/'+libname, source=sources)
336             SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
337         else:
338             print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
339         # note: libs is a global
340         add_lib_to_dict(libs, libtype, libname, priority)
341
342     def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''):
343         print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
344         lenv = self.Copy()
345         if lenv['OURPLATFORM']=='win32-vc':
346             lenv.Append(LINKFLAGS = Split(lenv['PLATFORM_LINKFLAGS']))
347         if  lenv['OURPLATFORM']=='darwin':
348             lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
349             lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
350             lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
351         lenv.Append(CPPPATH=includes)
352         lenv.Append(LIBPATH=libpath)
353         lenv.Append(LIBS=libs)
354         if lenv['WITH_BF_QUICKTIME']:
355              lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
356              lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
357         prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
358         SConsEnvironment.Default(self, prog)
359         program_list.append(prog)
360         if  lenv['OURPLATFORM']=='darwin':
361             lenv['BINARYKIND'] = binarykind
362             lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
363
364     def Glob(lenv, pattern):
365         path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
366         files = []
367         for i in glob.glob(path + pattern):
368             files.append(string.replace(i, path, ''))
369         return files