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, 2008, 2009, 2010 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.
38
__revision__ = "src/engine/SCons/Tool/__init__.py 5134 2010/08/16 23:02:40 bdeegan"
47
import SCons.Scanner.C
48
import SCons.Scanner.D
49
import SCons.Scanner.LaTeX
50
import SCons.Scanner.Prog
54
CScanner = SCons.Scanner.C.CScanner()
55
DScanner = SCons.Scanner.D.DScanner()
56
LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
57
PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner()
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
# FIXME: what should be done here? Two scanners scan the same extensions,
80
# but look for different files, e.g., "picture.eps" vs. "picture.pdf".
81
# The builders for DVI and PDF explicitly reference their scanners
82
# I think that means this is not needed???
83
for suffix in LaTeXSuffixes:
84
SourceFileScanner.add_scanner(suffix, LaTeXScanner)
85
SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner)
88
def __init__(self, name, toolpath=[], **kw):
90
self.toolpath = toolpath + DefaultToolpath
91
# remember these so we can merge them into the call
94
module = self._tool_module()
95
self.generate = module.generate
96
self.exists = module.exists
97
if hasattr(module, 'options'):
98
self.options = module.options
100
def _tool_module(self):
101
# TODO: Interchange zipimport with normal initilization for better error reporting
102
oldpythonpath = sys.path
103
sys.path = self.toolpath + sys.path
107
file, path, desc = imp.find_module(self.name, self.toolpath)
109
return imp.load_module(self.name, file, path, desc)
113
except ImportError, e:
114
if str(e)!="No module named %s"%self.name:
115
raise SCons.Errors.EnvironmentError(e)
121
for aPath in self.toolpath:
123
importer = zipimport.zipimporter(aPath)
124
return importer.load_module(self.name)
125
except ImportError, e:
128
sys.path = oldpythonpath
130
full_name = 'SCons.Tool.' + self.name
132
return sys.modules[full_name]
135
smpath = sys.modules['SCons.Tool'].__path__
137
file, path, desc = imp.find_module(self.name, smpath)
138
module = imp.load_module(full_name, file, path, desc)
139
setattr(SCons.Tool, self.name, module)
143
except ImportError, e:
144
if str(e)!="No module named %s"%self.name:
145
raise SCons.Errors.EnvironmentError(e)
148
importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] )
149
module = importer.load_module(full_name)
150
setattr(SCons.Tool, self.name, module)
152
except ImportError, e:
153
m = "No tool named '%s': %s" % (self.name, e)
154
raise SCons.Errors.EnvironmentError(m)
155
except ImportError, e:
156
m = "No tool named '%s': %s" % (self.name, e)
157
raise SCons.Errors.EnvironmentError(m)
159
def __call__(self, env, *args, **kw):
160
if self.init_kw is not None:
161
# Merge call kws into init kws;
162
# but don't bash self.init_kw.
165
kw = self.init_kw.copy()
169
env.Append(TOOLS = [ self.name ])
170
if hasattr(self, 'options'):
171
import SCons.Variables
172
if 'options' not in env:
173
from SCons.Script import ARGUMENTS
174
env['options']=SCons.Variables.Variables(args=ARGUMENTS)
180
self.generate(env, *args, **kw)
185
##########################################################################
186
# Create common executable program / library / object builders
188
def createProgBuilder(env):
189
"""This is a utility function that creates the Program
190
Builder in an Environment if it is not there already.
192
If it is already there, we return the existing one.
196
program = env['BUILDERS']['Program']
198
import SCons.Defaults
199
program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction,
200
emitter = '$PROGEMITTER',
201
prefix = '$PROGPREFIX',
202
suffix = '$PROGSUFFIX',
203
src_suffix = '$OBJSUFFIX',
204
src_builder = 'Object',
205
target_scanner = ProgramScanner)
206
env['BUILDERS']['Program'] = program
210
def createStaticLibBuilder(env):
211
"""This is a utility function that creates the StaticLibrary
212
Builder in an Environment if it is not there already.
214
If it is already there, we return the existing one.
218
static_lib = env['BUILDERS']['StaticLibrary']
220
action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
221
if env.Detect('ranlib'):
222
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
223
action_list.append(ranlib_action)
225
static_lib = SCons.Builder.Builder(action = action_list,
226
emitter = '$LIBEMITTER',
227
prefix = '$LIBPREFIX',
228
suffix = '$LIBSUFFIX',
229
src_suffix = '$OBJSUFFIX',
230
src_builder = 'StaticObject')
231
env['BUILDERS']['StaticLibrary'] = static_lib
232
env['BUILDERS']['Library'] = static_lib
236
def createSharedLibBuilder(env):
237
"""This is a utility function that creates the SharedLibrary
238
Builder in an Environment if it is not there already.
240
If it is already there, we return the existing one.
244
shared_lib = env['BUILDERS']['SharedLibrary']
246
import SCons.Defaults
247
action_list = [ SCons.Defaults.SharedCheck,
248
SCons.Defaults.ShLinkAction ]
249
shared_lib = SCons.Builder.Builder(action = action_list,
250
emitter = "$SHLIBEMITTER",
251
prefix = '$SHLIBPREFIX',
252
suffix = '$SHLIBSUFFIX',
253
target_scanner = ProgramScanner,
254
src_suffix = '$SHOBJSUFFIX',
255
src_builder = 'SharedObject')
256
env['BUILDERS']['SharedLibrary'] = shared_lib
260
def createLoadableModuleBuilder(env):
261
"""This is a utility function that creates the LoadableModule
262
Builder in an Environment if it is not there already.
264
If it is already there, we return the existing one.
268
ld_module = env['BUILDERS']['LoadableModule']
270
import SCons.Defaults
271
action_list = [ SCons.Defaults.SharedCheck,
272
SCons.Defaults.LdModuleLinkAction ]
273
ld_module = SCons.Builder.Builder(action = action_list,
274
emitter = "$LDMODULEEMITTER",
275
prefix = '$LDMODULEPREFIX',
276
suffix = '$LDMODULESUFFIX',
277
target_scanner = ProgramScanner,
278
src_suffix = '$SHOBJSUFFIX',
279
src_builder = 'SharedObject')
280
env['BUILDERS']['LoadableModule'] = ld_module
284
def createObjBuilders(env):
285
"""This is a utility function that creates the StaticObject
286
and SharedObject Builders in an Environment if they
287
are not there already.
289
If they are there already, we return the existing ones.
291
This is a separate function because soooo many Tools
292
use this functionality.
294
The return is a 2-tuple of (StaticObject, SharedObject)
299
static_obj = env['BUILDERS']['StaticObject']
301
static_obj = SCons.Builder.Builder(action = {},
303
prefix = '$OBJPREFIX',
304
suffix = '$OBJSUFFIX',
305
src_builder = ['CFile', 'CXXFile'],
306
source_scanner = SourceFileScanner,
308
env['BUILDERS']['StaticObject'] = static_obj
309
env['BUILDERS']['Object'] = static_obj
312
shared_obj = env['BUILDERS']['SharedObject']
314
shared_obj = SCons.Builder.Builder(action = {},
316
prefix = '$SHOBJPREFIX',
317
suffix = '$SHOBJSUFFIX',
318
src_builder = ['CFile', 'CXXFile'],
319
source_scanner = SourceFileScanner,
321
env['BUILDERS']['SharedObject'] = shared_obj
323
return (static_obj, shared_obj)
325
def createCFileBuilders(env):
326
"""This is a utility function that creates the CFile/CXXFile
327
Builders in an Environment if they
328
are not there already.
330
If they are there already, we return the existing ones.
332
This is a separate function because soooo many Tools
333
use this functionality.
335
The return is a 2-tuple of (CFile, CXXFile)
339
c_file = env['BUILDERS']['CFile']
341
c_file = SCons.Builder.Builder(action = {},
343
suffix = {None:'$CFILESUFFIX'})
344
env['BUILDERS']['CFile'] = c_file
346
env.SetDefault(CFILESUFFIX = '.c')
349
cxx_file = env['BUILDERS']['CXXFile']
351
cxx_file = SCons.Builder.Builder(action = {},
353
suffix = {None:'$CXXFILESUFFIX'})
354
env['BUILDERS']['CXXFile'] = cxx_file
355
env.SetDefault(CXXFILESUFFIX = '.cc')
357
return (c_file, cxx_file)
359
##########################################################################
360
# Create common Java builders
362
def CreateJarBuilder(env):
364
java_jar = env['BUILDERS']['Jar']
366
fs = SCons.Node.FS.get_default_fs()
367
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
368
java_jar = SCons.Builder.Builder(action = jar_com,
369
suffix = '$JARSUFFIX',
370
src_suffix = '$JAVACLASSSUFIX',
371
src_builder = 'JavaClassFile',
372
source_factory = fs.Entry)
373
env['BUILDERS']['Jar'] = java_jar
376
def CreateJavaHBuilder(env):
378
java_javah = env['BUILDERS']['JavaH']
380
fs = SCons.Node.FS.get_default_fs()
381
java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR')
382
java_javah = SCons.Builder.Builder(action = java_javah_com,
383
src_suffix = '$JAVACLASSSUFFIX',
384
target_factory = fs.Entry,
385
source_factory = fs.File,
386
src_builder = 'JavaClassFile')
387
env['BUILDERS']['JavaH'] = java_javah
390
def CreateJavaClassFileBuilder(env):
392
java_class_file = env['BUILDERS']['JavaClassFile']
394
fs = SCons.Node.FS.get_default_fs()
395
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
396
java_class_file = SCons.Builder.Builder(action = javac_com,
398
#suffix = '$JAVACLASSSUFFIX',
399
src_suffix = '$JAVASUFFIX',
400
src_builder = ['JavaFile'],
401
target_factory = fs.Entry,
402
source_factory = fs.File)
403
env['BUILDERS']['JavaClassFile'] = java_class_file
404
return java_class_file
406
def CreateJavaClassDirBuilder(env):
408
java_class_dir = env['BUILDERS']['JavaClassDir']
410
fs = SCons.Node.FS.get_default_fs()
411
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
412
java_class_dir = SCons.Builder.Builder(action = javac_com,
414
target_factory = fs.Dir,
415
source_factory = fs.Dir)
416
env['BUILDERS']['JavaClassDir'] = java_class_dir
417
return java_class_dir
419
def CreateJavaFileBuilder(env):
421
java_file = env['BUILDERS']['JavaFile']
423
java_file = SCons.Builder.Builder(action = {},
425
suffix = {None:'$JAVASUFFIX'})
426
env['BUILDERS']['JavaFile'] = java_file
427
env['JAVASUFFIX'] = '.java'
430
class ToolInitializerMethod(object):
432
This is added to a construction environment in place of a
433
method(s) normally called for a Builder (env.Object, env.StaticObject,
434
etc.). When called, it has its associated ToolInitializer
435
object search the specified list of tools and apply the first
436
one that exists to the construction environment. It then calls
437
whatever builder was (presumably) added to the construction
438
environment in place of this particular instance.
440
def __init__(self, name, initializer):
442
Note: we store the tool name as __name__ so it can be used by
443
the class that attaches this to a construction environment.
446
self.initializer = initializer
448
def get_builder(self, env):
450
Returns the appropriate real Builder for this method name
451
after having the associated ToolInitializer object apply
452
the appropriate Tool module.
454
builder = getattr(env, self.__name__)
456
self.initializer.apply_tools(env)
458
builder = getattr(env, self.__name__)
460
# There was no Builder added, which means no valid Tool
461
# for this name was found (or possibly there's a mismatch
462
# between the name we were called by and the Builder name
463
# added by the Tool module).
466
self.initializer.remove_methods(env)
470
def __call__(self, env, *args, **kw):
473
builder = self.get_builder(env)
476
return builder(*args, **kw)
478
class ToolInitializer(object):
480
A class for delayed initialization of Tools modules.
482
Instances of this class associate a list of Tool modules with
483
a list of Builder method names that will be added by those Tool
484
modules. As part of instantiating this object for a particular
485
construction environment, we also add the appropriate
486
ToolInitializerMethod objects for the various Builder methods
487
that we want to use to delay Tool searches until necessary.
489
def __init__(self, env, tools, names):
490
if not SCons.Util.is_List(tools):
492
if not SCons.Util.is_List(names):
499
method = ToolInitializerMethod(name, self)
500
self.methods[name] = method
501
env.AddMethod(method)
503
def remove_methods(self, env):
505
Removes the methods that were added by the tool initialization
506
so we no longer copy and re-bind them when the construction
507
environment gets cloned.
509
for method in self.methods.values():
510
env.RemoveMethod(method)
512
def apply_tools(self, env):
514
Searches the list of associated Tool modules for one that
515
exists, and applies that to the construction environment.
518
tool = SCons.Tool.Tool(t)
523
# If we fall through here, there was no tool module found.
524
# This is where we can put an informative error message
525
# about the inability to find the tool. We'll start doing
526
# this as we cut over more pre-defined Builder+Tools to use
527
# the ToolInitializer class.
529
def Initializers(env):
530
ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs'])
531
def Install(self, *args, **kw):
532
return self._InternalInstall(*args, **kw)
533
def InstallAs(self, *args, **kw):
534
return self._InternalInstallAs(*args, **kw)
535
env.AddMethod(Install)
536
env.AddMethod(InstallAs)
538
def FindTool(tools, env):
545
def FindAllTools(tools, env):
546
def ToolExists(tool, env=env):
547
return Tool(tool).exists(env)
548
return list(filter (ToolExists, tools))
550
def tool_list(platform, env):
553
# XXX this logic about what tool to prefer on which platform
554
# should be moved into either the platform files or
555
# the tool files themselves.
556
# The search orders here are described in the man page. If you
557
# change these search orders, update the man page as well.
558
if str(platform) == 'win32':
559
"prefer Microsoft tools on Windows"
560
linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ]
561
c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ]
562
cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ]
563
assemblers = ['masm', 'nasm', 'gas', '386asm' ]
564
fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
565
ars = ['mslib', 'ar', 'tlib']
566
other_plat_tools=['msvs','midl']
567
elif str(platform) == 'os2':
568
"prefer IBM tools on OS/2"
569
linkers = ['ilink', 'gnulink', ]#'mslink']
570
c_compilers = ['icc', 'gcc',]# 'msvc', 'cc']
571
cxx_compilers = ['icc', 'g++',]# 'msvc', 'c++']
572
assemblers = ['nasm',]# 'masm', 'gas']
573
fortran_compilers = ['ifl', 'g77']
574
ars = ['ar',]# 'mslib']
575
elif str(platform) == 'irix':
576
"prefer MIPSPro on IRIX"
577
linkers = ['sgilink', 'gnulink']
578
c_compilers = ['sgicc', 'gcc', 'cc']
579
cxx_compilers = ['sgic++', 'g++', 'c++']
580
assemblers = ['as', 'gas']
581
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
583
elif str(platform) == 'sunos':
584
"prefer Forte tools on SunOS"
585
linkers = ['sunlink', 'gnulink']
586
c_compilers = ['suncc', 'gcc', 'cc']
587
cxx_compilers = ['sunc++', 'g++', 'c++']
588
assemblers = ['as', 'gas']
589
fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77',
590
'gfortran', 'g77', 'fortran']
592
elif str(platform) == 'hpux':
593
"prefer aCC tools on HP-UX"
594
linkers = ['hplink', 'gnulink']
595
c_compilers = ['hpcc', 'gcc', 'cc']
596
cxx_compilers = ['hpc++', 'g++', 'c++']
597
assemblers = ['as', 'gas']
598
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
600
elif str(platform) == 'aix':
601
"prefer AIX Visual Age tools on AIX"
602
linkers = ['aixlink', 'gnulink']
603
c_compilers = ['aixcc', 'gcc', 'cc']
604
cxx_compilers = ['aixc++', 'g++', 'c++']
605
assemblers = ['as', 'gas']
606
fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran']
608
elif str(platform) == 'darwin':
609
"prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
610
linkers = ['applelink', 'gnulink']
611
c_compilers = ['gcc', 'cc']
612
cxx_compilers = ['g++', 'c++']
614
fortran_compilers = ['gfortran', 'f95', 'f90', 'g77']
617
"prefer GNU tools on all other platforms"
618
linkers = ['gnulink', 'mslink', 'ilink']
619
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
620
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++']
621
assemblers = ['gas', 'nasm', 'masm']
622
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
623
ars = ['ar', 'mslib']
625
c_compiler = FindTool(c_compilers, env) or c_compilers[0]
627
# XXX this logic about what tool provides what should somehow be
628
# moved into the tool files themselves.
629
if c_compiler and c_compiler == 'mingw':
630
# MinGW contains a linker, C compiler, C++ compiler,
631
# Fortran compiler, archiver and assembler:
635
fortran_compiler = None
638
# Don't use g++ if the C compiler has built-in C++ support:
639
if c_compiler in ('msvc', 'intelc', 'icc'):
642
cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0]
643
linker = FindTool(linkers, env) or linkers[0]
644
assembler = FindTool(assemblers, env) or assemblers[0]
645
fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
646
ar = FindTool(ars, env) or ars[0]
648
other_tools = FindAllTools(other_plat_tools + [
650
#TODO: merge 'install' into 'filesystem' and
651
# make 'filesystem' the default
654
'wix', #'midl', 'msvs',
657
# Foreign function interface
660
'jar', 'javac', 'javah', 'rmic',
662
'dvipdf', 'dvips', 'gs',
663
'tex', 'latex', 'pdflatex', 'pdftex',
666
# SourceCode factories
667
'BitKeeper', 'CVS', 'Perforce',
668
'RCS', 'SCCS', # 'Subversion',
671
tools = ([linker, c_compiler, cxx_compiler,
672
fortran_compiler, assembler, ar]
675
return [x for x in tools if x]
679
# indent-tabs-mode:nil
681
# vim: set expandtab tabstop=4 shiftwidth=4: