OSDN Git Service

scons: Indent abbreviated command line strings, so command messages stand out.
[android-x86/external-mesa.git] / scons / gallium.py
1 """gallium
2
3 Frontend-tool for Gallium3D architecture.
4
5 """
6
7 #
8 # Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
9 # All Rights Reserved.
10 #
11 # Permission is hereby granted, free of charge, to any person obtaining a
12 # copy of this software and associated documentation files (the
13 # "Software"), to deal in the Software without restriction, including
14 # without limitation the rights to use, copy, modify, merge, publish,
15 # distribute, sub license, and/or sell copies of the Software, and to
16 # permit persons to whom the Software is furnished to do so, subject to
17 # the following conditions:
18 #
19 # The above copyright notice and this permission notice (including the
20 # next paragraph) shall be included in all copies or substantial portions
21 # of the Software.
22 #
23 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
26 # IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
27 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #
31
32
33 import os
34 import os.path
35 import re
36
37 import SCons.Action
38 import SCons.Builder
39 import SCons.Scanner
40
41
42 def quietCommandLines(env):
43     # Quiet command lines
44     # See also http://www.scons.org/wiki/HidingCommandLinesInOutput
45     env['ASCOMSTR'] = "  Assembling $SOURCE ..."
46     env['ASPPCOMSTR'] = "  Assembling $SOURCE ..."
47     env['CCCOMSTR'] = "  Compiling $SOURCE ..."
48     env['SHCCCOMSTR'] = "  Compiling $SOURCE ..."
49     env['CXXCOMSTR'] = "  Compiling $SOURCE ..."
50     env['SHCXXCOMSTR'] = "  Compiling $SOURCE ..."
51     env['ARCOMSTR'] = "  Archiving $TARGET ..."
52     env['RANLIBCOMSTR'] = "  Indexing $TARGET ..."
53     env['LINKCOMSTR'] = "  Linking $TARGET ..."
54     env['SHLINKCOMSTR'] = "  Linking $TARGET ..."
55     env['LDMODULECOMSTR'] = "  Linking $TARGET ..."
56     env['SWIGCOMSTR'] = "  Generating $TARGET ..."
57
58
59 def createConvenienceLibBuilder(env):
60     """This is a utility function that creates the ConvenienceLibrary
61     Builder in an Environment if it is not there already.
62
63     If it is already there, we return the existing one.
64
65     Based on the stock StaticLibrary and SharedLibrary builders.
66     """
67
68     try:
69         convenience_lib = env['BUILDERS']['ConvenienceLibrary']
70     except KeyError:
71         action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
72         if env.Detect('ranlib'):
73             ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
74             action_list.append(ranlib_action)
75
76         convenience_lib = SCons.Builder.Builder(action = action_list,
77                                   emitter = '$LIBEMITTER',
78                                   prefix = '$LIBPREFIX',
79                                   suffix = '$LIBSUFFIX',
80                                   src_suffix = '$SHOBJSUFFIX',
81                                   src_builder = 'SharedObject')
82         env['BUILDERS']['ConvenienceLibrary'] = convenience_lib
83
84     return convenience_lib
85
86
87 # TODO: handle import statements with multiple modules
88 # TODO: handle from import statements
89 import_re = re.compile(r'^import\s+(\S+)$', re.M)
90
91 def python_scan(node, env, path):
92     # http://www.scons.org/doc/0.98.5/HTML/scons-user/c2781.html#AEN2789
93     contents = node.get_contents()
94     source_dir = node.get_dir()
95     imports = import_re.findall(contents)
96     results = []
97     for imp in imports:
98         for dir in path:
99             file = os.path.join(str(dir), imp.replace('.', os.sep) + '.py')
100             if os.path.exists(file):
101                 results.append(env.File(file))
102                 break
103             file = os.path.join(str(dir), imp.replace('.', os.sep), '__init__.py')
104             if os.path.exists(file):
105                 results.append(env.File(file))
106                 break
107     return results
108
109 python_scanner = SCons.Scanner.Scanner(function = python_scan, skeys = ['.py'])
110
111
112 def code_generate(env, script, target, source, command):
113     """Method to simplify code generation via python scripts.
114
115     http://www.scons.org/wiki/UsingCodeGenerators
116     http://www.scons.org/doc/0.98.5/HTML/scons-user/c2768.html
117     """
118
119     # We're generating code using Python scripts, so we have to be
120     # careful with our scons elements.  This entry represents
121     # the generator file *in the source directory*.
122     script_src = env.File(script).srcnode()
123
124     # This command creates generated code *in the build directory*.
125     command = command.replace('$SCRIPT', script_src.path)
126     code = env.Command(target, source, command)
127
128     # Explicitly mark that the generated code depends on the generator,
129     # and on implicitly imported python modules
130     path = (script_src.get_dir(),)
131     deps = [script_src]
132     deps += script_src.get_implicit_deps(env, python_scanner, path)
133     env.Depends(code, deps)
134
135     # Running the Python script causes .pyc files to be generated in the
136     # source directory.  When we clean up, they should go too. So add side
137     # effects for .pyc files
138     for dep in deps:
139         pyc = env.File(str(dep) + 'c')
140         env.SideEffect(pyc, code)
141
142     return code
143
144
145 def createCodeGenerateMethod(env):
146     env.Append(SCANNERS = python_scanner)
147     env.AddMethod(code_generate, 'CodeGenerate')
148
149
150 def symlink(target, source, env):
151     target = str(target[0])
152     source = str(source[0])
153     if os.path.islink(target) or os.path.exists(target):
154         os.remove(target)
155     os.symlink(os.path.basename(source), target)
156
157 def install_shared_library(env, source, version = ()):
158     source = str(source[0])
159     version = tuple(map(str, version))
160     target_dir =  os.path.join(env.Dir('#.').srcnode().abspath, env['build'], 'lib')
161     target_name = '.'.join((str(source),) + version)
162     last = env.InstallAs(os.path.join(target_dir, target_name), source)
163     while len(version):
164         version = version[:-1]
165         target_name = '.'.join((str(source),) + version)
166         action = SCons.Action.Action(symlink, "$TARGET -> $SOURCE")
167         last = env.Command(os.path.join(target_dir, target_name), last, action) 
168
169 def createInstallMethods(env):
170     env.AddMethod(install_shared_library, 'InstallSharedLibrary')
171
172
173 def num_jobs():
174     try:
175         return int(os.environ['NUMBER_OF_PROCESSORS'])
176     except (ValueError, KeyError):
177         pass
178
179     try:
180         return os.sysconf('SC_NPROCESSORS_ONLN')
181     except (ValueError, OSError, AttributeError):
182         pass
183
184     try:
185         return int(os.popen2("sysctl -n hw.ncpu")[1].read())
186     except ValueError:
187         pass
188
189     return 1
190
191
192 def generate(env):
193     """Common environment generation code"""
194
195     if env.get('quiet', True):
196         quietCommandLines(env)
197
198     # Toolchain
199     platform = env['platform']
200     if env['toolchain'] == 'default':
201         if platform == 'winddk':
202             env['toolchain'] = 'winddk'
203         elif platform == 'wince':
204             env['toolchain'] = 'wcesdk'
205     env.Tool(env['toolchain'])
206
207     env['gcc'] = 'gcc' in os.path.basename(env['CC']).split('-')
208     env['msvc'] = env['CC'] == 'cl'
209
210     # shortcuts
211     debug = env['debug']
212     machine = env['machine']
213     platform = env['platform']
214     x86 = env['machine'] == 'x86'
215     ppc = env['machine'] == 'ppc'
216     gcc = env['gcc']
217     msvc = env['msvc']
218
219     # Put build output in a separate dir, which depends on the current
220     # configuration. See also http://www.scons.org/wiki/AdvancedBuildExample
221     build_topdir = 'build'
222     build_subdir = env['platform']
223     if env['llvm']:
224         build_subdir += "-llvm"
225     if env['machine'] != 'generic':
226         build_subdir += '-' + env['machine']
227     if env['debug']:
228         build_subdir += "-debug"
229     if env['profile']:
230         build_subdir += "-profile"
231     build_dir = os.path.join(build_topdir, build_subdir)
232     # Place the .sconsign file in the build dir too, to avoid issues with
233     # different scons versions building the same source file
234     env['build'] = build_dir
235     env.SConsignFile(os.path.join(build_dir, '.sconsign'))
236     env.CacheDir('build/cache')
237
238     # Parallel build
239     if env.GetOption('num_jobs') <= 1:
240         env.SetOption('num_jobs', num_jobs())
241
242     # C preprocessor options
243     cppdefines = []
244     if debug:
245         cppdefines += ['DEBUG']
246     else:
247         cppdefines += ['NDEBUG']
248     if env['profile']:
249         cppdefines += ['PROFILE']
250     if platform == 'windows':
251         cppdefines += [
252             'WIN32',
253             '_WINDOWS',
254             #'_UNICODE',
255             #'UNICODE',
256             ('_WIN32_WINNT', '0x0501'), # minimum required OS version
257             ('WINVER', '0x0501'),
258             # http://msdn2.microsoft.com/en-us/library/6dwk3a1z.aspx,
259             'WIN32_LEAN_AND_MEAN',
260         ]
261         if msvc and env['toolchain'] != 'winddk':
262             cppdefines += [
263                 'VC_EXTRALEAN',
264                 '_CRT_SECURE_NO_DEPRECATE',
265             ]
266         if debug:
267             cppdefines += ['_DEBUG']
268     if env['toolchain'] == 'winddk':
269         # Mimic WINDDK's builtin flags. See also:
270         # - WINDDK's bin/makefile.new i386mk.inc for more info.
271         # - buildchk_wxp_x86.log files, generated by the WINDDK's build
272         # - http://alter.org.ua/docs/nt_kernel/vc8_proj/
273         if machine == 'x86':
274             cppdefines += ['_X86_', 'i386']
275         if machine == 'x86_64':
276             cppdefines += ['_AMD64_', 'AMD64']
277     if platform == 'winddk':
278         cppdefines += [
279             'STD_CALL',
280             ('CONDITION_HANDLING', '1'),
281             ('NT_INST', '0'),
282             ('WIN32', '100'),
283             ('_NT1X_', '100'),
284             ('WINNT', '1'),
285             ('_WIN32_WINNT', '0x0501'), # minimum required OS version
286             ('WINVER', '0x0501'),
287             ('_WIN32_IE', '0x0603'),
288             ('WIN32_LEAN_AND_MEAN', '1'),
289             ('DEVL', '1'),
290             ('__BUILDMACHINE__', 'WinDDK'),
291             ('FPO', '0'),
292         ]
293         if debug:
294             cppdefines += [('DBG', 1)]
295     if platform == 'wince':
296         cppdefines += [
297             '_CRT_SECURE_NO_DEPRECATE',
298             '_USE_32BIT_TIME_T',
299             'UNICODE',
300             '_UNICODE',
301             ('UNDER_CE', '600'),
302             ('_WIN32_WCE', '0x600'),
303             'WINCEOEM',
304             'WINCEINTERNAL',
305             'WIN32',
306             'STRICT',
307             'x86',
308             '_X86_',
309             'INTERNATIONAL',
310             ('INTLMSG_CODEPAGE', '1252'),
311         ]
312     if platform == 'windows':
313         cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_USER']
314     if platform == 'winddk':
315         cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_DISPLAY']
316     if platform == 'wince':
317         cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_CE']
318         cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_CE_OGL']
319     env.Append(CPPDEFINES = cppdefines)
320
321     # C compiler options
322     cflags = []
323     if gcc:
324         if debug:
325             cflags += ['-O0', '-g3']
326         elif env['toolchain'] == 'crossmingw':
327             cflags += ['-O0', '-g3'] # mingw 4.2.1 optimizer is broken
328         else:
329             cflags += ['-O3', '-g3']
330         if env['profile']:
331             cflags += ['-pg']
332         if env['machine'] == 'x86':
333             cflags += [
334                 '-m32',
335                 #'-march=pentium4',
336                 '-mmmx', '-msse', '-msse2', # enable SIMD intrinsics
337                 #'-mfpmath=sse',
338             ]
339         if env['machine'] == 'x86_64':
340             cflags += ['-m64']
341         # See also:
342         # - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
343         cflags += [
344             '-Werror=declaration-after-statement',
345             '-Wall',
346             '-Wmissing-prototypes',
347             '-Wmissing-field-initializers',
348             '-Wpointer-arith',
349             '-Wno-long-long',
350             '-ffast-math',
351             '-std=gnu99',
352             '-fmessage-length=0', # be nice to Eclipse
353         ]
354     if msvc:
355         # See also:
356         # - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
357         # - cl /?
358         if debug:
359             cflags += [
360               '/Od', # disable optimizations
361               '/Oi', # enable intrinsic functions
362               '/Oy-', # disable frame pointer omission
363               '/GL-', # disable whole program optimization
364             ]
365         else:
366             cflags += [
367                 '/O2', # optimize for speed
368                 #'/fp:fast', # fast floating point 
369             ]
370         if env['profile']:
371             cflags += [
372                 '/Gh', # enable _penter hook function
373                 '/GH', # enable _pexit hook function
374             ]
375         cflags += [
376             '/W3', # warning level
377             #'/Wp64', # enable 64 bit porting warnings
378         ]
379         if env['machine'] == 'x86':
380             cflags += [
381                 #'/QIfist', # Suppress _ftol
382                 #'/arch:SSE2', # use the SSE2 instructions
383             ]
384         if platform == 'windows':
385             cflags += [
386                 # TODO
387             ]
388         if platform == 'winddk':
389             cflags += [
390                 '/Zl', # omit default library name in .OBJ
391                 '/Zp8', # 8bytes struct member alignment
392                 '/Gy', # separate functions for linker
393                 '/Gm-', # disable minimal rebuild
394                 '/WX', # treat warnings as errors
395                 '/Gz', # __stdcall Calling convention
396                 '/GX-', # disable C++ EH
397                 '/GR-', # disable C++ RTTI
398                 '/GF', # enable read-only string pooling
399                 '/G6', # optimize for PPro, P-II, P-III
400                 '/Ze', # enable extensions
401                 '/Gi-', # disable incremental compilation
402                 '/QIfdiv-', # disable Pentium FDIV fix
403                 '/hotpatch', # prepares an image for hotpatching.
404                 #'/Z7', #enable old-style debug info
405             ]
406         if platform == 'wince':
407             # See also C:\WINCE600\public\common\oak\misc\makefile.def
408             cflags += [
409                 '/Zl', # omit default library name in .OBJ
410                 '/GF', # enable read-only string pooling
411                 '/GR-', # disable C++ RTTI
412                 '/GS', # enable security checks
413                 # Allow disabling language conformance to maintain backward compat
414                 #'/Zc:wchar_t-', # don't force wchar_t as native type, instead of typedef
415                 #'/Zc:forScope-', # don't enforce Standard C++ for scoping rules
416                 #'/wd4867',
417                 #'/wd4430',
418                 #'/MT',
419                 #'/U_MT',
420             ]
421         # Automatic pdb generation
422         # See http://scons.tigris.org/issues/show_bug.cgi?id=1656
423         env.EnsureSConsVersion(0, 98, 0)
424         env['PDB'] = '${TARGET.base}.pdb'
425     env.Append(CFLAGS = cflags)
426     env.Append(CXXFLAGS = cflags)
427
428     if env['platform'] == 'windows' and msvc:
429         # Choose the appropriate MSVC CRT
430         # http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
431         if env['debug']:
432             env.Append(CCFLAGS = ['/MTd'])
433             env.Append(SHCCFLAGS = ['/LDd'])
434         else:
435             env.Append(CCFLAGS = ['/MT'])
436             env.Append(SHCCFLAGS = ['/LD'])
437     
438     # Assembler options
439     if gcc:
440         if env['machine'] == 'x86':
441             env.Append(ASFLAGS = ['-m32'])
442         if env['machine'] == 'x86_64':
443             env.Append(ASFLAGS = ['-m64'])
444
445     # Linker options
446     linkflags = []
447     if gcc:
448         if env['machine'] == 'x86':
449             linkflags += ['-m32']
450         if env['machine'] == 'x86_64':
451             linkflags += ['-m64']
452     if platform == 'windows' and msvc:
453         # See also:
454         # - http://msdn2.microsoft.com/en-us/library/y0zzbyt4.aspx
455         linkflags += [
456             '/fixed:no',
457             '/incremental:no',
458         ]
459     if platform == 'winddk':
460         linkflags += [
461             '/merge:_PAGE=PAGE',
462             '/merge:_TEXT=.text',
463             '/section:INIT,d',
464             '/opt:ref',
465             '/opt:icf',
466             '/ignore:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221',
467             '/incremental:no',
468             '/fullbuild',
469             '/release',
470             '/nodefaultlib',
471             '/wx',
472             '/debug',
473             '/debugtype:cv',
474             '/version:5.1',
475             '/osversion:5.1',
476             '/functionpadmin:5',
477             '/safeseh',
478             '/pdbcompress',
479             '/stack:0x40000,0x1000',
480             '/driver',
481             '/align:0x80',
482             '/subsystem:native,5.01',
483             '/base:0x10000',
484
485             '/entry:DrvEnableDriver',
486         ]
487         if env['debug'] or env['profile']:
488             linkflags += [
489                 '/MAP', # http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
490             ]
491     if platform == 'wince':
492         linkflags += [
493             '/nodefaultlib',
494             #'/incremental:no',
495             #'/fullbuild',
496             '/entry:_DllMainCRTStartup',
497         ]
498     env.Append(LINKFLAGS = linkflags)
499
500     # Default libs
501     env.Append(LIBS = [])
502
503     # Custom builders and methods
504     createConvenienceLibBuilder(env)
505     createCodeGenerateMethod(env)
506     createInstallMethods(env)
507
508     # for debugging
509     #print env.Dump()
510
511
512 def exists(env):
513     return 1