50ab4564786363e3ad31422bc935c994951328ac
[scons.git] / src / engine / SCons / Tool / __init__.py
1 """SCons.Tool
2
3 SCons tool selection.
4
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
7 chain).
8
9 Note that because this subsysem 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
13 tool definition.
14 """
15
16 #
17 # __COPYRIGHT__
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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
40
41 import imp
42 import sys
43
44 import SCons.Errors
45 import SCons.Defaults
46
47 class ToolSpec:
48     def __init__(self, name):
49         self.name = name
50
51     def __str__(self):
52         return self.name
53     
54 def Tool(name, platform = None):
55     """Select a canned Tool specification.
56     """
57     full_name = 'SCons.Tool.' + name
58     if not sys.modules.has_key(full_name):
59         try:
60             file, path, desc = imp.find_module(name,
61                                         sys.modules['SCons.Tool'].__path__)
62             imp.load_module(full_name, file, path, desc)
63         except ImportError:
64             raise SCons.Errors.UserError, "No tool named '%s'" % name
65         if file:
66             file.close()
67     spec = ToolSpec(name)
68     spec.__call__ = sys.modules[full_name].generate
69     spec.exists = sys.modules[full_name].exists
70     return spec
71
72 def createObjBuilders(env):
73     """This is a utility function that creates the Object
74     and SharedObject Builders in an Environment if they
75     are not there already.
76
77     If they are there already, we return the existing ones.
78
79     This is a separate function because soooo many Tools
80     use this functionality.
81
82     The return is a 2-tuple of (StaticObject, SharedObject)
83     """
84
85     try:
86         static_obj = env['BUILDERS']['Object']
87     except KeyError:
88         static_obj = SCons.Defaults.StaticObject()
89         env['BUILDERS']['Object'] = static_obj
90         env['BUILDERS']['StaticObject'] = static_obj
91
92     try:
93         shared_obj = env['BUILDERS']['SharedObject']
94     except KeyError:
95         shared_obj = SCons.Defaults.SharedObject()
96         env['BUILDERS']['SharedObject'] = shared_obj
97
98     return (static_obj, shared_obj)
99
100 def createCFileBuilders(env):
101     """This is a utility function that creates the CFile/CXXFile
102     Builders in an Environment if they
103     are not there already.
104
105     If they are there already, we return the existing ones.
106
107     This is a separate function because soooo many Tools
108     use this functionality.
109
110     The return is a 2-tuple of (CFile, CXXFile)
111     """
112
113     try:
114         c_file = env['BUILDERS']['CFile']
115     except KeyError:
116         c_file = SCons.Defaults.CFile()
117         env['BUILDERS']['CFile'] = c_file
118         env['CFILESUFFIX'] = '.c'
119
120     try:
121         cxx_file = env['BUILDERS']['CXXFile']
122     except KeyError:
123         cxx_file = SCons.Defaults.CXXFile()
124         env['BUILDERS']['CXXFile'] = cxx_file
125         env['CXXFILESUFFIX'] = '.cc'
126
127     return (c_file, cxx_file)
128
129 def FindTool(tools, env):
130     for tool in tools:
131         t = Tool(tool)
132         if t.exists(env):
133             return tool
134     return None
135
136 def FindAllTools(tools, env):
137     def ToolExists(tool, env=env):
138         return Tool(tool).exists(env)
139     return filter (ToolExists, tools)
140              
141 def tool_list(platform, env):
142
143     # XXX this logic about what tool to prefer on which platform
144     #     should be moved into either the platform files or
145     #     the tool files themselves.
146     if str(platform) == 'win32':
147         "prefer Microsoft tools on Windows"
148         linkers = ['mslink', 'gnulink', 'ilink', 'linkloc' ]
149         c_compilers = ['msvc', 'mingw', 'gcc', 'icc' ]
150         assemblers = ['masm', 'nasm', 'gas', '386asm' ]
151         fortran_compilers = ['g77', 'ifl']
152         ars = ['mslib', 'ar']
153     elif str(platform) == 'os2':
154         "prefer IBM tools on OS/2"
155         linkers = ['ilink', 'gnulink', 'mslink']
156         c_compilers = ['icc', 'gcc', 'msvc']
157         assemblers = ['nasm', 'masm', 'gas']
158         fortran_compilers = ['ifl', 'g77']
159         ars = ['ar', 'mslib']
160     else:
161         "prefer GNU tools on all other platforms"
162         linkers = ['gnulink', 'mslink', 'ilink']
163         c_compilers = ['gcc', 'msvc', 'icc']
164         assemblers = ['gas', 'nasm', 'masm']
165         fortran_compilers = ['g77', 'ifl']
166         ars = ['ar', 'mslib']
167
168     c_compiler = FindTool(c_compilers, env) or c_compilers[0]
169  
170     # XXX this logic about what tool provides what should somehow be
171     #     moved into the tool files themselves.
172     if c_compiler and c_compiler == 'mingw':
173         # MinGW contains a linker, C compiler, C++ compiler, 
174         # Fortran compiler, archiver and assember:
175         linker = None
176         assembler = None
177         fortran_compiler = None
178         ar = None
179         cxx_compiler = None
180     else:
181         linker = FindTool(linkers, env) or linkers[0]
182         assembler = FindTool(assemblers, env) or assemblers[0]
183         fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0]
184         ar = FindTool(ars, env) or ars[0]
185
186         # Don't use g++ if the C compiler has built-in C++ support:
187         if c_compiler and (c_compiler == 'msvc' or c_compiler == 'icc'):
188             cxx_compiler = None
189         else:
190             cxx_compiler = FindTool(['g++'], env)
191         
192     other_tools = FindAllTools(['dvipdf', 'dvips',
193                                 'latex', 'lex',
194                                 'pdflatex', 'pdftex',
195                                 'tar', 'tex', 'yacc'], env)
196
197     tools = ([linker, c_compiler, cxx_compiler,
198               fortran_compiler, assembler, ar]
199              + other_tools)
200     
201     return filter(lambda x: x, tools)