1 """engine.SCons.Tool.msvc
3 Tool-specific initialization for Microsoft Visual C/C++.
5 There normally shouldn't be any need to import this module directly.
6 It will usually be imported through the generic SCons.Tool.Tool()
14 # Permission is hereby granted, free of charge, to any person obtaining
15 # a copy of this software and associated documentation files (the
16 # "Software"), to deal in the Software without restriction, including
17 # without limitation the rights to use, copy, modify, merge, publish,
18 # distribute, sublicense, and/or sell copies of the Software, and to
19 # permit persons to whom the Software is furnished to do so, subject to
20 # the following conditions:
22 # The above copyright notice and this permission notice shall be included
23 # in all copies or substantial portions of the Software.
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
44 import SCons.Platform.win32
46 import SCons.Tool.msvs
49 import SCons.Scanner.RC
51 from MSCommon import msvc_exists, msvc_setup_env
53 CSuffixes = ['.c', '.C']
54 CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
56 def validate_vars(env):
57 """Validate the PCH and PCHSTOP construction variables."""
58 if env.has_key('PCH') and env['PCH']:
59 if not env.has_key('PCHSTOP'):
60 raise SCons.Errors.UserError, "The PCHSTOP construction must be defined if PCH is defined."
61 if not SCons.Util.is_String(env['PCHSTOP']):
62 raise SCons.Errors.UserError, "The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP']
64 def pch_emitter(target, source, env):
65 """Adds the object file target."""
73 if SCons.Util.splitext(str(t))[1] == '.pch':
75 if SCons.Util.splitext(str(t))[1] == '.obj':
79 obj = SCons.Util.splitext(str(pch))[0]+'.obj'
81 target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work
83 return (target, source)
85 def object_emitter(target, source, env, parent_emitter):
86 """Sets up the PCH dependencies for an object file."""
90 parent_emitter(target, source, env)
92 if env.has_key('PCH') and env['PCH']:
93 env.Depends(target, env['PCH'])
95 return (target, source)
97 def static_object_emitter(target, source, env):
98 return object_emitter(target, source, env,
99 SCons.Defaults.StaticObjectEmitter)
101 def shared_object_emitter(target, source, env):
102 return object_emitter(target, source, env,
103 SCons.Defaults.SharedObjectEmitter)
105 pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR')
106 pch_builder = SCons.Builder.Builder(action=pch_action, suffix='.pch',
108 source_scanner=SCons.Tool.SourceFileScanner)
111 # Logic to build .rc files into .res files (resource files)
112 res_scanner = SCons.Scanner.RC.RCScan()
113 res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
114 res_builder = SCons.Builder.Builder(action=res_action,
118 source_scanner=res_scanner)
120 def msvc_batch_key(action, env, target, source):
122 Returns a key to identify unique batches of sources for compilation.
124 If batching is enabled (via the $MSVC_BATCH setting), then all
125 target+source pairs that use the same action, defined by the same
126 environment, and have the same target and source directories, will
129 Returning None specifies that the specified target+source should not
130 be batched with other compilations.
132 b = env.subst('$MSVC_BATCH')
133 if b in (None, '', '0'):
134 # We're not using batching; return no key.
138 if os.path.splitext(t.name)[0] != os.path.splitext(s.name)[0]:
139 # The base names are different, so this *must* be compiled
140 # separately; return no key.
142 return (id(action), id(env), t.dir, s.dir)
144 def msvc_output_flag(target, source, env, for_signature):
146 Returns the correct /Fo flag for batching.
148 If batching is disabled or there's only one source file, then we
149 return an /Fo string that specifies the target explicitly. Otherwise,
150 we return an /Fo string that just specifies the first target's
151 directory (where the Visual C/C++ compiler will put the .obj files).
153 b = env.subst('$MSVC_BATCH')
154 if b in (None, '', '0') or len(source) == 1:
157 # The Visual C/C++ compiler requires a \ at the end of the /Fo
158 # option to indicate an output directory. We use os.sep here so
159 # that the test(s) for this can be run on non-Windows systems
160 # without having a hard-coded backslash mess up command-line
162 return '/Fo${TARGET.dir}' + os.sep
164 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR",
165 batch_key=msvc_batch_key,
166 targets='$CHANGED_TARGETS')
167 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR",
168 batch_key=msvc_batch_key,
169 targets='$CHANGED_TARGETS')
170 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR",
171 batch_key=msvc_batch_key,
172 targets='$CHANGED_TARGETS')
173 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR",
174 batch_key=msvc_batch_key,
175 targets='$CHANGED_TARGETS')
178 """Add Builders and construction variables for MSVC++ to an Environment."""
179 static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
181 # TODO(batch): shouldn't reach in to cmdgen this way; necessary
182 # for now to bypass the checks in Builder.DictCmdGenerator.__call__()
183 # and allow .cc and .cpp to be compiled in the same command line.
184 static_obj.cmdgen.source_ext_match = False
185 shared_obj.cmdgen.source_ext_match = False
187 for suffix in CSuffixes:
188 static_obj.add_action(suffix, CAction)
189 shared_obj.add_action(suffix, ShCAction)
190 static_obj.add_emitter(suffix, static_object_emitter)
191 shared_obj.add_emitter(suffix, shared_object_emitter)
193 for suffix in CXXSuffixes:
194 static_obj.add_action(suffix, CXXAction)
195 shared_obj.add_action(suffix, ShCXXAction)
196 static_obj.add_emitter(suffix, static_object_emitter)
197 shared_obj.add_emitter(suffix, shared_object_emitter)
199 env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Z7") or ""}'])
200 env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'])
201 env['_MSVC_OUTPUT_FLAG'] = msvc_output_flag
202 env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS'
204 env['CCFLAGS'] = SCons.Util.CLVar('/nologo')
205 env['CFLAGS'] = SCons.Util.CLVar('')
206 env['CCCOM'] = '$CC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CFLAGS $CCFLAGS $_CCCOMCOM'
208 env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
209 env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
210 env['SHCCCOM'] = '$SHCC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCFLAGS $SHCCFLAGS $_CCCOMCOM'
212 env['CXXFLAGS'] = SCons.Util.CLVar('$( /TP $)')
213 env['CXXCOM'] = '$CXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CXXFLAGS $CCFLAGS $_CCCOMCOM'
214 env['SHCXX'] = '$CXX'
215 env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
216 env['SHCXXCOM'] = '$SHCXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM'
217 env['CPPDEFPREFIX'] = '/D'
218 env['CPPDEFSUFFIX'] = ''
219 env['INCPREFIX'] = '/I'
220 env['INCSUFFIX'] = ''
221 # env.Append(OBJEMITTER = [static_object_emitter])
222 # env.Append(SHOBJEMITTER = [shared_object_emitter])
223 env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
226 env['RCFLAGS'] = SCons.Util.CLVar('')
227 env['RCSUFFIXES']=['.rc','.rc2']
228 env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
229 env['BUILDERS']['RES'] = res_builder
230 env['OBJPREFIX'] = ''
231 env['OBJSUFFIX'] = '.obj'
232 env['SHOBJPREFIX'] = '$OBJPREFIX'
233 env['SHOBJSUFFIX'] = '$OBJSUFFIX'
235 # Set-up ms tools paths for default version
241 env['CFILESUFFIX'] = '.c'
242 env['CXXFILESUFFIX'] = '.cc'
244 env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}'])
245 env['PCHCOM'] = '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS'
246 env['BUILDERS']['PCH'] = pch_builder
248 if not env.has_key('ENV'):
250 if not env['ENV'].has_key('SystemRoot'): # required for dlls in the winsxs folders
251 env['ENV']['SystemRoot'] = SCons.Platform.win32.get_system_root()
254 return msvc_exists('cl')
258 # indent-tabs-mode:nil
260 # vim: set expandtab tabstop=4 shiftwidth=4: