3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 """SCons tool selection.
26 Looks for modules that define a callable object that can modify a
27 construction environment as appropriate for a given tool (or tool chain).
29 Note that because this subsystem just *selects* a callable that can
30 modify a construction environment, it's possible for people to define
31 their own "tool specification" in an arbitrary callable function. No
32 one needs to use or tie in to this subsystem in order to roll their own
36 from __future__
import annotations
46 import SCons
.Scanner
.C
47 import SCons
.Scanner
.D
48 import SCons
.Scanner
.Java
49 import SCons
.Scanner
.LaTeX
50 import SCons
.Scanner
.Prog
51 import SCons
.Scanner
.SWIG
52 from SCons
.Tool
.linkCommon
import LibSymlinksActionFunction
, LibSymlinksStrFun
56 CScanner
= SCons
.Scanner
.C
.CScanner()
57 DScanner
= SCons
.Scanner
.D
.DScanner()
58 JavaScanner
= SCons
.Scanner
.Java
.JavaScanner()
59 LaTeXScanner
= SCons
.Scanner
.LaTeX
.LaTeXScanner()
60 PDFLaTeXScanner
= SCons
.Scanner
.LaTeX
.PDFLaTeXScanner()
61 ProgramScanner
= SCons
.Scanner
.Prog
.ProgramScanner()
62 SourceFileScanner
= SCons
.Scanner
.ScannerBase({}, name
='SourceFileScanner')
63 SWIGScanner
= SCons
.Scanner
.SWIG
.SWIGScanner()
65 CSuffixes
= [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
66 ".h", ".H", ".hxx", ".hpp", ".hh",
69 ".S", ".spp", ".SPP", ".sx"]
73 IDLSuffixes
= [".idl", ".IDL"]
75 LaTeXSuffixes
= [".tex", ".ltx", ".latex"]
79 for suffix
in CSuffixes
:
80 SourceFileScanner
.add_scanner(suffix
, CScanner
)
82 for suffix
in DSuffixes
:
83 SourceFileScanner
.add_scanner(suffix
, DScanner
)
85 for suffix
in SWIGSuffixes
:
86 SourceFileScanner
.add_scanner(suffix
, SWIGScanner
)
88 # FIXME: what should be done here? Two scanners scan the same extensions,
89 # but look for different files, e.g., "picture.eps" vs. "picture.pdf".
90 # The builders for DVI and PDF explicitly reference their scanners
91 # I think that means this is not needed???
92 for suffix
in LaTeXSuffixes
:
93 SourceFileScanner
.add_scanner(suffix
, LaTeXScanner
)
94 SourceFileScanner
.add_scanner(suffix
, PDFLaTeXScanner
)
96 # Tool aliases are needed for those tools whose module names also
97 # occur in the python standard library (This causes module shadowing and
98 # can break using python library functions under python3) or if the current tool/file names
99 # are not legal module names (violate python's identifier rules or are
100 # python language keywords).
102 'gettext': 'gettext_tool',
103 'clang++': 'clangxx',
105 'ninja' : 'ninja_tool'
110 def __init__(self
, name
, toolpath
=None, **kwargs
) -> None:
114 # Rename if there's a TOOL_ALIAS for this tool
115 self
.name
= TOOL_ALIASES
.get(name
, name
)
116 self
.toolpath
= toolpath
+ DefaultToolpath
117 # remember these so we can merge them into the call
118 self
.init_kw
= kwargs
120 module
= self
._tool
_module
()
121 self
.generate
= module
.generate
122 self
.exists
= module
.exists
123 if hasattr(module
, 'options'):
124 self
.options
= module
.options
126 def _tool_module(self
):
127 """Try to load a tool module.
129 This will hunt in the toolpath for both a Python file (toolname.py)
130 and a Python module (toolname directory), then try the regular
131 import machinery, then fallback to try a zipfile.
133 oldpythonpath
= sys
.path
134 sys
.path
= self
.toolpath
+ sys
.path
135 # These could be enabled under "if debug:"
136 # sys.stderr.write(f"Tool: {self.name}\n")
137 # sys.stderr.write(f"PATH: {sys.path}\n")
138 # sys.stderr.write(f"toolpath: {self.toolpath}\n")
139 # sys.stderr.write(f"SCONS.TOOL path: {sys.modules['SCons.Tool'].__path__}\n")
142 found_name
= self
.name
143 add_to_scons_tools_namespace
= False
145 # Search for the tool module, but don't import it, yet.
147 # First look in the toolpath: these take priority.
148 # TODO: any reason to not just use find_spec here?
149 for path
in self
.toolpath
:
150 sepname
= self
.name
.replace('.', os
.path
.sep
)
151 file_path
= os
.path
.join(path
, sepname
+ ".py")
152 file_package
= os
.path
.join(path
, sepname
)
154 if debug
: sys
.stderr
.write(f
"Trying: {file_path} {file_package}\n")
156 if os
.path
.isfile(file_path
):
157 spec
= importlib
.util
.spec_from_file_location(self
.name
, file_path
)
158 if debug
: sys
.stderr
.write(f
"file_Path: {file_path} FOUND\n")
160 elif os
.path
.isdir(file_package
):
161 file_package
= os
.path
.join(file_package
, '__init__.py')
162 spec
= importlib
.util
.spec_from_file_location(self
.name
, file_package
)
163 if debug
: sys
.stderr
.write(f
"PACKAGE: {file_package} Found\n")
168 # Now look in the builtin tools (SCons.Tool package)
170 if debug
: sys
.stderr
.write(f
"NO SPEC: {self.name}\n")
171 spec
= importlib
.util
.find_spec("." + self
.name
, package
='SCons.Tool')
173 found_name
= 'SCons.Tool.' + self
.name
174 add_to_scons_tools_namespace
= True
175 if debug
: sys
.stderr
.write(f
"Spec Found? .{self.name}: {spec}\n")
178 # we are going to bail out here, format up stuff for the msg
179 sconstools
= os
.path
.normpath(sys
.modules
['SCons.Tool'].__path
__[0])
181 sconstools
= ", ".join(self
.toolpath
) + ", " + sconstools
182 msg
= f
"No tool module '{self.name}' found in {sconstools}"
183 raise SCons
.Errors
.UserError(msg
)
185 # We have a module spec, so we're good to go.
186 module
= importlib
.util
.module_from_spec(spec
)
188 if debug
: sys
.stderr
.write(f
"MODULE IS NONE: {self.name}\n")
189 msg
= f
"Tool module '{self.name}' failed import"
190 raise SCons
.Errors
.SConsEnvironmentError(msg
)
192 # Don't reload a tool we already loaded.
193 sys_modules_value
= sys
.modules
.get(found_name
, False)
196 if sys_modules_value
and sys_modules_value
.__file
__ == spec
.origin
:
197 found_module
= sys
.modules
[found_name
]
199 # Not sure what to do in the case that there already
200 # exists sys.modules[self.name] but the source file is
202 sys
.modules
[found_name
] = module
203 spec
.loader
.exec_module(module
)
204 if add_to_scons_tools_namespace
:
205 # If we found it in SCons.Tool, add it to the module
206 setattr(SCons
.Tool
, self
.name
, module
)
207 found_module
= module
209 if found_module
is not None:
210 sys
.path
= oldpythonpath
213 sys
.path
= oldpythonpath
215 # We try some other things here, but this is essentially dead code,
216 # because we bailed out above if we didn't find a module spec.
217 full_name
= 'SCons.Tool.' + self
.name
219 return sys
.modules
[full_name
]
222 # This support was added to enable running inside
223 # a py2exe bundle a long time ago - unclear if it's
224 # still needed. It is *not* intended to load individual
225 # tool modules stored in a zipfile.
228 tooldir
= sys
.modules
['SCons.Tool'].__path
__[0]
229 importer
= zipimport
.zipimporter(tooldir
)
230 if not hasattr(importer
, 'find_spec'):
231 # zipimport only added find_spec, exec_module in 3.10,
232 # unlike importlib, where they've been around since 3.4.
233 # If we don't have 'em, use the old way.
234 module
= importer
.load_module(full_name
)
236 spec
= importer
.find_spec(full_name
)
237 module
= importlib
.util
.module_from_spec(spec
)
238 importer
.exec_module(module
)
239 sys
.modules
[full_name
] = module
240 setattr(SCons
.Tool
, self
.name
, module
)
242 except zipimport
.ZipImportError
as e
:
243 msg
= "No tool named '{self.name}': {e}"
244 raise SCons
.Errors
.SConsEnvironmentError(msg
)
246 def __call__(self
, env
, *args
, **kw
) -> None:
247 if self
.init_kw
is not None:
248 # Merge call kws into init kws;
249 # but don't bash self.init_kw.
252 kw
= self
.init_kw
.copy()
256 env
.AppendUnique(TOOLS
=[self
.name
])
257 if hasattr(self
, 'options'):
258 import SCons
.Variables
259 if 'options' not in env
:
260 from SCons
.Script
import ARGUMENTS
261 env
['options'] = SCons
.Variables
.Variables(args
=ARGUMENTS
)
262 opts
= env
['options']
267 self
.generate(env
, *args
, **kw
)
269 def __str__(self
) -> str:
273 LibSymlinksAction
= SCons
.Action
.Action(LibSymlinksActionFunction
, LibSymlinksStrFun
)
276 ##########################################################################
277 # Create common executable program / library / object builders
279 def createProgBuilder(env
):
280 """This is a utility function that creates the Program
281 Builder in an Environment if it is not there already.
283 If it is already there, we return the existing one.
287 program
= env
['BUILDERS']['Program']
289 import SCons
.Defaults
290 program
= SCons
.Builder
.Builder(action
=SCons
.Defaults
.LinkAction
,
291 emitter
='$PROGEMITTER',
292 prefix
='$PROGPREFIX',
293 suffix
='$PROGSUFFIX',
294 src_suffix
='$OBJSUFFIX',
295 src_builder
='Object',
296 target_scanner
=ProgramScanner
)
297 env
['BUILDERS']['Program'] = program
302 def createStaticLibBuilder(env
):
303 """This is a utility function that creates the StaticLibrary
304 Builder in an Environment if it is not there already.
306 If it is already there, we return the existing one.
310 static_lib
= env
['BUILDERS']['StaticLibrary']
312 action_list
= [SCons
.Action
.Action("$ARCOM", "$ARCOMSTR")]
313 if env
.get('RANLIB', False) or env
.Detect('ranlib'):
314 ranlib_action
= SCons
.Action
.Action("$RANLIBCOM", "$RANLIBCOMSTR")
315 action_list
.append(ranlib_action
)
317 static_lib
= SCons
.Builder
.Builder(action
=action_list
,
318 emitter
='$LIBEMITTER',
321 src_suffix
='$OBJSUFFIX',
322 src_builder
='StaticObject')
323 env
['BUILDERS']['StaticLibrary'] = static_lib
324 env
['BUILDERS']['Library'] = static_lib
329 def createSharedLibBuilder(env
, shlib_suffix
: str='$_SHLIBSUFFIX'):
330 """This is a utility function that creates the SharedLibrary
331 Builder in an Environment if it is not there already.
333 If it is already there, we return the existing one.
336 shlib_suffix: The suffix specified for the shared library builder
341 shared_lib
= env
['BUILDERS']['SharedLibrary']
343 import SCons
.Defaults
344 action_list
= [SCons
.Defaults
.SharedCheck
,
345 SCons
.Defaults
.ShLinkAction
,
347 shared_lib
= SCons
.Builder
.Builder(action
=action_list
,
348 emitter
="$SHLIBEMITTER",
349 prefix
="$SHLIBPREFIX",
351 target_scanner
=ProgramScanner
,
352 src_suffix
='$SHOBJSUFFIX',
353 src_builder
='SharedObject')
354 env
['BUILDERS']['SharedLibrary'] = shared_lib
359 def createLoadableModuleBuilder(env
, loadable_module_suffix
: str='$_LDMODULESUFFIX'):
360 """This is a utility function that creates the LoadableModule
361 Builder in an Environment if it is not there already.
363 If it is already there, we return the existing one.
366 loadable_module_suffix: The suffix specified for the loadable module builder
371 ld_module
= env
['BUILDERS']['LoadableModule']
373 import SCons
.Defaults
374 action_list
= [SCons
.Defaults
.SharedCheck
,
375 SCons
.Defaults
.LdModuleLinkAction
,
377 ld_module
= SCons
.Builder
.Builder(action
=action_list
,
378 emitter
="$LDMODULEEMITTER",
379 prefix
="$LDMODULEPREFIX",
380 suffix
=loadable_module_suffix
,
381 target_scanner
=ProgramScanner
,
382 src_suffix
='$SHOBJSUFFIX',
383 src_builder
='SharedObject')
384 env
['BUILDERS']['LoadableModule'] = ld_module
389 def createObjBuilders(env
):
390 """This is a utility function that creates the StaticObject
391 and SharedObject Builders in an Environment if they
392 are not there already.
394 If they are there already, we return the existing ones.
396 This is a separate function because soooo many Tools
397 use this functionality.
399 The return is a 2-tuple of (StaticObject, SharedObject)
403 static_obj
= env
['BUILDERS']['StaticObject']
405 static_obj
= SCons
.Builder
.Builder(action
={},
409 src_builder
=['CFile', 'CXXFile'],
410 source_scanner
=SourceFileScanner
,
412 env
['BUILDERS']['StaticObject'] = static_obj
413 env
['BUILDERS']['Object'] = static_obj
416 shared_obj
= env
['BUILDERS']['SharedObject']
418 shared_obj
= SCons
.Builder
.Builder(action
={},
420 prefix
='$SHOBJPREFIX',
421 suffix
='$SHOBJSUFFIX',
422 src_builder
=['CFile', 'CXXFile'],
423 source_scanner
=SourceFileScanner
,
425 env
['BUILDERS']['SharedObject'] = shared_obj
427 return (static_obj
, shared_obj
)
430 def createCFileBuilders(env
):
431 """This is a utility function that creates the CFile/CXXFile
432 Builders in an Environment if they
433 are not there already.
435 If they are there already, we return the existing ones.
437 This is a separate function because soooo many Tools
438 use this functionality.
440 The return is a 2-tuple of (CFile, CXXFile)
444 c_file
= env
['BUILDERS']['CFile']
446 c_file
= SCons
.Builder
.Builder(action
={},
448 suffix
={None: '$CFILESUFFIX'})
449 env
['BUILDERS']['CFile'] = c_file
451 env
.SetDefault(CFILESUFFIX
='.c')
454 cxx_file
= env
['BUILDERS']['CXXFile']
456 cxx_file
= SCons
.Builder
.Builder(action
={},
458 suffix
={None: '$CXXFILESUFFIX'})
459 env
['BUILDERS']['CXXFile'] = cxx_file
460 env
.SetDefault(CXXFILESUFFIX
='.cc')
462 return (c_file
, cxx_file
)
465 ##########################################################################
466 # Create common Java builders
468 def CreateJarBuilder(env
):
469 """The Jar builder expects a list of class files
470 which it can package into a jar file.
472 The jar tool provides an interface for passing other types
473 of java files such as .java, directories or swig interfaces
474 and will build them to class files in which it can package
478 java_jar
= env
['BUILDERS']['JarFile']
480 fs
= SCons
.Node
.FS
.get_default_fs()
481 jar_com
= SCons
.Action
.Action('$JARCOM', '$JARCOMSTR')
482 java_jar
= SCons
.Builder
.Builder(action
=jar_com
,
484 src_suffix
='$JAVACLASSSUFFIX',
485 src_builder
='JavaClassFile',
486 source_factory
=fs
.Entry
)
487 env
['BUILDERS']['JarFile'] = java_jar
491 def CreateJavaHBuilder(env
):
493 java_javah
= env
['BUILDERS']['JavaH']
495 fs
= SCons
.Node
.FS
.get_default_fs()
496 java_javah_com
= SCons
.Action
.Action('$JAVAHCOM', '$JAVAHCOMSTR')
497 java_javah
= SCons
.Builder
.Builder(action
=java_javah_com
,
498 src_suffix
='$JAVACLASSSUFFIX',
499 target_factory
=fs
.Entry
,
500 source_factory
=fs
.File
,
501 src_builder
='JavaClassFile')
502 env
['BUILDERS']['JavaH'] = java_javah
506 def CreateJavaClassFileBuilder(env
):
508 java_class_file
= env
['BUILDERS']['JavaClassFile']
510 fs
= SCons
.Node
.FS
.get_default_fs()
511 javac_com
= SCons
.Action
.Action('$JAVACCOM', '$JAVACCOMSTR')
512 java_class_file
= SCons
.Builder
.Builder(action
=javac_com
,
514 # suffix = '$JAVACLASSSUFFIX',
515 src_suffix
='$JAVASUFFIX',
516 src_builder
=['JavaFile'],
517 target_factory
=fs
.Entry
,
518 source_factory
=fs
.File
,
519 target_scanner
=JavaScanner
)
520 env
['BUILDERS']['JavaClassFile'] = java_class_file
521 return java_class_file
524 def CreateJavaClassDirBuilder(env
):
526 java_class_dir
= env
['BUILDERS']['JavaClassDir']
528 fs
= SCons
.Node
.FS
.get_default_fs()
529 javac_com
= SCons
.Action
.Action('$JAVACCOM', '$JAVACCOMSTR')
530 java_class_dir
= SCons
.Builder
.Builder(action
=javac_com
,
532 target_factory
=fs
.Dir
,
533 source_factory
=fs
.Dir
,
534 target_scanner
=JavaScanner
)
535 env
['BUILDERS']['JavaClassDir'] = java_class_dir
536 return java_class_dir
539 def CreateJavaFileBuilder(env
):
541 java_file
= env
['BUILDERS']['JavaFile']
543 java_file
= SCons
.Builder
.Builder(action
={},
545 suffix
={None: '$JAVASUFFIX'})
546 env
['BUILDERS']['JavaFile'] = java_file
547 env
['JAVASUFFIX'] = '.java'
551 class ToolInitializerMethod
:
553 This is added to a construction environment in place of a
554 method(s) normally called for a Builder (env.Object, env.StaticObject,
555 etc.). When called, it has its associated ToolInitializer
556 object search the specified list of tools and apply the first
557 one that exists to the construction environment. It then calls
558 whatever builder was (presumably) added to the construction
559 environment in place of this particular instance.
562 def __init__(self
, name
, initializer
) -> None:
564 Note: we store the tool name as __name__ so it can be used by
565 the class that attaches this to a construction environment.
568 self
.initializer
= initializer
570 def get_builder(self
, env
):
572 Returns the appropriate real Builder for this method name
573 after having the associated ToolInitializer object apply
574 the appropriate Tool module.
576 builder
= getattr(env
, self
.__name
__)
578 self
.initializer
.apply_tools(env
)
580 builder
= getattr(env
, self
.__name
__)
582 # There was no Builder added, which means no valid Tool
583 # for this name was found (or possibly there's a mismatch
584 # between the name we were called by and the Builder name
585 # added by the Tool module).
588 self
.initializer
.remove_methods(env
)
592 def __call__(self
, env
, *args
, **kw
):
595 builder
= self
.get_builder(env
)
598 return builder(*args
, **kw
)
601 class ToolInitializer
:
603 A class for delayed initialization of Tools modules.
605 Instances of this class associate a list of Tool modules with
606 a list of Builder method names that will be added by those Tool
607 modules. As part of instantiating this object for a particular
608 construction environment, we also add the appropriate
609 ToolInitializerMethod objects for the various Builder methods
610 that we want to use to delay Tool searches until necessary.
613 def __init__(self
, env
, tools
, names
) -> None:
614 if not SCons
.Util
.is_List(tools
):
616 if not SCons
.Util
.is_List(names
):
623 method
= ToolInitializerMethod(name
, self
)
624 self
.methods
[name
] = method
625 env
.AddMethod(method
)
627 def remove_methods(self
, env
) -> None:
629 Removes the methods that were added by the tool initialization
630 so we no longer copy and re-bind them when the construction
631 environment gets cloned.
633 for method
in self
.methods
.values():
634 env
.RemoveMethod(method
)
636 def apply_tools(self
, env
) -> None:
638 Searches the list of associated Tool modules for one that
639 exists, and applies that to the construction environment.
642 tool
= SCons
.Tool
.Tool(t
)
647 # If we fall through here, there was no tool module found.
648 # This is where we can put an informative error message
649 # about the inability to find the tool. We'll start doing
650 # this as we cut over more pre-defined Builder+Tools to use
651 # the ToolInitializer class.
654 def Initializers(env
) -> None:
655 ToolInitializer(env
, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib'])
657 def Install(self
, *args
, **kw
):
658 return self
._InternalInstall
(*args
, **kw
)
660 def InstallAs(self
, *args
, **kw
):
661 return self
._InternalInstallAs
(*args
, **kw
)
663 def InstallVersionedLib(self
, *args
, **kw
):
664 return self
._InternalInstallVersionedLib
(*args
, **kw
)
666 env
.AddMethod(Install
)
667 env
.AddMethod(InstallAs
)
668 env
.AddMethod(InstallVersionedLib
)
671 def FindTool(tools
, env
):
679 def FindAllTools(tools
, env
):
680 def ToolExists(tool
, env
=env
):
681 return Tool(tool
).exists(env
)
683 return list(filter(ToolExists
, tools
))
686 def tool_list(platform
, env
):
687 other_plat_tools
= []
688 # XXX this logic about what tool to prefer on which platform
689 # should be moved into either the platform files or
690 # the tool files themselves.
691 # The search orders here are described in the man page. If you
692 # change these search orders, update the man page as well.
693 if str(platform
) == 'win32':
694 "prefer Microsoft tools on Windows"
695 linkers
= ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32']
696 c_compilers
= ['msvc', 'mingw', 'gcc', 'clang', 'intelc', 'icl', 'icc', 'cc', 'bcc32']
697 cxx_compilers
= ['msvc', 'intelc', 'icc', 'g++', 'clang++', 'cxx', 'bcc32']
698 assemblers
= ['masm', 'nasm', 'gas', '386asm']
699 fortran_compilers
= ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
700 ars
= ['mslib', 'ar', 'tlib']
701 other_plat_tools
= ['msvs', 'midl', 'wix']
702 elif str(platform
) == 'os2':
703 "prefer IBM tools on OS/2"
704 linkers
= ['ilink', 'gnulink', ] # 'mslink']
705 c_compilers
= ['icc', 'gcc', ] # 'msvc', 'cc']
706 cxx_compilers
= ['icc', 'g++', ] # 'msvc', 'cxx']
707 assemblers
= ['nasm', ] # 'masm', 'gas']
708 fortran_compilers
= ['ifl', 'g77']
709 ars
= ['ar', ] # 'mslib']
710 elif str(platform
) == 'irix':
711 "prefer MIPSPro on IRIX"
712 linkers
= ['sgilink', 'gnulink']
713 c_compilers
= ['sgicc', 'gcc', 'cc']
714 cxx_compilers
= ['sgicxx', 'g++', 'cxx']
715 assemblers
= ['as', 'gas']
716 fortran_compilers
= ['f95', 'f90', 'f77', 'g77', 'fortran']
718 elif str(platform
) == 'sunos':
719 "prefer Forte tools on SunOS"
720 linkers
= ['sunlink', 'gnulink']
721 c_compilers
= ['suncc', 'gcc', 'cc']
722 cxx_compilers
= ['suncxx', 'g++', 'cxx']
723 assemblers
= ['as', 'gas']
724 fortran_compilers
= ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77',
725 'gfortran', 'g77', 'fortran']
727 elif str(platform
) == 'hpux':
728 "prefer aCC tools on HP-UX"
729 linkers
= ['hplink', 'gnulink']
730 c_compilers
= ['hpcc', 'gcc', 'cc']
731 cxx_compilers
= ['hpcxx', 'g++', 'cxx']
732 assemblers
= ['as', 'gas']
733 fortran_compilers
= ['f95', 'f90', 'f77', 'g77', 'fortran']
735 elif str(platform
) == 'aix':
736 "prefer AIX Visual Age tools on AIX"
737 linkers
= ['aixlink', 'gnulink']
738 c_compilers
= ['aixcc', 'gcc', 'cc']
739 cxx_compilers
= ['aixcxx', 'g++', 'cxx']
740 assemblers
= ['as', 'gas']
741 fortran_compilers
= ['f95', 'f90', 'aixf77', 'g77', 'fortran']
743 elif str(platform
) == 'darwin':
744 "prefer GNU tools on Mac OS X, except for some linkers and IBM tools"
745 linkers
= ['applelink', 'gnulink']
746 c_compilers
= ['gcc', 'cc']
747 cxx_compilers
= ['g++', 'cxx']
749 fortran_compilers
= ['gfortran', 'f95', 'f90', 'g77']
751 elif str(platform
) == 'cygwin':
752 "prefer GNU tools on Cygwin, except for a platform-specific linker"
753 linkers
= ['cyglink', 'mslink', 'ilink']
754 c_compilers
= ['gcc', 'msvc', 'intelc', 'icc', 'cc']
755 cxx_compilers
= ['g++', 'msvc', 'intelc', 'icc', 'cxx']
756 assemblers
= ['gas', 'nasm', 'masm']
757 fortran_compilers
= ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
758 ars
= ['ar', 'mslib']
760 "prefer GNU tools on all other platforms"
761 linkers
= ['gnulink', 'ilink']
762 c_compilers
= ['gcc', 'clang', 'intelc', 'icc', 'cc']
763 cxx_compilers
= ['g++', 'clang++', 'intelc', 'icc', 'cxx']
764 assemblers
= ['gas', 'nasm', 'masm']
765 fortran_compilers
= ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
768 if not str(platform
) == 'win32':
769 other_plat_tools
+= ['m4', 'rpm']
771 c_compiler
= FindTool(c_compilers
, env
) or c_compilers
[0]
773 # XXX this logic about what tool provides what should somehow be
774 # moved into the tool files themselves.
775 if c_compiler
and c_compiler
== 'mingw':
776 # MinGW contains a linker, C compiler, C++ compiler,
777 # Fortran compiler, archiver and assembler:
781 fortran_compiler
= None
784 # Don't use g++ if the C compiler has built-in C++ support:
785 if c_compiler
in ('msvc', 'intelc', 'icc'):
788 cxx_compiler
= FindTool(cxx_compilers
, env
) or cxx_compilers
[0]
789 linker
= FindTool(linkers
, env
) or linkers
[0]
790 assembler
= FindTool(assemblers
, env
) or assemblers
[0]
791 fortran_compiler
= FindTool(fortran_compilers
, env
) or fortran_compilers
[0]
792 ar
= FindTool(ars
, env
) or ars
[0]
794 d_compilers
= ['dmd', 'ldc', 'gdc']
795 d_compiler
= FindTool(d_compilers
, env
) or d_compilers
[0]
797 other_tools
= FindAllTools(other_plat_tools
+ [
798 # TODO: merge 'install' into 'filesystem' and
799 # make 'filesystem' the default
803 # Foreign function interface
806 'jar', 'javac', 'javah', 'rmic',
808 'dvipdf', 'dvips', 'gs',
809 'tex', 'latex', 'pdflatex', 'pdftex',
812 # File builders (text)
826 return [x
for x
in tools
if x
]
829 def find_program_path(env
, key_program
, default_paths
=None, add_path
: bool=False) -> str |
None:
831 Find the location of a tool using various means.
833 Mainly for windows where tools aren't all installed in /usr/bin, etc.
836 env: Current Construction Environment.
837 key_program: Tool to locate.
838 default_paths: List of additional paths this tool might be found in.
839 add_path: If true, add path found if it was from *default_paths*.
841 # First search in the SCons path
842 path
= env
.WhereIs(key_program
)
846 # Then in the OS path
847 path
= SCons
.Util
.WhereIs(key_program
)
850 env
.AppendENVPath('PATH', os
.path
.dirname(path
))
853 # Finally, add the defaults and check again.
854 if default_paths
is None:
857 save_path
= env
['ENV']['PATH']
858 for p
in default_paths
:
859 env
.AppendENVPath('PATH', p
)
860 path
= env
.WhereIs(key_program
)
862 # By default, do not change ['ENV']['PATH'] permananetly
863 # leave that to the caller, unless add_path is true.
864 env
['ENV']['PATH'] = save_path
865 if path
and add_path
:
866 env
.AppendENVPath('PATH', os
.path
.dirname(path
))
872 # indent-tabs-mode:nil
874 # vim: set expandtab tabstop=4 shiftwidth=4: