3 Tool-specific initialization for Microsoft Visual C/C++.
5 Based on SCons.Tool.msvc, without the MSVS detection.
10 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
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:
20 # The above copyright notice and this permission notice shall be included
21 # in all copies or substantial portions of the Software.
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.
39 import SCons.Platform.win32
43 import SCons.Scanner.RC
45 CSuffixes = ['.c', '.C']
46 CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
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']
56 def pch_emitter(target, source, env):
57 """Adds the object file target."""
65 if SCons.Util.splitext(str(t))[1] == '.pch':
67 if SCons.Util.splitext(str(t))[1] == '.obj':
71 obj = SCons.Util.splitext(str(pch))[0]+'.obj'
73 target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work
75 return (target, source)
77 def object_emitter(target, source, env, parent_emitter):
78 """Sets up the PCH dependencies for an object file."""
82 parent_emitter(target, source, env)
84 if env.has_key('PCH') and env['PCH']:
85 env.Depends(target, env['PCH'])
87 return (target, source)
89 def static_object_emitter(target, source, env):
90 return object_emitter(target, source, env,
91 SCons.Defaults.StaticObjectEmitter)
93 def shared_object_emitter(target, source, env):
94 return object_emitter(target, source, env,
95 SCons.Defaults.SharedObjectEmitter)
97 pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR')
98 pch_builder = SCons.Builder.Builder(action=pch_action, suffix='.pch',
100 source_scanner=SCons.Tool.SourceFileScanner)
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,
110 source_scanner=res_scanner)
112 def msvc_batch_key(action, env, target, source):
114 Returns a key to identify unique batches of sources for compilation.
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
121 Returning None specifies that the specified target+source should not
122 be batched with other compilations.
124 b = env.subst('$MSVC_BATCH')
125 if b in (None, '', '0'):
126 # We're not using batching; return no key.
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.
134 return (id(action), id(env), t.dir, s.dir)
136 def msvc_output_flag(target, source, env, for_signature):
138 Returns the correct /Fo flag for batching.
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).
145 b = env.subst('$MSVC_BATCH')
146 if b in (None, '', '0') or len(source) == 1:
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
154 return '/Fo${TARGET.dir}' + os.sep
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')
170 """Add Builders and construction variables for MSVC++ to an Environment."""
171 static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
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
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)
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)
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'
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'
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'
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
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'
227 env['CFILESUFFIX'] = '.c'
228 env['CXXFILESUFFIX'] = '.cc'
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
234 if not env.has_key('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()
240 return env.Detect('cl')
244 # indent-tabs-mode:nil
246 # vim: set expandtab tabstop=4 shiftwidth=4: