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 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
39__revision__ = "src/engine/SCons/Tool/__init__.py 4369 2009/09/19 15:58:29 scons"
40
41import imp
42import sys
43
44import SCons.Builder
45import SCons.Errors
46import SCons.Node.FS
47import SCons.Scanner
48import SCons.Scanner.C
49import SCons.Scanner.D
50import SCons.Scanner.LaTeX
51import SCons.Scanner.Prog
52
53DefaultToolpath=[]
54
55CScanner = SCons.Scanner.C.CScanner()
56DScanner = SCons.Scanner.D.DScanner()
57LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
58PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner()
59ProgramScanner = SCons.Scanner.Prog.ProgramScanner()
60SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner')
61
62CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
63             ".h", ".H", ".hxx", ".hpp", ".hh",
64             ".F", ".fpp", ".FPP",
65             ".m", ".mm",
66             ".S", ".spp", ".SPP"]
67
68DSuffixes = ['.d']
69
70IDLSuffixes = [".idl", ".IDL"]
71
72LaTeXSuffixes = [".tex", ".ltx", ".latex"]
73
74for suffix in CSuffixes:
75    SourceFileScanner.add_scanner(suffix, CScanner)
76
77for suffix in DSuffixes:
78    SourceFileScanner.add_scanner(suffix, DScanner)
79
80# FIXME: what should be done here? Two scanners scan the same extensions,
81# but look for different files, e.g., "picture.eps" vs. "picture.pdf".
82# The builders for DVI and PDF explicitly reference their scanners
83# I think that means this is not needed???
84for suffix in LaTeXSuffixes:
85    SourceFileScanner.add_scanner(suffix, LaTeXScanner)
86    SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner)
87
88class Tool:
89    def __init__(self, name, toolpath=[], **kw):
90        self.name = name
91        self.toolpath = toolpath + DefaultToolpath
92        # remember these so we can merge them into the call
93        self.init_kw = kw
94
95        module = self._tool_module()
96        self.generate = module.generate
97        self.exists = module.exists
98        if hasattr(module, 'options'):
99            self.options = module.options
100
101    def _tool_module(self):
102        # TODO: Interchange zipimport with normal initilization for better error reporting
103        oldpythonpath = sys.path
104        sys.path = self.toolpath + sys.path
105
106        try:
107            try:
108                file, path, desc = imp.find_module(self.name, self.toolpath)
109                try:
110                    return imp.load_module(self.name, file, path, desc)
111                finally:
112                    if file:
113                        file.close()
114            except ImportError as e:
115                if str(e)!="No module named %s"%self.name:
116                    raise SCons.Errors.EnvironmentError(e)
117                try:
118                    import zipimport
119                except ImportError:
120                    pass
121                else:
122                    for aPath in self.toolpath:
123                        try:
124                            importer = zipimport.zipimporter(aPath)
125                            return importer.load_module(self.name)
126                        except ImportError as e:
127                            pass
128        finally:
129            sys.path = oldpythonpath
130
131        full_name = 'SCons.Tool.' + self.name
132        try:
133            return sys.modules[full_name]
134        except KeyError:
135            try:
136                smpath = sys.modules['SCons.Tool'].__path__
137                try:
138                    file, path, desc = imp.find_module(self.name, smpath)
139                    module = imp.load_module(full_name, file, path, desc)
140                    setattr(SCons.Tool, self.name, module)
141                    if file:
142                        file.close()
143                    return module
144                except ImportError as e:
145                    if str(e)!="No module named %s"%self.name:
146                        raise SCons.Errors.EnvironmentError(e)
147                    try:
148                        import zipimport
149                        importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] )
150                        module = importer.load_module(full_name)
151                        setattr(SCons.Tool, self.name, module)
152                        return module
153                    except ImportError as e:
154                        m = "No tool named '%s': %s" % (self.name, e)
155                        raise SCons.Errors.EnvironmentError(m)
156            except ImportError as e:
157                m = "No tool named '%s': %s" % (self.name, e)
158                raise SCons.Errors.EnvironmentError(m)
159
160    def __call__(self, env, *args, **kw):
161        if self.init_kw is not None:
162            # Merge call kws into init kws;
163            # but don't bash self.init_kw.
164            if kw is not None:
165                call_kw = kw
166                kw = self.init_kw.copy()
167                kw.update(call_kw)
168            else:
169                kw = self.init_kw
170        env.Append(TOOLS = [ self.name ])
171        if hasattr(self, 'options'):
172            import SCons.Variables
173            if 'options' not in env:
174                from SCons.Script import ARGUMENTS
175                env['options']=SCons.Variables.Variables(args=ARGUMENTS)
176            opts=env['options']
177
178            self.options(opts)
179            opts.Update(env)
180
181        self.generate(*( env, ) + args, **kw)
182
183    def __str__(self):
184        return self.name
185
186##########################################################################
187#  Create common executable program / library / object builders
188
189def createProgBuilder(env):
190    """This is a utility function that creates the Program
191    Builder in an Environment if it is not there already.
192
193    If it is already there, we return the existing one.
194    """
195
196    try:
197        program = env['BUILDERS']['Program']
198    except KeyError:
199        import SCons.Defaults
200        program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction,
201                                        emitter = '$PROGEMITTER',
202                                        prefix = '$PROGPREFIX',
203                                        suffix = '$PROGSUFFIX',
204                                        src_suffix = '$OBJSUFFIX',
205                                        src_builder = 'Object',
206                                        target_scanner = ProgramScanner)
207        env['BUILDERS']['Program'] = program
208
209    return program
210
211def createStaticLibBuilder(env):
212    """This is a utility function that creates the StaticLibrary
213    Builder in an Environment if it is not there already.
214
215    If it is already there, we return the existing one.
216    """
217
218    try:
219        static_lib = env['BUILDERS']['StaticLibrary']
220    except KeyError:
221        action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
222        if env.Detect('ranlib'):
223            ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
224            action_list.append(ranlib_action)
225
226        static_lib = SCons.Builder.Builder(action = action_list,
227                                           emitter = '$LIBEMITTER',
228                                           prefix = '$LIBPREFIX',
229                                           suffix = '$LIBSUFFIX',
230                                           src_suffix = '$OBJSUFFIX',
231                                           src_builder = 'StaticObject')
232        env['BUILDERS']['StaticLibrary'] = static_lib
233        env['BUILDERS']['Library'] = static_lib
234
235    return static_lib
236
237def createSharedLibBuilder(env):
238    """This is a utility function that creates the SharedLibrary
239    Builder in an Environment if it is not there already.
240
241    If it is already there, we return the existing one.
242    """
243
244    try:
245        shared_lib = env['BUILDERS']['SharedLibrary']
246    except KeyError:
247        import SCons.Defaults
248        action_list = [ SCons.Defaults.SharedCheck,
249                        SCons.Defaults.ShLinkAction ]
250        shared_lib = SCons.Builder.Builder(action = action_list,
251                                           emitter = "$SHLIBEMITTER",
252                                           prefix = '$SHLIBPREFIX',
253                                           suffix = '$SHLIBSUFFIX',
254                                           target_scanner = ProgramScanner,
255                                           src_suffix = '$SHOBJSUFFIX',
256                                           src_builder = 'SharedObject')
257        env['BUILDERS']['SharedLibrary'] = shared_lib
258
259    return shared_lib
260
261def createLoadableModuleBuilder(env):
262    """This is a utility function that creates the LoadableModule
263    Builder in an Environment if it is not there already.
264
265    If it is already there, we return the existing one.
266    """
267
268    try:
269        ld_module = env['BUILDERS']['LoadableModule']
270    except KeyError:
271        import SCons.Defaults
272        action_list = [ SCons.Defaults.SharedCheck,
273                        SCons.Defaults.LdModuleLinkAction ]
274        ld_module = SCons.Builder.Builder(action = action_list,
275                                          emitter = "$LDMODULEEMITTER",
276                                          prefix = '$LDMODULEPREFIX',
277                                          suffix = '$LDMODULESUFFIX',
278                                          target_scanner = ProgramScanner,
279                                          src_suffix = '$SHOBJSUFFIX',
280                                          src_builder = 'SharedObject')
281        env['BUILDERS']['LoadableModule'] = ld_module
282
283    return ld_module
284
285def createObjBuilders(env):
286    """This is a utility function that creates the StaticObject
287    and SharedObject Builders in an Environment if they
288    are not there already.
289
290    If they are there already, we return the existing ones.
291
292    This is a separate function because soooo many Tools
293    use this functionality.
294
295    The return is a 2-tuple of (StaticObject, SharedObject)
296    """
297
298
299    try:
300        static_obj = env['BUILDERS']['StaticObject']
301    except KeyError:
302        static_obj = SCons.Builder.Builder(action = {},
303                                           emitter = {},
304                                           prefix = '$OBJPREFIX',
305                                           suffix = '$OBJSUFFIX',
306                                           src_builder = ['CFile', 'CXXFile'],
307                                           source_scanner = SourceFileScanner,
308                                           single_source = 1)
309        env['BUILDERS']['StaticObject'] = static_obj
310        env['BUILDERS']['Object'] = static_obj
311
312    try:
313        shared_obj = env['BUILDERS']['SharedObject']
314    except KeyError:
315        shared_obj = SCons.Builder.Builder(action = {},
316                                           emitter = {},
317                                           prefix = '$SHOBJPREFIX',
318                                           suffix = '$SHOBJSUFFIX',
319                                           src_builder = ['CFile', 'CXXFile'],
320                                           source_scanner = SourceFileScanner,
321                                           single_source = 1)
322        env['BUILDERS']['SharedObject'] = shared_obj
323
324    return (static_obj, shared_obj)
325
326def createCFileBuilders(env):
327    """This is a utility function that creates the CFile/CXXFile
328    Builders in an Environment if they
329    are not there already.
330
331    If they are there already, we return the existing ones.
332
333    This is a separate function because soooo many Tools
334    use this functionality.
335
336    The return is a 2-tuple of (CFile, CXXFile)
337    """
338
339    try:
340        c_file = env['BUILDERS']['CFile']
341    except KeyError:
342        c_file = SCons.Builder.Builder(action = {},
343                                       emitter = {},
344                                       suffix = {None:'$CFILESUFFIX'})
345        env['BUILDERS']['CFile'] = c_file
346
347        env.SetDefault(CFILESUFFIX = '.c')
348
349    try:
350        cxx_file = env['BUILDERS']['CXXFile']
351    except KeyError:
352        cxx_file = SCons.Builder.Builder(action = {},
353                                         emitter = {},
354                                         suffix = {None:'$CXXFILESUFFIX'})
355        env['BUILDERS']['CXXFile'] = cxx_file
356        env.SetDefault(CXXFILESUFFIX = '.cc')
357
358    return (c_file, cxx_file)
359
360##########################################################################
361#  Create common Java builders
362
363def CreateJarBuilder(env):
364    try:
365        java_jar = env['BUILDERS']['Jar']
366    except KeyError:
367        fs = SCons.Node.FS.get_default_fs()
368        jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
369        java_jar = SCons.Builder.Builder(action = jar_com,
370                                         suffix = '$JARSUFFIX',
371                                         src_suffix = '$JAVACLASSSUFIX',
372                                         src_builder = 'JavaClassFile',
373                                         source_factory = fs.Entry)
374        env['BUILDERS']['Jar'] = java_jar
375    return java_jar
376
377def CreateJavaHBuilder(env):
378    try:
379        java_javah = env['BUILDERS']['JavaH']
380    except KeyError:
381        fs = SCons.Node.FS.get_default_fs()
382        java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR')
383        java_javah = SCons.Builder.Builder(action = java_javah_com,
384                                           src_suffix = '$JAVACLASSSUFFIX',
385                                           target_factory = fs.Entry,
386                                           source_factory = fs.File,
387                                           src_builder = 'JavaClassFile')
388        env['BUILDERS']['JavaH'] = java_javah
389    return java_javah
390
391def CreateJavaClassFileBuilder(env):
392    try:
393        java_class_file = env['BUILDERS']['JavaClassFile']
394    except KeyError:
395        fs = SCons.Node.FS.get_default_fs()
396        javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
397        java_class_file = SCons.Builder.Builder(action = javac_com,
398                                                emitter = {},
399                                                #suffix = '$JAVACLASSSUFFIX',
400                                                src_suffix = '$JAVASUFFIX',
401                                                src_builder = ['JavaFile'],
402                                                target_factory = fs.Entry,
403                                                source_factory = fs.File)
404        env['BUILDERS']['JavaClassFile'] = java_class_file
405    return java_class_file
406
407def CreateJavaClassDirBuilder(env):
408    try:
409        java_class_dir = env['BUILDERS']['JavaClassDir']
410    except KeyError:
411        fs = SCons.Node.FS.get_default_fs()
412        javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
413        java_class_dir = SCons.Builder.Builder(action = javac_com,
414                                               emitter = {},
415                                               target_factory = fs.Dir,
416                                               source_factory = fs.Dir)
417        env['BUILDERS']['JavaClassDir'] = java_class_dir
418    return java_class_dir
419
420def CreateJavaFileBuilder(env):
421    try:
422        java_file = env['BUILDERS']['JavaFile']
423    except KeyError:
424        java_file = SCons.Builder.Builder(action = {},
425                                          emitter = {},
426                                          suffix = {None:'$JAVASUFFIX'})
427        env['BUILDERS']['JavaFile'] = java_file
428        env['JAVASUFFIX'] = '.java'
429    return java_file
430
431class ToolInitializerMethod:
432    """
433    This is added to a construction environment in place of a
434    method(s) normally called for a Builder (env.Object, env.StaticObject,
435    etc.).  When called, it has its associated ToolInitializer
436    object search the specified list of tools and apply the first
437    one that exists to the construction environment.  It then calls
438    whatever builder was (presumably) added to the construction
439    environment in place of this particular instance.
440    """
441    def __init__(self, name, initializer):
442        """
443        Note:  we store the tool name as __name__ so it can be used by
444        the class that attaches this to a construction environment.
445        """
446        self.__name__ = name
447        self.initializer = initializer
448
449    def get_builder(self, env):
450        """
451	Returns the appropriate real Builder for this method name
452	after having the associated ToolInitializer object apply
453	the appropriate Tool module.
454        """
455        builder = getattr(env, self.__name__)
456
457        self.initializer.apply_tools(env)
458
459        builder = getattr(env, self.__name__)
460        if builder is self:
461            # There was no Builder added, which means no valid Tool
462            # for this name was found (or possibly there's a mismatch
463            # between the name we were called by and the Builder name
464            # added by the Tool module).
465            return None
466
467        self.initializer.remove_methods(env)
468
469        return builder
470
471    def __call__(self, env, *args, **kw):
472        """
473        """
474        builder = self.get_builder(env)
475        if builder is None:
476            return [], []
477        return builder(*args, **kw)
478
479class ToolInitializer:
480    """
481    A class for delayed initialization of Tools modules.
482
483    Instances of this class associate a list of Tool modules with
484    a list of Builder method names that will be added by those Tool
485    modules.  As part of instantiating this object for a particular
486    construction environment, we also add the appropriate
487    ToolInitializerMethod objects for the various Builder methods
488    that we want to use to delay Tool searches until necessary.
489    """
490    def __init__(self, env, tools, names):
491        if not SCons.Util.is_List(tools):
492            tools = [tools]
493        if not SCons.Util.is_List(names):
494            names = [names]
495        self.env = env
496        self.tools = tools
497        self.names = names
498        self.methods = {}
499        for name in names:
500            method = ToolInitializerMethod(name, self)
501            self.methods[name] = method
502            env.AddMethod(method)
503
504    def remove_methods(self, env):
505        """
506        Removes the methods that were added by the tool initialization
507        so we no longer copy and re-bind them when the construction
508        environment gets cloned.
509        """
510        for method in self.methods.values():
511            env.RemoveMethod(method)
512
513    def apply_tools(self, env):
514        """
515	Searches the list of associated Tool modules for one that
516	exists, and applies that to the construction environment.
517        """
518        for t in self.tools:
519            tool = SCons.Tool.Tool(t)
520            if tool.exists(env):
521                env.Tool(tool)
522                return
523
524	# If we fall through here, there was no tool module found.
525	# This is where we can put an informative error message
526	# about the inability to find the tool.   We'll start doing
527	# this as we cut over more pre-defined Builder+Tools to use
528	# the ToolInitializer class.
529
530def Initializers(env):
531    ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs'])
532    def Install(self, *args, **kw):
533        return self._InternalInstall(*args, **kw)
534    def InstallAs(self, *args, **kw):
535        return self._InternalInstallAs(*args, **kw)
536    env.AddMethod(Install)
537    env.AddMethod(InstallAs)
538
539def FindTool(tools, env):
540    for tool in tools:
541        t = Tool(tool)
542        if t.exists(env):
543            return tool
544    return None
545
546def FindAllTools(tools, env):
547    def ToolExists(tool, env=env):
548        return Tool(tool).exists(env)
549    return filter (ToolExists, tools)
550
551def tool_list(platform, env):
552
553    other_plat_tools=[]
554    # XXX this logic about what tool to prefer on which platform
555    #     should be moved into either the platform files or
556    #     the tool files themselves.
557    # The search orders here are described in the man page.  If you
558    # change these search orders, update the man page as well.
559    if str(platform) == 'win32':
560        "prefer Microsoft tools on Windows"
561        linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ]
562        c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ]
563        cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ]
564        assemblers = ['masm', 'nasm', 'gas', '386asm' ]
565        fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
566        ars = ['mslib', 'ar', 'tlib']
567        other_plat_tools=['msvs','midl']
568    elif str(platform) == 'os2':
569        "prefer IBM tools on OS/2"
570        linkers = ['ilink', 'gnulink', ]#'mslink']
571        c_compilers = ['icc', 'gcc',]# 'msvc', 'cc']
572        cxx_compilers = ['icc', 'g++',]# 'msvc', 'c++']
573        assemblers = ['nasm',]# 'masm', 'gas']
574        fortran_compilers = ['ifl', 'g77']
575        ars = ['ar',]# 'mslib']
576    elif str(platform) == 'irix':
577        "prefer MIPSPro on IRIX"
578        linkers = ['sgilink', 'gnulink']
579        c_compilers = ['sgicc', 'gcc', 'cc']
580        cxx_compilers = ['sgic++', 'g++', 'c++']
581        assemblers = ['as', 'gas']
582        fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
583        ars = ['sgiar']
584    elif str(platform) == 'sunos':
585        "prefer Forte tools on SunOS"
586        linkers = ['sunlink', 'gnulink']
587        c_compilers = ['suncc', 'gcc', 'cc']
588        cxx_compilers = ['sunc++', 'g++', 'c++']
589        assemblers = ['as', 'gas']
590        fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77',
591                             'gfortran', 'g77', 'fortran']
592        ars = ['sunar']
593    elif str(platform) == 'hpux':
594        "prefer aCC tools on HP-UX"
595        linkers = ['hplink', 'gnulink']
596        c_compilers = ['hpcc', 'gcc', 'cc']
597        cxx_compilers = ['hpc++', 'g++', 'c++']
598        assemblers = ['as', 'gas']
599        fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran']
600        ars = ['ar']
601    elif str(platform) == 'aix':
602        "prefer AIX Visual Age tools on AIX"
603        linkers = ['aixlink', 'gnulink']
604        c_compilers = ['aixcc', 'gcc', 'cc']
605        cxx_compilers = ['aixc++', 'g++', 'c++']
606        assemblers = ['as', 'gas']
607        fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran']
608        ars = ['ar']
609    elif str(platform) == 'darwin':
610        "prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
611        linkers = ['applelink', 'gnulink']
612        c_compilers = ['gcc', 'cc']
613        cxx_compilers = ['g++', 'c++']
614        assemblers = ['as']
615        fortran_compilers = ['gfortran', 'f95', 'f90', 'g77']
616        ars = ['ar']
617    else:
618        "prefer GNU tools on all other platforms"
619        linkers = ['gnulink', 'mslink', 'ilink']
620        c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc']
621        cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++']
622        assemblers = ['gas', 'nasm', 'masm']
623        fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
624        ars = ['ar', 'mslib']
625
626    c_compiler = FindTool(c_compilers, env) or c_compilers[0]
627
628    # XXX this logic about what tool provides what should somehow be
629    #     moved into the tool files themselves.
630    if c_compiler and c_compiler == 'mingw':
631        # MinGW contains a linker, C compiler, C++ compiler,
632        # Fortran compiler, archiver and assembler:
633        cxx_compiler = None
634        linker = None
635        assembler = None
636        fortran_compiler = None
637        ar = None
638    else:
639        # Don't use g++ if the C compiler has built-in C++ support:
640        if c_compiler in ('msvc', 'intelc', 'icc'):
641            cxx_compiler = None
642        else:
643            cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0]
644        linker = FindTool(linkers, env) or linkers[0]
645        assembler = FindTool(assemblers, env) or assemblers[0]
646        fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
647        ar = FindTool(ars, env) or ars[0]
648
649    other_tools = FindAllTools(['BitKeeper', 'CVS',
650                                'dmd',
651                                'filesystem',
652                                'dvipdf', 'dvips', 'gs',
653                                'jar', 'javac', 'javah',
654                                'latex', 'lex',
655                                'm4', #'midl', 'msvs',
656                                'pdflatex', 'pdftex', 'Perforce',
657                                'RCS', 'rmic', 'rpcgen',
658                                'SCCS',
659                                # 'Subversion',
660                                'swig',
661                                'tar', 'tex',
662                                'yacc', 'zip', 'rpm', 'wix']+other_plat_tools,
663                               env)
664
665    tools = ([linker, c_compiler, cxx_compiler,
666              fortran_compiler, assembler, ar]
667             + other_tools)
668
669    return filter(lambda x: x, tools)
670
671# Local Variables:
672# tab-width:4
673# indent-tabs-mode:nil
674# End:
675# vim: set expandtab tabstop=4 shiftwidth=4:
676