Merge remote branch 'origin/nvc0'
[mesa.git] / scons / msvc_sa.py
1 """msvc_sa
2
3 Tool-specific initialization for Microsoft Visual C/C++.
4
5 Based on SCons.Tool.msvc, without the MSVS detection.
6
7 """
8
9 #
10 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
11 #
12 # Permission is hereby granted, free of charge, to any person obtaining
13 # a copy of this software and associated documentation files (the
14 # "Software"), to deal in the Software without restriction, including
15 # without limitation the rights to use, copy, modify, merge, publish,
16 # distribute, sublicense, and/or sell copies of the Software, and to
17 # permit persons to whom the Software is furnished to do so, subject to
18 # the following conditions:
19 #
20 # The above copyright notice and this permission notice shall be included
21 # in all copies or substantial portions of the Software.
22 #
23 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
24 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
25 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #
31
32 import os.path
33 import re
34 import string
35
36 import SCons.Action
37 import SCons.Builder
38 import SCons.Errors
39 import SCons.Platform.win32
40 import SCons.Tool
41 import SCons.Util
42 import SCons.Warnings
43 import SCons.Scanner.RC
44
45 CSuffixes = ['.c', '.C']
46 CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
47
48 def validate_vars(env):
49 """Validate the PCH and PCHSTOP construction variables."""
50 if env.has_key('PCH') and env['PCH']:
51 if not env.has_key('PCHSTOP'):
52 raise SCons.Errors.UserError, "The PCHSTOP construction must be defined if PCH is defined."
53 if not SCons.Util.is_String(env['PCHSTOP']):
54 raise SCons.Errors.UserError, "The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP']
55
56 def pch_emitter(target, source, env):
57 """Adds the object file target."""
58
59 validate_vars(env)
60
61 pch = None
62 obj = None
63
64 for t in target:
65 if SCons.Util.splitext(str(t))[1] == '.pch':
66 pch = t
67 if SCons.Util.splitext(str(t))[1] == '.obj':
68 obj = t
69
70 if not obj:
71 obj = SCons.Util.splitext(str(pch))[0]+'.obj'
72
73 target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work
74
75 return (target, source)
76
77 def object_emitter(target, source, env, parent_emitter):
78 """Sets up the PCH dependencies for an object file."""
79
80 validate_vars(env)
81
82 parent_emitter(target, source, env)
83
84 if env.has_key('PCH') and env['PCH']:
85 env.Depends(target, env['PCH'])
86
87 return (target, source)
88
89 def static_object_emitter(target, source, env):
90 return object_emitter(target, source, env,
91 SCons.Defaults.StaticObjectEmitter)
92
93 def shared_object_emitter(target, source, env):
94 return object_emitter(target, source, env,
95 SCons.Defaults.SharedObjectEmitter)
96
97 pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR')
98 pch_builder = SCons.Builder.Builder(action=pch_action, suffix='.pch',
99 emitter=pch_emitter,
100 source_scanner=SCons.Tool.SourceFileScanner)
101
102
103 # Logic to build .rc files into .res files (resource files)
104 res_scanner = SCons.Scanner.RC.RCScan()
105 res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
106 res_builder = SCons.Builder.Builder(action=res_action,
107 src_suffix='.rc',
108 suffix='.res',
109 src_builder=[],
110 source_scanner=res_scanner)
111
112 def msvc_batch_key(action, env, target, source):
113 """
114 Returns a key to identify unique batches of sources for compilation.
115
116 If batching is enabled (via the $MSVC_BATCH setting), then all
117 target+source pairs that use the same action, defined by the same
118 environment, and have the same target and source directories, will
119 be batched.
120
121 Returning None specifies that the specified target+source should not
122 be batched with other compilations.
123 """
124 b = env.subst('$MSVC_BATCH')
125 if b in (None, '', '0'):
126 # We're not using batching; return no key.
127 return None
128 t = target[0]
129 s = source[0]
130 if os.path.splitext(t.name)[0] != os.path.splitext(s.name)[0]:
131 # The base names are different, so this *must* be compiled
132 # separately; return no key.
133 return None
134 return (id(action), id(env), t.dir, s.dir)
135
136 def msvc_output_flag(target, source, env, for_signature):
137 """
138 Returns the correct /Fo flag for batching.
139
140 If batching is disabled or there's only one source file, then we
141 return an /Fo string that specifies the target explicitly. Otherwise,
142 we return an /Fo string that just specifies the first target's
143 directory (where the Visual C/C++ compiler will put the .obj files).
144 """
145 b = env.subst('$MSVC_BATCH')
146 if b in (None, '', '0') or len(source) == 1:
147 return '/Fo$TARGET'
148 else:
149 # The Visual C/C++ compiler requires a \ at the end of the /Fo
150 # option to indicate an output directory. We use os.sep here so
151 # that the test(s) for this can be run on non-Windows systems
152 # without having a hard-coded backslash mess up command-line
153 # argument parsing.
154 return '/Fo${TARGET.dir}' + os.sep
155
156 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR",
157 batch_key=msvc_batch_key,
158 targets='$CHANGED_TARGETS')
159 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR",
160 batch_key=msvc_batch_key,
161 targets='$CHANGED_TARGETS')
162 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR",
163 batch_key=msvc_batch_key,
164 targets='$CHANGED_TARGETS')
165 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR",
166 batch_key=msvc_batch_key,
167 targets='$CHANGED_TARGETS')
168
169 def generate(env):
170 """Add Builders and construction variables for MSVC++ to an Environment."""
171 static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
172
173 # TODO(batch): shouldn't reach in to cmdgen this way; necessary
174 # for now to bypass the checks in Builder.DictCmdGenerator.__call__()
175 # and allow .cc and .cpp to be compiled in the same command line.
176 static_obj.cmdgen.source_ext_match = False
177 shared_obj.cmdgen.source_ext_match = False
178
179 for suffix in CSuffixes:
180 static_obj.add_action(suffix, CAction)
181 shared_obj.add_action(suffix, ShCAction)
182 static_obj.add_emitter(suffix, static_object_emitter)
183 shared_obj.add_emitter(suffix, shared_object_emitter)
184
185 for suffix in CXXSuffixes:
186 static_obj.add_action(suffix, CXXAction)
187 shared_obj.add_action(suffix, ShCXXAction)
188 static_obj.add_emitter(suffix, static_object_emitter)
189 shared_obj.add_emitter(suffix, shared_object_emitter)
190
191 env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Z7") or ""}'])
192 env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'])
193 env['_MSVC_OUTPUT_FLAG'] = msvc_output_flag
194 env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS'
195 env['CC'] = 'cl'
196 env['CCFLAGS'] = SCons.Util.CLVar('/nologo')
197 env['CFLAGS'] = SCons.Util.CLVar('')
198 env['CCCOM'] = '$CC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CFLAGS $CCFLAGS $_CCCOMCOM'
199 env['SHCC'] = '$CC'
200 env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
201 env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
202 env['SHCCCOM'] = '$SHCC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCFLAGS $SHCCFLAGS $_CCCOMCOM'
203 env['CXX'] = '$CC'
204 env['CXXFLAGS'] = SCons.Util.CLVar('$( /TP $)')
205 env['CXXCOM'] = '$CXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CXXFLAGS $CCFLAGS $_CCCOMCOM'
206 env['SHCXX'] = '$CXX'
207 env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
208 env['SHCXXCOM'] = '$SHCXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM'
209 env['CPPDEFPREFIX'] = '/D'
210 env['CPPDEFSUFFIX'] = ''
211 env['INCPREFIX'] = '/I'
212 env['INCSUFFIX'] = ''
213 # env.Append(OBJEMITTER = [static_object_emitter])
214 # env.Append(SHOBJEMITTER = [shared_object_emitter])
215 env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
216
217 env['RC'] = 'rc'
218 env['RCFLAGS'] = SCons.Util.CLVar('')
219 env['RCSUFFIXES']=['.rc','.rc2']
220 env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
221 env['BUILDERS']['RES'] = res_builder
222 env['OBJPREFIX'] = ''
223 env['OBJSUFFIX'] = '.obj'
224 env['SHOBJPREFIX'] = '$OBJPREFIX'
225 env['SHOBJSUFFIX'] = '$OBJSUFFIX'
226
227 env['CFILESUFFIX'] = '.c'
228 env['CXXFILESUFFIX'] = '.cc'
229
230 env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}'])
231 env['PCHCOM'] = '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS'
232 env['BUILDERS']['PCH'] = pch_builder
233
234 if not env.has_key('ENV'):
235 env['ENV'] = {}
236 if not env['ENV'].has_key('SystemRoot'): # required for dlls in the winsxs folders
237 env['ENV']['SystemRoot'] = SCons.Platform.win32.get_system_root()
238
239 def exists(env):
240 return env.Detect('cl')
241
242 # Local Variables:
243 # tab-width:4
244 # indent-tabs-mode:nil
245 # End:
246 # vim: set expandtab tabstop=4 shiftwidth=4: