OSDN Git Service

es/glapi: Remove unnecessary extensions from es_COMPAT.
[android-x86/external-mesa.git] / scons / generic.py
1 """generic
2
3 Generic tool that provides a commmon ground for all platforms.
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 import platform as _platform
37 import sys
38
39 import SCons.Action
40 import SCons.Builder
41 import SCons.Scanner
42
43
44 def quietCommandLines(env):
45     # Quiet command lines
46     # See also http://www.scons.org/wiki/HidingCommandLinesInOutput
47     env['CCCOMSTR'] = "Compiling $SOURCE ..."
48     env['CXXCOMSTR'] = "Compiling $SOURCE ..."
49     env['ARCOMSTR'] = "Archiving $TARGET ..."
50     env['RANLIBCOMSTR'] = ""
51     env['LINKCOMSTR'] = "Linking $TARGET ..."
52
53
54 def createConvenienceLibBuilder(env):
55     """This is a utility function that creates the ConvenienceLibrary
56     Builder in an Environment if it is not there already.
57
58     If it is already there, we return the existing one.
59
60     Based on the stock StaticLibrary and SharedLibrary builders.
61     """
62
63     try:
64         convenience_lib = env['BUILDERS']['ConvenienceLibrary']
65     except KeyError:
66         action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
67         if env.Detect('ranlib'):
68             ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
69             action_list.append(ranlib_action)
70
71         convenience_lib = SCons.Builder.Builder(action = action_list,
72                                   emitter = '$LIBEMITTER',
73                                   prefix = '$LIBPREFIX',
74                                   suffix = '$LIBSUFFIX',
75                                   src_suffix = '$SHOBJSUFFIX',
76                                   src_builder = 'SharedObject')
77         env['BUILDERS']['ConvenienceLibrary'] = convenience_lib
78
79     return convenience_lib
80
81
82 # TODO: handle import statements with multiple modules
83 # TODO: handle from import statements
84 import_re = re.compile(r'^import\s+(\S+)$', re.M)
85
86 def python_scan(node, env, path):
87     # http://www.scons.org/doc/0.98.5/HTML/scons-user/c2781.html#AEN2789
88     contents = node.get_contents()
89     source_dir = node.get_dir()
90     imports = import_re.findall(contents)
91     results = []
92     for imp in imports:
93         for dir in path:
94             file = os.path.join(str(dir), imp.replace('.', os.sep) + '.py')
95             if os.path.exists(file):
96                 results.append(env.File(file))
97                 break
98             file = os.path.join(str(dir), imp.replace('.', os.sep), '__init__.py')
99             if os.path.exists(file):
100                 results.append(env.File(file))
101                 break
102     return results
103
104 python_scanner = SCons.Scanner.Scanner(function = python_scan, skeys = ['.py'])
105
106
107 def code_generate(env, script, target, source, command):
108     """Method to simplify code generation via python scripts.
109
110     http://www.scons.org/wiki/UsingCodeGenerators
111     http://www.scons.org/doc/0.98.5/HTML/scons-user/c2768.html
112     """
113
114     # We're generating code using Python scripts, so we have to be
115     # careful with our scons elements.  This entry represents
116     # the generator file *in the source directory*.
117     script_src = env.File(script).srcnode()
118
119     # This command creates generated code *in the build directory*.
120     command = command.replace('$SCRIPT', script_src.path)
121     code = env.Command(target, source, command)
122
123     # Explicitly mark that the generated code depends on the generator,
124     # and on implicitly imported python modules
125     path = (script_src.get_dir(),)
126     deps = [script_src]
127     deps += script_src.get_implicit_deps(env, python_scanner, path)
128     env.Depends(code, deps)
129
130     # Running the Python script causes .pyc files to be generated in the
131     # source directory.  When we clean up, they should go too. So add side
132     # effects for .pyc files
133     for dep in deps:
134         pyc = env.File(str(dep) + 'c')
135         env.SideEffect(pyc, code)
136
137     return code
138
139
140 def createCodeGenerateMethod(env):
141     env.Append(SCANNERS = python_scanner)
142     env.AddMethod(code_generate, 'CodeGenerate')
143
144
145 def symlink(target, source, env):
146     target = str(target[0])
147     source = str(source[0])
148     if os.path.islink(target) or os.path.exists(target):
149         os.remove(target)
150     os.symlink(os.path.basename(source), target)
151
152 def install_shared_library(env, source, version = ()):
153     source = str(source[0])
154     version = tuple(map(str, version))
155     target_dir =  os.path.join(env.Dir('#.').srcnode().abspath, env['build'], 'lib')
156     target_name = '.'.join((str(source),) + version)
157     last = env.InstallAs(os.path.join(target_dir, target_name), source)
158     while len(version):
159         version = version[:-1]
160         target_name = '.'.join((str(source),) + version)
161         action = SCons.Action.Action(symlink, "$TARGET -> $SOURCE")
162         last = env.Command(os.path.join(target_dir, target_name), last, action) 
163
164 def createInstallMethods(env):
165     env.AddMethod(install_shared_library, 'InstallSharedLibrary')
166
167
168 _platform_map = {
169     'linux2': 'linux',
170     'win32': 'windows',
171 }
172
173
174 _machine_map = {
175         'x86': 'x86',
176         'i386': 'x86',
177         'i486': 'x86',
178         'i586': 'x86',
179         'i686': 'x86',
180         'ppc': 'ppc',
181         'x86_64': 'x86_64',
182 }
183
184
185 _toolchain_map = {
186     'winddk': 'winddk',
187     'wince': 'wcesdk',
188 }
189
190
191 _bool_map = {
192     'y': 1, 
193     'yes': 1,
194     't': 1, 
195     'true': 1, 
196     '1': 1,
197     'on': 1,
198     'all': 1, 
199     'n': 0, 
200     'no': 0, 
201     'f': 0, 
202     'false': 0, 
203     '0': 0,
204     'off': 0,
205     'none': 0,
206 }
207
208
209 def num_jobs():
210     try:
211         return int(os.environ['NUMBER_OF_PROCESSORS'])
212     except (ValueError, KeyError):
213         pass
214
215     try:
216         return os.sysconf('SC_NPROCESSORS_ONLN')
217     except (ValueError, OSError, AttributeError):
218         pass
219
220     try:
221         return int(os.popen2("sysctl -n hw.ncpu")[1].read())
222     except ValueError:
223         pass
224
225     return 1
226
227
228 def generate(env):
229     """Common environment generation code"""
230
231     from SCons.Script import ARGUMENTS
232
233     # FIXME: this is already too late
234     #if env.get('quiet', False):
235     #    quietCommandLines(env)
236
237
238     # Platform
239     try:
240         env['platform'] = ARGUMENTS['platform']
241     except KeyError:
242         env['platform'] = _platform_map.get(sys.platform, sys.platform)
243
244     # Machine
245     try:
246         env['machine'] = ARGUMENTS['machine']
247     except KeyError:
248         env['machine'] = _machine_map.get(os.environ.get('PROCESSOR_ARCHITECTURE', _platform.machine()), 'generic')
249
250     # Toolchain
251     try:
252         env['toolchain'] = ARGUMENTS['toolchain']
253     except KeyError:
254         if env['platform'] in ('windows', 'winddk', 'wince') and sys.platform != 'win32':
255             env['toolchain'] = 'crossmingw'
256         else:
257             env['toolchain'] = _toolchain_map.get(env['platform'], 'default')
258     if env['toolchain'] == 'crossmingw' and env['machine'] not in ('generic', 'x86'):
259             env['machine'] = 'x86'
260
261     try:
262         env['MSVS_VERSION'] = ARGUMENTS['MSVS_VERSION']
263     except KeyError:
264         pass
265
266     # Build type
267     env['debug'] = _bool_map[ARGUMENTS.get('debug', 'no')]
268     env['profile'] = _bool_map[ARGUMENTS.get('profile', 'no')]
269
270     # Put build output in a separate dir, which depends on the current
271     # configuration. See also http://www.scons.org/wiki/AdvancedBuildExample
272     try:
273         env['build'] = ARGUMENTS['build']
274     except KeyError:
275         build_topdir = 'build'
276         build_subdir = env['platform']
277         if env['machine'] != 'generic':
278             build_subdir += '-' + env['machine']
279         if env['debug']:
280             build_subdir += "-debug"
281         if env['profile']:
282             build_subdir += "-profile"
283         env['build'] = os.path.join(build_topdir, build_subdir)
284     # Place the .sconsign file in the build dir too, to avoid issues with
285     # different scons versions building the same source file
286     env.SConsignFile(os.path.join(env['build'], '.sconsign'))
287
288     # Parallel build
289     if env.GetOption('num_jobs') <= 1:
290         env.SetOption('num_jobs', num_jobs())
291
292     # Summary
293     print
294     print '  platform=%s' % env['platform']
295     print '  machine=%s' % env['machine']
296     print '  toolchain=%s' % env['toolchain']
297     print '  debug=%s' % ['no', 'yes'][env['debug']]
298     print '  profile=%s' % ['no', 'yes'][env['profile']]
299     print '  build=%s' % env['build']
300     print '  %s jobs' % env.GetOption('num_jobs')
301     print
302
303     # Load tool chain
304     env.Tool(env['toolchain'])
305
306     env['gcc'] = 'gcc' in os.path.basename(env['CC']).split('-')
307     env['msvc'] = env['CC'] == 'cl'
308
309     # shortcuts
310     debug = env['debug']
311     machine = env['machine']
312     platform = env['platform']
313     x86 = env['machine'] == 'x86'
314     ppc = env['machine'] == 'ppc'
315     gcc = env['gcc']
316     msvc = env['msvc']
317
318     # C preprocessor options
319     cppdefines = []
320     if debug:
321         cppdefines += ['DEBUG']
322     else:
323         cppdefines += ['NDEBUG']
324     if env['profile']:
325         cppdefines += ['PROFILE']
326     if platform == 'windows':
327         cppdefines += [
328             'WIN32',
329             '_WINDOWS',
330             #'_UNICODE',
331             #'UNICODE',
332             # http://msdn2.microsoft.com/en-us/library/6dwk3a1z.aspx,
333             #'WIN32_LEAN_AND_MEAN',
334         ]
335         if msvc:
336             cppdefines += [
337                 'VC_EXTRALEAN',
338                 '_CRT_SECURE_NO_DEPRECATE',
339             ]
340         if debug:
341             cppdefines += ['_DEBUG']
342     if platform == 'winddk':
343         # Mimic WINDDK's builtin flags. See also:
344         # - WINDDK's bin/makefile.new i386mk.inc for more info.
345         # - buildchk_wxp_x86.log files, generated by the WINDDK's build
346         # - http://alter.org.ua/docs/nt_kernel/vc8_proj/
347         cppdefines += [
348             ('_X86_', '1'),
349             ('i386', '1'),
350             'STD_CALL',
351             ('CONDITION_HANDLING', '1'),
352             ('NT_INST', '0'),
353             ('WIN32', '100'),
354             ('_NT1X_', '100'),
355             ('WINNT', '1'),
356             ('_WIN32_WINNT', '0x0501'), # minimum required OS version
357             ('WINVER', '0x0501'),
358             ('_WIN32_IE', '0x0603'),
359             ('WIN32_LEAN_AND_MEAN', '1'),
360             ('DEVL', '1'),
361             ('__BUILDMACHINE__', 'WinDDK'),
362             ('FPO', '0'),
363         ]
364         if debug:
365             cppdefines += [('DBG', 1)]
366     if platform == 'wince':
367         cppdefines += [
368             '_CRT_SECURE_NO_DEPRECATE',
369             '_USE_32BIT_TIME_T',
370             'UNICODE',
371             '_UNICODE',
372             ('UNDER_CE', '600'),
373             ('_WIN32_WCE', '0x600'),
374             'WINCEOEM',
375             'WINCEINTERNAL',
376             'WIN32',
377             'STRICT',
378             'x86',
379             '_X86_',
380             'INTERNATIONAL',
381             ('INTLMSG_CODEPAGE', '1252'),
382         ]
383     env.Append(CPPDEFINES = cppdefines)
384
385     # C preprocessor includes
386     if platform == 'winddk':
387         env.Append(CPPPATH = [
388             env['SDK_INC_PATH'],
389             env['DDK_INC_PATH'],
390             env['WDM_INC_PATH'],
391             env['CRT_INC_PATH'],
392         ])
393
394     # C compiler options
395     cflags = [] # C
396     cxxflags = [] # C++
397     ccflags = [] # C & C++
398     if gcc:
399         if debug:
400             ccflags += ['-O0', '-g3']
401         elif env['toolchain'] == 'crossmingw':
402             ccflags += ['-O0', '-g3'] # mingw 4.2.1 optimizer is broken
403         else:
404             ccflags += ['-O3', '-g0']
405         if env['profile']:
406             ccflags += ['-pg']
407         if env['machine'] == 'x86':
408             ccflags += [
409                 '-m32',
410                 #'-march=pentium4',
411                 '-mmmx', '-msse', '-msse2', # enable SIMD intrinsics
412                 #'-mfpmath=sse',
413             ]
414         if env['machine'] == 'x86_64':
415             ccflags += ['-m64']
416         # See also:
417         # - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
418         ccflags += [
419             '-Wall',
420             '-Wmissing-field-initializers',
421             '-Wpointer-arith',
422             '-Wno-long-long',
423             '-ffast-math',
424             '-fmessage-length=0', # be nice to Eclipse
425         ]
426         cflags += [
427             '-Werror=declaration-after-statement',
428             '-Wmissing-prototypes',
429             '-std=gnu99',
430         ]
431     if msvc:
432         # See also:
433         # - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
434         # - cl /?
435         if debug:
436             ccflags += [
437               '/Od', # disable optimizations
438               '/Oi', # enable intrinsic functions
439               '/Oy-', # disable frame pointer omission
440               '/GL-', # disable whole program optimization
441             ]
442         else:
443             ccflags += [
444               '/Ox', # maximum optimizations
445               '/Oi', # enable intrinsic functions
446               '/Ot', # favor code speed
447               #'/fp:fast', # fast floating point 
448             ]
449         if env['profile']:
450             ccflags += [
451                 '/Gh', # enable _penter hook function
452                 '/GH', # enable _pexit hook function
453             ]
454         ccflags += [
455             '/W3', # warning level
456             #'/Wp64', # enable 64 bit porting warnings
457         ]
458         if env['machine'] == 'x86':
459             ccflags += [
460                 #'/QIfist', # Suppress _ftol
461                 #'/arch:SSE2', # use the SSE2 instructions
462             ]
463         if platform == 'windows':
464             ccflags += [
465                 # TODO
466             ]
467         if platform == 'winddk':
468             ccflags += [
469                 '/Zl', # omit default library name in .OBJ
470                 '/Zp8', # 8bytes struct member alignment
471                 '/Gy', # separate functions for linker
472                 '/Gm-', # disable minimal rebuild
473                 '/WX', # treat warnings as errors
474                 '/Gz', # __stdcall Calling convention
475                 '/GX-', # disable C++ EH
476                 '/GR-', # disable C++ RTTI
477                 '/GF', # enable read-only string pooling
478                 '/G6', # optimize for PPro, P-II, P-III
479                 '/Ze', # enable extensions
480                 '/Gi-', # disable incremental compilation
481                 '/QIfdiv-', # disable Pentium FDIV fix
482                 '/hotpatch', # prepares an image for hotpatching.
483                 #'/Z7', #enable old-style debug info
484             ]
485         if platform == 'wince':
486             # See also C:\WINCE600\public\common\oak\misc\makefile.def
487             ccflags += [
488                 '/Zl', # omit default library name in .OBJ
489                 '/GF', # enable read-only string pooling
490                 '/GR-', # disable C++ RTTI
491                 '/GS', # enable security checks
492                 # Allow disabling language conformance to maintain backward compat
493                 #'/Zc:wchar_t-', # don't force wchar_t as native type, instead of typedef
494                 #'/Zc:forScope-', # don't enforce Standard C++ for scoping rules
495                 #'/wd4867',
496                 #'/wd4430',
497                 #'/MT',
498                 #'/U_MT',
499             ]
500         # Automatic pdb generation
501         # See http://scons.tigris.org/issues/show_bug.cgi?id=1656
502         env.EnsureSConsVersion(0, 98, 0)
503         env['PDB'] = '${TARGET.base}.pdb'
504     env.Append(CCFLAGS = ccflags)
505     env.Append(CFLAGS = cflags)
506     env.Append(CXXFLAGS = cxxflags)
507
508     if env['platform'] == 'windows' and msvc:
509         # Choose the appropriate MSVC CRT
510         # http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
511         if env['debug']:
512             env.Append(CCFLAGS = ['/MTd'])
513             env.Append(SHCCFLAGS = ['/LDd'])
514         else:
515             env.Append(CCFLAGS = ['/MT'])
516             env.Append(SHCCFLAGS = ['/LD'])
517     
518     # Assembler options
519     if gcc:
520         if env['machine'] == 'x86':
521             env.Append(ASFLAGS = ['-m32'])
522         if env['machine'] == 'x86_64':
523             env.Append(ASFLAGS = ['-m64'])
524
525     # Linker options
526     linkflags = []
527     if gcc:
528         if env['machine'] == 'x86':
529             linkflags += ['-m32']
530         if env['machine'] == 'x86_64':
531             linkflags += ['-m64']
532     if platform == 'windows' and msvc:
533         # See also:
534         # - http://msdn2.microsoft.com/en-us/library/y0zzbyt4.aspx
535         linkflags += [
536             '/fixed:no',
537             '/incremental:no',
538         ]
539     if platform == 'winddk':
540         linkflags += [
541             '/merge:_PAGE=PAGE',
542             '/merge:_TEXT=.text',
543             '/section:INIT,d',
544             '/opt:ref',
545             '/opt:icf',
546             '/ignore:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221',
547             '/incremental:no',
548             '/fullbuild',
549             '/release',
550             '/nodefaultlib',
551             '/wx',
552             '/debug',
553             '/debugtype:cv',
554             '/version:5.1',
555             '/osversion:5.1',
556             '/functionpadmin:5',
557             '/safeseh',
558             '/pdbcompress',
559             '/stack:0x40000,0x1000',
560             '/driver',
561             '/align:0x80',
562             '/subsystem:native,5.01',
563             '/base:0x10000',
564
565             '/entry:DrvEnableDriver',
566         ]
567         if env['debug'] or env['profile']:
568             linkflags += [
569                 '/MAP', # http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
570             ]
571     if platform == 'wince':
572         linkflags += [
573             '/nodefaultlib',
574             #'/incremental:no',
575             #'/fullbuild',
576             '/entry:_DllMainCRTStartup',
577         ]
578     env.Append(LINKFLAGS = linkflags)
579
580     # Default libs
581     env.Append(LIBS = [])
582
583     # Custom builders and methods
584     createConvenienceLibBuilder(env)
585     createCodeGenerateMethod(env)
586     createInstallMethods(env)
587
588     # for debugging
589     #print env.Dump()
590
591
592 def exists(env):
593     return 1