OLD | NEW |
(Empty) | |
| 1 """engine.SCons.Tool.msvc |
| 2 |
| 3 Tool-specific initialization for Microsoft Visual C/C++. |
| 4 |
| 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() |
| 7 selection method. |
| 8 |
| 9 """ |
| 10 |
| 11 # |
| 12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S
Cons Foundation |
| 13 # |
| 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: |
| 21 # |
| 22 # The above copyright notice and this permission notice shall be included |
| 23 # in all copies or substantial portions of the Software. |
| 24 # |
| 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. |
| 32 # |
| 33 |
| 34 __revision__ = "src/engine/SCons/Tool/msvc.py 5134 2010/08/16 23:02:40 bdeegan" |
| 35 |
| 36 import os.path |
| 37 import re |
| 38 import sys |
| 39 |
| 40 import SCons.Action |
| 41 import SCons.Builder |
| 42 import SCons.Errors |
| 43 import SCons.Platform.win32 |
| 44 import SCons.Tool |
| 45 import SCons.Tool.msvs |
| 46 import SCons.Util |
| 47 import SCons.Warnings |
| 48 import SCons.Scanner.RC |
| 49 |
| 50 from MSCommon import msvc_exists, msvc_setup_env_once |
| 51 |
| 52 CSuffixes = ['.c', '.C'] |
| 53 CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] |
| 54 |
| 55 def validate_vars(env): |
| 56 """Validate the PCH and PCHSTOP construction variables.""" |
| 57 if 'PCH' in env and env['PCH']: |
| 58 if 'PCHSTOP' not in env: |
| 59 raise SCons.Errors.UserError("The PCHSTOP construction must be defin
ed if PCH is defined.") |
| 60 if not SCons.Util.is_String(env['PCHSTOP']): |
| 61 raise SCons.Errors.UserError("The PCHSTOP construction variable must
be a string: %r"%env['PCHSTOP']) |
| 62 |
| 63 def pch_emitter(target, source, env): |
| 64 """Adds the object file target.""" |
| 65 |
| 66 validate_vars(env) |
| 67 |
| 68 pch = None |
| 69 obj = None |
| 70 |
| 71 for t in target: |
| 72 if SCons.Util.splitext(str(t))[1] == '.pch': |
| 73 pch = t |
| 74 if SCons.Util.splitext(str(t))[1] == '.obj': |
| 75 obj = t |
| 76 |
| 77 if not obj: |
| 78 obj = SCons.Util.splitext(str(pch))[0]+'.obj' |
| 79 |
| 80 target = [pch, obj] # pch must be first, and obj second for the PCHCOM to wo
rk |
| 81 |
| 82 return (target, source) |
| 83 |
| 84 def object_emitter(target, source, env, parent_emitter): |
| 85 """Sets up the PCH dependencies for an object file.""" |
| 86 |
| 87 validate_vars(env) |
| 88 |
| 89 parent_emitter(target, source, env) |
| 90 |
| 91 # Add a dependency, but only if the target (e.g. 'Source1.obj') |
| 92 # doesn't correspond to the pre-compiled header ('Source1.pch'). |
| 93 # If the basenames match, then this was most likely caused by |
| 94 # someone adding the source file to both the env.PCH() and the |
| 95 # env.Program() calls, and adding the explicit dependency would |
| 96 # cause a cycle on the .pch file itself. |
| 97 # |
| 98 # See issue #2505 for a discussion of what to do if it turns |
| 99 # out this assumption causes trouble in the wild: |
| 100 # http://scons.tigris.org/issues/show_bug.cgi?id=2505 |
| 101 if 'PCH' in env: |
| 102 pch = env['PCH'] |
| 103 if str(target[0]) != SCons.Util.splitext(str(pch))[0] + '.obj': |
| 104 env.Depends(target, pch) |
| 105 |
| 106 return (target, source) |
| 107 |
| 108 def static_object_emitter(target, source, env): |
| 109 return object_emitter(target, source, env, |
| 110 SCons.Defaults.StaticObjectEmitter) |
| 111 |
| 112 def shared_object_emitter(target, source, env): |
| 113 return object_emitter(target, source, env, |
| 114 SCons.Defaults.SharedObjectEmitter) |
| 115 |
| 116 pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR') |
| 117 pch_builder = SCons.Builder.Builder(action=pch_action, suffix='.pch', |
| 118 emitter=pch_emitter, |
| 119 source_scanner=SCons.Tool.SourceFileScanner) |
| 120 |
| 121 |
| 122 # Logic to build .rc files into .res files (resource files) |
| 123 res_scanner = SCons.Scanner.RC.RCScan() |
| 124 res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') |
| 125 res_builder = SCons.Builder.Builder(action=res_action, |
| 126 src_suffix='.rc', |
| 127 suffix='.res', |
| 128 src_builder=[], |
| 129 source_scanner=res_scanner) |
| 130 |
| 131 def msvc_batch_key(action, env, target, source): |
| 132 """ |
| 133 Returns a key to identify unique batches of sources for compilation. |
| 134 |
| 135 If batching is enabled (via the $MSVC_BATCH setting), then all |
| 136 target+source pairs that use the same action, defined by the same |
| 137 environment, and have the same target and source directories, will |
| 138 be batched. |
| 139 |
| 140 Returning None specifies that the specified target+source should not |
| 141 be batched with other compilations. |
| 142 """ |
| 143 b = env.subst('$MSVC_BATCH') |
| 144 if b in (None, '', '0'): |
| 145 # We're not using batching; return no key. |
| 146 return None |
| 147 t = target[0] |
| 148 s = source[0] |
| 149 if os.path.splitext(t.name)[0] != os.path.splitext(s.name)[0]: |
| 150 # The base names are different, so this *must* be compiled |
| 151 # separately; return no key. |
| 152 return None |
| 153 return (id(action), id(env), t.dir, s.dir) |
| 154 |
| 155 def msvc_output_flag(target, source, env, for_signature): |
| 156 """ |
| 157 Returns the correct /Fo flag for batching. |
| 158 |
| 159 If batching is disabled or there's only one source file, then we |
| 160 return an /Fo string that specifies the target explicitly. Otherwise, |
| 161 we return an /Fo string that just specifies the first target's |
| 162 directory (where the Visual C/C++ compiler will put the .obj files). |
| 163 """ |
| 164 b = env.subst('$MSVC_BATCH') |
| 165 if b in (None, '', '0') or len(source) == 1: |
| 166 return '/Fo$TARGET' |
| 167 else: |
| 168 # The Visual C/C++ compiler requires a \ at the end of the /Fo |
| 169 # option to indicate an output directory. We use os.sep here so |
| 170 # that the test(s) for this can be run on non-Windows systems |
| 171 # without having a hard-coded backslash mess up command-line |
| 172 # argument parsing. |
| 173 return '/Fo${TARGET.dir}' + os.sep |
| 174 |
| 175 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR", |
| 176 batch_key=msvc_batch_key, |
| 177 targets='$CHANGED_TARGETS') |
| 178 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR", |
| 179 batch_key=msvc_batch_key, |
| 180 targets='$CHANGED_TARGETS') |
| 181 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR", |
| 182 batch_key=msvc_batch_key, |
| 183 targets='$CHANGED_TARGETS') |
| 184 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR", |
| 185 batch_key=msvc_batch_key, |
| 186 targets='$CHANGED_TARGETS') |
| 187 |
| 188 def generate(env): |
| 189 """Add Builders and construction variables for MSVC++ to an Environment.""" |
| 190 static_obj, shared_obj = SCons.Tool.createObjBuilders(env) |
| 191 |
| 192 # TODO(batch): shouldn't reach in to cmdgen this way; necessary |
| 193 # for now to bypass the checks in Builder.DictCmdGenerator.__call__() |
| 194 # and allow .cc and .cpp to be compiled in the same command line. |
| 195 static_obj.cmdgen.source_ext_match = False |
| 196 shared_obj.cmdgen.source_ext_match = False |
| 197 |
| 198 for suffix in CSuffixes: |
| 199 static_obj.add_action(suffix, CAction) |
| 200 shared_obj.add_action(suffix, ShCAction) |
| 201 static_obj.add_emitter(suffix, static_object_emitter) |
| 202 shared_obj.add_emitter(suffix, shared_object_emitter) |
| 203 |
| 204 for suffix in CXXSuffixes: |
| 205 static_obj.add_action(suffix, CXXAction) |
| 206 shared_obj.add_action(suffix, ShCXXAction) |
| 207 static_obj.add_emitter(suffix, static_object_emitter) |
| 208 shared_obj.add_emitter(suffix, shared_object_emitter) |
| 209 |
| 210 env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Z7") or ""}']) |
| 211 env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or
"",File(PCH))) or ""}']) |
| 212 env['_MSVC_OUTPUT_FLAG'] = msvc_output_flag |
| 213 env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPD
BFLAGS' |
| 214 env['CC'] = 'cl' |
| 215 env['CCFLAGS'] = SCons.Util.CLVar('/nologo') |
| 216 env['CFLAGS'] = SCons.Util.CLVar('') |
| 217 env['CCCOM'] = '$CC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CFLAGS $CCF
LAGS $_CCCOMCOM' |
| 218 env['SHCC'] = '$CC' |
| 219 env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') |
| 220 env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS') |
| 221 env['SHCCCOM'] = '$SHCC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCFLAGS
$SHCCFLAGS $_CCCOMCOM' |
| 222 env['CXX'] = '$CC' |
| 223 env['CXXFLAGS'] = SCons.Util.CLVar('$( /TP $)') |
| 224 env['CXXCOM'] = '$CXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CXXFLAGS $
CCFLAGS $_CCCOMCOM' |
| 225 env['SHCXX'] = '$CXX' |
| 226 env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') |
| 227 env['SHCXXCOM'] = '$SHCXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCXXFLA
GS $SHCCFLAGS $_CCCOMCOM' |
| 228 env['CPPDEFPREFIX'] = '/D' |
| 229 env['CPPDEFSUFFIX'] = '' |
| 230 env['INCPREFIX'] = '/I' |
| 231 env['INCSUFFIX'] = '' |
| 232 # env.Append(OBJEMITTER = [static_object_emitter]) |
| 233 # env.Append(SHOBJEMITTER = [shared_object_emitter]) |
| 234 env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 |
| 235 |
| 236 env['RC'] = 'rc' |
| 237 env['RCFLAGS'] = SCons.Util.CLVar('') |
| 238 env['RCSUFFIXES']=['.rc','.rc2'] |
| 239 env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES
' |
| 240 env['BUILDERS']['RES'] = res_builder |
| 241 env['OBJPREFIX'] = '' |
| 242 env['OBJSUFFIX'] = '.obj' |
| 243 env['SHOBJPREFIX'] = '$OBJPREFIX' |
| 244 env['SHOBJSUFFIX'] = '$OBJSUFFIX' |
| 245 |
| 246 # Set-up ms tools paths |
| 247 msvc_setup_env_once(env) |
| 248 |
| 249 env['CFILESUFFIX'] = '.c' |
| 250 env['CXXFILESUFFIX'] = '.cc' |
| 251 |
| 252 env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}']) |
| 253 env['PCHCOM'] = '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEF
FLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDB
FLAGS' |
| 254 env['BUILDERS']['PCH'] = pch_builder |
| 255 |
| 256 if 'ENV' not in env: |
| 257 env['ENV'] = {} |
| 258 if 'SystemRoot' not in env['ENV']: # required for dlls in the winsxs fold
ers |
| 259 env['ENV']['SystemRoot'] = SCons.Platform.win32.get_system_root() |
| 260 |
| 261 def exists(env): |
| 262 return msvc_exists() |
| 263 |
| 264 # Local Variables: |
| 265 # tab-width:4 |
| 266 # indent-tabs-mode:nil |
| 267 # End: |
| 268 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |