1"""SCons.Tool
2
3SCons tool selection.
4
5This looks for modules that define a callable object that can modify
6a construction environment as appropriate for a given tool (or tool
7chain).
8
9Note that because this subsystem just *selects* a callable that can
10modify a construction environment, it's possible for people to define
11their own "tool specification" in an arbitrary callable function.  No
12one needs to use or tie in to this subsystem in order to roll their own
13tool definition.
14"""
15
16#
17# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 The SCons Foundation
18#
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:
26#
27# The above copyright notice and this permission notice shall be included
28# in all copies or substantial portions of the Software.
29#
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.
37
38__revision__ = "src/engine/SCons/Tool/__init__.py issue-2856:2676:d23b7a2f45e8 2012/08/05 15:38:28 garyo"
39
40import imp
41import sys
42
43import SCons.Builder
44import SCons.Errors
45import SCons.Node.FS
46import SCons.Scanner
47import SCons.Scanner.C
48import SCons.Scanner.D
49import SCons.Scanner.LaTeX
50import SCons.Scanner.Prog
51
52DefaultToolpath=[]
53
54CScanner = SCons.Scanner.C.CScanner()
55DScanner = SCons.Scanner.D.DScanner()
56LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
57PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner()
58ProgramScanner = SCons.Scanner.Prog.ProgramScanner()
59SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner')
60
61CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
62             ".h", ".H", ".hxx", ".hpp", ".hh",
63             ".F", ".fpp", ".FPP",
64             ".m", ".mm",
65             ".S", ".spp", ".SPP", ".sx"]
66
67DSuffixes = ['.d']
68
69IDLSuffixes = [".idl", ".IDL"]
70
71LaTeXSuffixes = [".tex", ".ltx", ".latex"]
72
73for suffix in CSuffixes:
74    SourceFileScanner.add_scanner(suffix, CScanner)
75
76for suffix in DSuffixes:
77    SourceFileScanner.add_scanner(suffix, DScanner)
78
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???
83for suffix in LaTeXSuffixes:
84    SourceFileScanner.add_scanner(suffix, LaTeXScanner)
85    SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner)
86
87class Tool(object):
88    def __init__(self, name, toolpath=[], **kw):
89        self.name = name
90        self.toolpath = toolpath + DefaultToolpath
91        # remember these so we can merge them into the call
92        self.init_kw = kw
93
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
99
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
104
105        try:
106            try:
107                file, path, desc = imp.find_module(self.name, self.toolpath)
108                try:
109                    return imp.load_module(self.name, file, path, desc)
110                finally:
111                    if file:
112                        file.close()
113            except ImportError, e:
114                if str(e)!="No module named %s"%self.name:
115                    raise SCons.Errors.EnvironmentError(e)
116                try:
117                    import zipimport
118                except ImportError:
119                    pass
120                else:
121                    for aPath in self.toolpath:
122                        try:
123                            importer = zipimport.zipimporter(aPath)
124                            return importer.load_module(self.name)
125                        except ImportError, e:
126                            pass
127        finally:
128            sys.path = oldpythonpath
129
130        full_name = 'SCons.Tool.' + self.name
131        try:
132            return sys.modules[full_name]
133        except KeyError:
134            try:
135                smpath = sys.modules['SCons.Tool'].__path__
136                try:
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)
140                    if file:
141                        file.close()
142                    return module
143                except ImportError, e:
144                    if str(e)!="No module named %s"%self.name:
145                        raise SCons.Errors.EnvironmentError(e)
146                    try:
147                        import zipimport
148                        importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] )
149                        module = importer.load_module(full_name)
150                        setattr(SCons.Tool, self.name, module)
151                        return 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)
158
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.
163            if kw is not None:
164                call_kw = kw
165                kw = self.init_kw.copy()
166                kw.update(call_kw)
167            else:
168                kw = self.init_kw
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)
175            opts=env['options']
176
177            self.options(opts)
178            opts.Update(env)
179
180        self.generate(env, *args, **kw)
181
182    def __str__(self):
183        return self.name
184
185##########################################################################
186#  Create common executable program / library / object builders
187
188def createProgBuilder(env):
189    """This is a utility function that creates the Program
190    Builder in an Environment if it is not there already.
191
192    If it is already there, we return the existing one.
193    """
194
195    try:
196        program = env['BUILDERS']['Program']
197    except KeyError:
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
207
208    return program
209
210def createStaticLibBuilder(env):
211    """This is a utility function that creates the StaticLibrary
212    Builder in an Environment if it is not there already.
213
214    If it is already there, we return the existing one.
215    """
216
217    try:
218        static_lib = env['BUILDERS']['StaticLibrary']
219    except KeyError:
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)
224
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
233
234    return static_lib
235
236def createSharedLibBuilder(env):
237    """This is a utility function that creates the SharedLibrary
238    Builder in an Environment if it is not there already.
239
240    If it is already there, we return the existing one.
241    """
242
243    try:
244        shared_lib = env['BUILDERS']['SharedLibrary']
245    except KeyError:
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
257
258    return shared_lib
259
260def createLoadableModuleBuilder(env):
261    """This is a utility function that creates the LoadableModule
262    Builder in an Environment if it is not there already.
263
264    If it is already there, we return the existing one.
265    """
266
267    try:
268        ld_module = env['BUILDERS']['LoadableModule']
269    except KeyError:
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
281
282    return ld_module
283
284def 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.
288
289    If they are there already, we return the existing ones.
290
291    This is a separate function because soooo many Tools
292    use this functionality.
293
294    The return is a 2-tuple of (StaticObject, SharedObject)
295    """
296
297
298    try:
299        static_obj = env['BUILDERS']['StaticObject']
300    except KeyError:
301        static_obj = SCons.Builder.Builder(action = {},
302                                           emitter = {},
303                                           prefix = '$OBJPREFIX',
304                                           suffix = '$OBJSUFFIX',
305                                           src_builder = ['CFile', 'CXXFile'],
306                                           source_scanner = SourceFileScanner,
307                                           single_source = 1)
308        env['BUILDERS']['StaticObject'] = static_obj
309        env['BUILDERS']['Object'] = static_obj
310
311    try:
312        shared_obj = env['BUILDERS']['SharedObject']
313    except KeyError:
314        shared_obj = SCons.Builder.Builder(action = {},
315                                           emitter = {},
316                                           prefix = '$SHOBJPREFIX',
317                                           suffix = '$SHOBJSUFFIX',
318                                           src_builder = ['CFile', 'CXXFile'],
319                                           source_scanner = SourceFileScanner,
320                                           single_source = 1)
321        env['BUILDERS']['SharedObject'] = shared_obj
322
323    return (static_obj, shared_obj)
324
325def 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.
329
330    If they are there already, we return the existing ones.
331
332    This is a separate function because soooo many Tools
333    use this functionality.
334
335    The return is a 2-tuple of (CFile, CXXFile)
336    """
337
338    try:
339        c_file = env['BUILDERS']['CFile']
340    except KeyError:
341        c_file = SCons.Builder.Builder(action = {},
342                                       emitter = {},
343                                       suffix = {None:'$CFILESUFFIX'})
344        env['BUILDERS']['CFile'] = c_file
345
346        env.SetDefault(CFILESUFFIX = '.c')
347
348    try:
349        cxx_file = env['BUILDERS']['CXXFile']
350    except KeyError:
351        cxx_file = SCons.Builder.Builder(action = {},
352                                         emitter = {},
353                                         suffix = {None:'$CXXFILESUFFIX'})
354        env['BUILDERS']['CXXFile'] = cxx_file
355        env.SetDefault(CXXFILESUFFIX = '.cc')
356
357    return (c_file, cxx_file)
358
359##########################################################################
360#  Create common Java builders
361
362def CreateJarBuilder(env):
363    try:
364        java_jar = env['BUILDERS']['Jar']
365    except KeyError:
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
374    return java_jar
375
376def CreateJavaHBuilder(env):
377    try:
378        java_javah = env['BUILDERS']['JavaH']
379    except KeyError:
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
388    return java_javah
389
390def CreateJavaClassFileBuilder(env):
391    try:
392        java_class_file = env['BUILDERS']['JavaClassFile']
393    except KeyError:
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,
397                                                emitter = {},
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
405
406def CreateJavaClassDirBuilder(env):
407    try:
408        java_class_dir = env['BUILDERS']['JavaClassDir']
409    except KeyError:
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,
413                                               emitter = {},
414                                               target_factory = fs.Dir,
415                                               source_factory = fs.Dir)
416        env['BUILDERS']['JavaClassDir'] = java_class_dir
417    return java_class_dir
418
419def CreateJavaFileBuilder(env):
420    try:
421        java_file = env['BUILDERS']['JavaFile']
422    except KeyError:
423        java_file = SCons.Builder.Builder(action = {},
424                                          emitter = {},
425                                          suffix = {None:'$JAVASUFFIX'})
426        env['BUILDERS']['JavaFile'] = java_file
427        env['JAVASUFFIX'] = '.java'
428    return java_file
429
430class ToolInitializerMethod(object):
431    """
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.
439    """
440    def __init__(self, name, initializer):
441        """
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.
444        """
445        self.__name__ = name
446        self.initializer = initializer
447
448    def get_builder(self, env):
449        """
450	Returns the appropriate real Builder for this method name
451	after having the associated ToolInitializer object apply
452	the appropriate Tool module.
453        """
454        builder = getattr(env, self.__name__)
455
456        self.initializer.apply_tools(env)
457
458        builder = getattr(env, self.__name__)
459        if builder is self:
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).
464            return None
465
466        self.initializer.remove_methods(env)
467
468        return builder
469
470    def __call__(self, env, *args, **kw):
471        """
472        """
473        builder = self.get_builder(env)
474        if builder is None:
475            return [], []
476        return builder(*args, **kw)
477
478class ToolInitializer(object):
479    """
480    A class for delayed initialization of Tools modules.
481
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.
488    """
489    def __init__(self, env, tools, names):
490        if not SCons.Util.is_List(tools):
491            tools = [tools]
492        if not SCons.Util.is_List(names):
493            names = [names]
494        self.env = env
495        self.tools = tools
496        self.names = names
497        self.methods = {}
498        for name in names:
499            method = ToolInitializerMethod(name, self)
500            self.methods[name] = method
501            env.AddMethod(method)
502
503    def remove_methods(self, env):
504        """
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.
508        """
509        for method in self.methods.values():
510            env.RemoveMethod(method)
511
512    def apply_tools(self, env):
513        """
514	Searches the list of associated Tool modules for one that
515	exists, and applies that to the construction environment.
516        """
517        for t in self.tools:
518            tool = SCons.Tool.Tool(t)
519            if tool.exists(env):
520                env.Tool(tool)
521                return
522
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.
528
529def 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)
537
538def FindTool(tools, env):
539    for tool in tools:
540        t = Tool(tool)
541        if t.exists(env):
542            return tool
543    return None
544
545def FindAllTools(tools, env):
546    def ToolExists(tool, env=env):
547        return Tool(tool).exists(env)
548    return list(filter (ToolExists, tools))
549
550def tool_list(platform, env):
551
552    other_plat_tools=[]
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']
582        ars = ['sgiar']
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']
591        ars = ['sunar']
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']
599        ars = ['ar']
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']
607        ars = ['ar']
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++']
613        assemblers = ['as']
614        fortran_compilers = ['gfortran', 'f95', 'f90', 'g77']
615        ars = ['ar']
616    else:
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']
624
625    c_compiler = FindTool(c_compilers, env) or c_compilers[0]
626
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:
632        cxx_compiler = None
633        linker = None
634        assembler = None
635        fortran_compiler = None
636        ar = None
637    else:
638        # Don't use g++ if the C compiler has built-in C++ support:
639        if c_compiler in ('msvc', 'intelc', 'icc'):
640            cxx_compiler = None
641        else:
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]
647
648    other_tools = FindAllTools(other_plat_tools + [
649                               'dmd',
650                               #TODO: merge 'install' into 'filesystem' and
651                               # make 'filesystem' the default
652                               'filesystem',
653                               'm4',
654                               'wix', #'midl', 'msvs',
655                               # Parser generators
656                               'lex', 'yacc',
657                               # Foreign function interface
658                               'rpcgen', 'swig',
659                               # Java
660                               'jar', 'javac', 'javah', 'rmic',
661                               # TeX
662                               'dvipdf', 'dvips', 'gs',
663                               'tex', 'latex', 'pdflatex', 'pdftex',
664                               # Archivers
665                               'tar', 'zip', 'rpm',
666                               # SourceCode factories
667                               'BitKeeper', 'CVS', 'Perforce',
668                               'RCS', 'SCCS', # 'Subversion',
669                               ], env)
670
671    tools = ([linker, c_compiler, cxx_compiler,
672              fortran_compiler, assembler, ar]
673             + other_tools)
674
675    return [x for x in tools if x]
676
677# Local Variables:
678# tab-width:4
679# indent-tabs-mode:nil
680# End:
681# vim: set expandtab tabstop=4 shiftwidth=4:
682