5
This looks for modules that define a callable object that can modify
6
a construction environment as appropriate for a given tool (or tool
9
Note that because this subsystem just *selects* a callable that can
10
modify a construction environment, it's possible for people to define
11
their own "tool specification" in an arbitrary callable function. No
12
one needs to use or tie in to this subsystem in order to roll their own
17
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
19
# Permission is hereby granted, free of charge, to any person obtaining
20
# a copy of this software and associated documentation files (the
21
# "Software"), to deal in the Software without restriction, including
22
# without limitation the rights to use, copy, modify, merge, publish,
23
# distribute, sublicense, and/or sell copies of the Software, and to
24
# permit persons to whom the Software is furnished to do so, subject to
25
# the following conditions:
27
# The above copyright notice and this permission notice shall be included
28
# in all copies or substantial portions of the Software.
30
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
31
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
32
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39
__revision__ = "src/engine/SCons/Tool/__init__.py 2523 2007/12/12 09:37:41 knight"
48
import SCons.Scanner.C
49
import SCons.Scanner.D
50
import SCons.Scanner.LaTeX
51
import SCons.Scanner.Prog
55
CScanner = SCons.Scanner.C.CScanner()
56
DScanner = SCons.Scanner.D.DScanner()
57
LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
58
ProgramScanner = SCons.Scanner.Prog.ProgramScanner()
59
SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner')
61
CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
62
".h", ".H", ".hxx", ".hpp", ".hh",
69
IDLSuffixes = [".idl", ".IDL"]
71
LaTeXSuffixes = [".tex", ".ltx", ".latex"]
73
for suffix in CSuffixes:
74
SourceFileScanner.add_scanner(suffix, CScanner)
76
for suffix in DSuffixes:
77
SourceFileScanner.add_scanner(suffix, DScanner)
79
for suffix in LaTeXSuffixes:
80
SourceFileScanner.add_scanner(suffix, LaTeXScanner)
83
def __init__(self, name, toolpath=[], **kw):
85
self.toolpath = toolpath + DefaultToolpath
86
# remember these so we can merge them into the call
89
module = self._tool_module()
90
self.generate = module.generate
91
self.exists = module.exists
92
if hasattr(module, 'options'):
93
self.options = module.options
95
def _tool_module(self):
96
# TODO: Interchange zipimport with normal initilization for better error reporting
97
oldpythonpath = sys.path
98
sys.path = self.toolpath + sys.path
102
file, path, desc = imp.find_module(self.name, self.toolpath)
104
return imp.load_module(self.name, file, path, desc)
108
except ImportError, e:
109
if str(e)!="No module named %s"%self.name:
110
raise SCons.Errors.EnvironmentError, e
116
for aPath in self.toolpath:
118
importer = zipimport.zipimporter(aPath)
119
return importer.load_module(self.name)
120
except ImportError, e:
123
sys.path = oldpythonpath
125
full_name = 'SCons.Tool.' + self.name
127
return sys.modules[full_name]
130
smpath = sys.modules['SCons.Tool'].__path__
132
file, path, desc = imp.find_module(self.name, smpath)
133
module = imp.load_module(full_name, file, path, desc)
134
setattr(SCons.Tool, self.name, module)
138
except ImportError, e:
139
if e!="No module named %s"%self.name:
140
raise SCons.Errors.EnvironmentError, e
143
importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] )
144
module = importer.load_module(full_name)
145
setattr(SCons.Tool, self.name, module)
147
except ImportError, e:
148
m = "No tool named '%s': %s" % (self.name, e)
149
raise SCons.Errors.EnvironmentError, m
150
except ImportError, e:
151
m = "No tool named '%s': %s" % (self.name, e)
152
raise SCons.Errors.EnvironmentError, m
154
def __call__(self, env, *args, **kw):
155
if self.init_kw is not None:
156
# Merge call kws into init kws;
157
# but don't bash self.init_kw.
160
kw = self.init_kw.copy()
164
env.Append(TOOLS = [ self.name ])
165
if hasattr(self, 'options'):
166
from SCons.Options import Options
167
if not env.has_key('options'):
168
from SCons.Script import ARGUMENTS
169
env['options']=Options(args=ARGUMENTS)
175
apply(self.generate, ( env, ) + args, kw)
180
##########################################################################
181
# Create common executable program / library / object builders
183
def createProgBuilder(env):
184
"""This is a utility function that creates the Program
185
Builder in an Environment if it is not there already.
187
If it is already there, we return the existing one.
191
program = env['BUILDERS']['Program']
193
import SCons.Defaults
194
program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction,
195
emitter = '$PROGEMITTER',
196
prefix = '$PROGPREFIX',
197
suffix = '$PROGSUFFIX',
198
src_suffix = '$OBJSUFFIX',
199
src_builder = 'Object',
200
target_scanner = ProgramScanner)
201
env['BUILDERS']['Program'] = program
205
def createStaticLibBuilder(env):
206
"""This is a utility function that creates the StaticLibrary
207
Builder in an Environment if it is not there already.
209
If it is already there, we return the existing one.
213
static_lib = env['BUILDERS']['StaticLibrary']
215
action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
216
if env.Detect('ranlib'):
217
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
218
action_list.append(ranlib_action)
220
static_lib = SCons.Builder.Builder(action = action_list,
221
emitter = '$LIBEMITTER',
222
prefix = '$LIBPREFIX',
223
suffix = '$LIBSUFFIX',
224
src_suffix = '$OBJSUFFIX',
225
src_builder = 'StaticObject')
226
env['BUILDERS']['StaticLibrary'] = static_lib
227
env['BUILDERS']['Library'] = static_lib
231
def createSharedLibBuilder(env):
232
"""This is a utility function that creates the SharedLibrary
233
Builder in an Environment if it is not there already.
235
If it is already there, we return the existing one.
239
shared_lib = env['BUILDERS']['SharedLibrary']
241
import SCons.Defaults
242
action_list = [ SCons.Defaults.SharedCheck,
243
SCons.Defaults.ShLinkAction ]
244
shared_lib = SCons.Builder.Builder(action = action_list,
245
emitter = "$SHLIBEMITTER",
246
prefix = '$SHLIBPREFIX',
247
suffix = '$SHLIBSUFFIX',
248
target_scanner = ProgramScanner,
249
src_suffix = '$SHOBJSUFFIX',
250
src_builder = 'SharedObject')
251
env['BUILDERS']['SharedLibrary'] = shared_lib
255
def createLoadableModuleBuilder(env):
256
"""This is a utility function that creates the LoadableModule
257
Builder in an Environment if it is not there already.
259
If it is already there, we return the existing one.
263
ld_module = env['BUILDERS']['LoadableModule']
265
import SCons.Defaults
266
action_list = [ SCons.Defaults.SharedCheck,
267
SCons.Defaults.LdModuleLinkAction ]
268
ld_module = SCons.Builder.Builder(action = action_list,
269
emitter = "$SHLIBEMITTER",
270
prefix = '$LDMODULEPREFIX',
271
suffix = '$LDMODULESUFFIX',
272
target_scanner = ProgramScanner,
273
src_suffix = '$SHOBJSUFFIX',
274
src_builder = 'SharedObject')
275
env['BUILDERS']['LoadableModule'] = ld_module
279
def createObjBuilders(env):
280
"""This is a utility function that creates the StaticObject
281
and SharedObject Builders in an Environment if they
282
are not there already.
284
If they are there already, we return the existing ones.
286
This is a separate function because soooo many Tools
287
use this functionality.
289
The return is a 2-tuple of (StaticObject, SharedObject)
294
static_obj = env['BUILDERS']['StaticObject']
296
static_obj = SCons.Builder.Builder(action = {},
298
prefix = '$OBJPREFIX',
299
suffix = '$OBJSUFFIX',
300
src_builder = ['CFile', 'CXXFile'],
301
source_scanner = SourceFileScanner,
303
env['BUILDERS']['StaticObject'] = static_obj
304
env['BUILDERS']['Object'] = static_obj
307
shared_obj = env['BUILDERS']['SharedObject']
309
shared_obj = SCons.Builder.Builder(action = {},
311
prefix = '$SHOBJPREFIX',
312
suffix = '$SHOBJSUFFIX',
313
src_builder = ['CFile', 'CXXFile'],
314
source_scanner = SourceFileScanner,
316
env['BUILDERS']['SharedObject'] = shared_obj
318
return (static_obj, shared_obj)
320
def createCFileBuilders(env):
321
"""This is a utility function that creates the CFile/CXXFile
322
Builders in an Environment if they
323
are not there already.
325
If they are there already, we return the existing ones.
327
This is a separate function because soooo many Tools
328
use this functionality.
330
The return is a 2-tuple of (CFile, CXXFile)
334
c_file = env['BUILDERS']['CFile']
336
c_file = SCons.Builder.Builder(action = {},
338
suffix = {None:'$CFILESUFFIX'})
339
env['BUILDERS']['CFile'] = c_file
341
env.SetDefault(CFILESUFFIX = '.c')
344
cxx_file = env['BUILDERS']['CXXFile']
346
cxx_file = SCons.Builder.Builder(action = {},
348
suffix = {None:'$CXXFILESUFFIX'})
349
env['BUILDERS']['CXXFile'] = cxx_file
350
env.SetDefault(CXXFILESUFFIX = '.cc')
352
return (c_file, cxx_file)
354
##########################################################################
355
# Create common Java builders
357
def CreateJarBuilder(env):
359
java_jar = env['BUILDERS']['Jar']
361
fs = SCons.Node.FS.get_default_fs()
362
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
363
java_jar = SCons.Builder.Builder(action = jar_com,
364
suffix = '$JARSUFFIX',
365
src_suffix = '$JAVACLASSSUFIX',
366
src_builder = 'JavaClassFile',
367
source_factory = fs.Entry)
368
env['BUILDERS']['Jar'] = java_jar
371
def CreateJavaHBuilder(env):
373
java_javah = env['BUILDERS']['JavaH']
375
fs = SCons.Node.FS.get_default_fs()
376
java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR')
377
java_javah = SCons.Builder.Builder(action = java_javah_com,
378
src_suffix = '$JAVACLASSSUFFIX',
379
target_factory = fs.Entry,
380
source_factory = fs.File,
381
src_builder = 'JavaClassFile')
382
env['BUILDERS']['JavaH'] = java_javah
385
def CreateJavaClassFileBuilder(env):
387
java_class_file = env['BUILDERS']['JavaClassFile']
389
fs = SCons.Node.FS.get_default_fs()
390
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
391
java_class_file = SCons.Builder.Builder(action = javac_com,
393
#suffix = '$JAVACLASSSUFFIX',
394
src_suffix = '$JAVASUFFIX',
395
src_builder = ['JavaFile'],
396
target_factory = fs.Entry,
397
source_factory = fs.File)
398
env['BUILDERS']['JavaClassFile'] = java_class_file
399
return java_class_file
401
def CreateJavaClassDirBuilder(env):
403
java_class_dir = env['BUILDERS']['JavaClassDir']
405
fs = SCons.Node.FS.get_default_fs()
406
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
407
java_class_dir = SCons.Builder.Builder(action = javac_com,
409
target_factory = fs.Dir,
410
source_factory = fs.Dir)
411
env['BUILDERS']['JavaClassDir'] = java_class_dir
412
return java_class_dir
414
def CreateJavaFileBuilder(env):
416
java_file = env['BUILDERS']['JavaFile']
418
java_file = SCons.Builder.Builder(action = {},
420
suffix = {None:'$JAVASUFFIX'})
421
env['BUILDERS']['JavaFile'] = java_file
422
env['JAVASUFFIX'] = '.java'
425
class ToolInitializer:
427
A class for delayed initialization of Tools modules.
429
This is intended to be added to a construction environment in
430
place of the method(s) normally called for a Builder (env.Object,
431
env.StaticObject, etc.). When called, it searches the specified
432
list of tools, applies the first one that exists to the construction
433
environment, and calls whatever builder was (presumably) added the
434
construction environment in our place.
436
def __init__(self, name, tools):
438
Note: we store the tool name as __name__ so it can be used by
439
the class that attaches this to a construction environment.
442
if not SCons.Util.is_List(tools):
445
def __call__(self, env, *args, **kw):
447
tool = SCons.Tool.Tool(t)
452
builder = getattr(env, self.__name__)
454
# There was no Builder added, which means no valid Tool
455
# for this name was found (or possibly there's a mismatch
456
# between the name we were called by and the Builder name
457
# added by the Tool module).
459
# (Eventually this is where we'll put a more informative
460
# error message about the inability to find that tool
461
# as cut over more Builders+Tools to using this.
464
# Let the construction environment remove the added method
465
# so we no longer copy and re-bind this method when the
466
# construction environment gets cloned.
467
env.RemoveMethod(self)
468
return apply(builder, args, kw)
470
def Initializers(env):
471
env.AddMethod(ToolInitializer('Install', 'install'))
472
env.AddMethod(ToolInitializer('InstallAs', 'install'))
474
def FindTool(tools, env):
481
def FindAllTools(tools, env):
482
def ToolExists(tool, env=env):
483
return Tool(tool).exists(env)
484
return filter (ToolExists, tools)
486
def tool_list(platform, env):
488
# XXX this logic about what tool to prefer on which platform
489
# should be moved into either the platform files or
490
# the tool files themselves.
491
# The search orders here are described in the man page. If you
492
# change these search orders, update the man page as well.
493
if str(platform) == 'win32':
494
"prefer Microsoft tools on Windows"
495
linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ]
496
c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ]
497
cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ]
498
assemblers = ['masm', 'nasm', 'gas', '386asm' ]
499
fortran_compilers = ['g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
500
ars = ['mslib', 'ar', 'tlib']
501
elif str(platform) == 'os2':
502
"prefer IBM tools on OS/2"
503
linkers = ['ilink', 'gnulink', 'mslink']
504
c_compilers = ['icc', 'gcc', 'msvc', 'cc']
505
cxx_compilers = ['icc', 'g++', 'msvc', 'c++']
506
assemblers = ['nasm', 'masm', 'gas']
507
fortran_compilers = ['ifl', 'g77']
508
ars = ['ar', 'mslib']
509
elif str(platform) == 'irix':
510
"prefer MIPSPro on IRIX"
511
linkers = ['sgilink', 'gnulink']
512
c_compilers = ['sgicc', 'gcc', 'cc']
513
cxx_compilers = ['sgic++', 'g++', 'c++']
514
assemblers = ['as', 'gas']
515
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
517
elif str(platform) == 'sunos':
518
"prefer Forte tools on SunOS"
519
linkers = ['sunlink', 'gnulink']
520
c_compilers = ['suncc', 'gcc', 'cc']
521
cxx_compilers = ['sunc++', 'g++', 'c++']
522
assemblers = ['as', 'gas']
523
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
525
elif str(platform) == 'hpux':
526
"prefer aCC tools on HP-UX"
527
linkers = ['hplink', 'gnulink']
528
c_compilers = ['hpcc', 'gcc', 'cc']
529
cxx_compilers = ['hpc++', 'g++', 'c++']
530
assemblers = ['as', 'gas']
531
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
533
elif str(platform) == 'aix':
534
"prefer AIX Visual Age tools on AIX"
535
linkers = ['aixlink', 'gnulink']
536
c_compilers = ['aixcc', 'gcc', 'cc']
537
cxx_compilers = ['aixc++', 'g++', 'c++']
538
assemblers = ['as', 'gas']
539
fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran']
541
elif str(platform) == 'darwin':
542
"prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
543
linkers = ['applelink', 'gnulink']
544
c_compilers = ['gcc', 'cc']
545
cxx_compilers = ['g++', 'c++']
547
fortran_compilers = ['f95', 'f90', 'g77']
550
"prefer GNU tools on all other platforms"
551
linkers = ['gnulink', 'mslink', 'ilink']
552
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
553
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++']
554
assemblers = ['gas', 'nasm', 'masm']
555
fortran_compilers = ['f95', 'f90', 'g77', 'ifort', 'ifl', 'fortran']
556
ars = ['ar', 'mslib']
558
c_compiler = FindTool(c_compilers, env) or c_compilers[0]
560
# XXX this logic about what tool provides what should somehow be
561
# moved into the tool files themselves.
562
if c_compiler and c_compiler == 'mingw':
563
# MinGW contains a linker, C compiler, C++ compiler,
564
# Fortran compiler, archiver and assembler:
568
fortran_compiler = None
571
# Don't use g++ if the C compiler has built-in C++ support:
572
if c_compiler in ('msvc', 'intelc', 'icc'):
575
cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0]
576
linker = FindTool(linkers, env) or linkers[0]
577
assembler = FindTool(assemblers, env) or assemblers[0]
578
fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
579
ar = FindTool(ars, env) or ars[0]
581
other_tools = FindAllTools(['BitKeeper', 'CVS',
584
'dvipdf', 'dvips', 'gs',
585
'jar', 'javac', 'javah',
587
'm4', 'midl', 'msvs',
588
'pdflatex', 'pdftex', 'Perforce',
589
'RCS', 'rmic', 'rpcgen',
594
'yacc', 'zip', 'rpm', 'wix'],
597
tools = ([linker, c_compiler, cxx_compiler,
598
fortran_compiler, assembler, ar]
601
return filter(lambda x: x, tools)