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()
12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The SCons Foundation
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__
= "src/engine/SCons/Tool/msvc.py 2523 2007/12/12 09:37:41 knight"
43 import SCons
.Platform
.win32
45 import SCons
.Tool
.mslib
46 import SCons
.Tool
.mslink
50 CSuffixes
= ['.c', '.C']
51 CXXSuffixes
= ['.cc', '.cpp', '.cxx', '.c++', '.C++']
53 def get_winddk_paths(env
, version
=None):
54 """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values
55 of those three environment variables that should be set
56 in order to execute the MSVC tools properly."""
63 if 'BASEDIR' in os
.environ
:
64 WINDDKdir
= os
.environ
['BASEDIR']
66 WINDDKdir
= "C:\\WINDDK\\3790.1830"
68 exe_paths
.append( os
.path
.join(WINDDKdir
, 'bin') )
69 exe_paths
.append( os
.path
.join(WINDDKdir
, 'bin\\x86') )
70 include_paths
.append( os
.path
.join(WINDDKdir
, 'inc\\wxp') )
71 lib_paths
.append( os
.path
.join(WINDDKdir
, 'lib') )
73 include_path
= string
.join( include_paths
, os
.pathsep
)
74 lib_path
= string
.join(lib_paths
, os
.pathsep
)
75 exe_path
= string
.join(exe_paths
, os
.pathsep
)
76 return (include_path
, lib_path
, exe_path
)
78 def validate_vars(env
):
79 """Validate the PCH and PCHSTOP construction variables."""
80 if env
.has_key('PCH') and env
['PCH']:
81 if not env
.has_key('PCHSTOP'):
82 raise SCons
.Errors
.UserError
, "The PCHSTOP construction must be defined if PCH is defined."
83 if not SCons
.Util
.is_String(env
['PCHSTOP']):
84 raise SCons
.Errors
.UserError
, "The PCHSTOP construction variable must be a string: %r"%env
['PCHSTOP']
86 def pch_emitter(target
, source
, env
):
87 """Adds the object file target."""
95 if SCons
.Util
.splitext(str(t
))[1] == '.pch':
97 if SCons
.Util
.splitext(str(t
))[1] == '.obj':
101 obj
= SCons
.Util
.splitext(str(pch
))[0]+'.obj'
103 target
= [pch
, obj
] # pch must be first, and obj second for the PCHCOM to work
105 return (target
, source
)
107 def object_emitter(target
, source
, env
, parent_emitter
):
108 """Sets up the PCH dependencies for an object file."""
112 parent_emitter(target
, source
, env
)
114 if env
.has_key('PCH') and env
['PCH']:
115 env
.Depends(target
, env
['PCH'])
117 return (target
, source
)
119 def static_object_emitter(target
, source
, env
):
120 return object_emitter(target
, source
, env
,
121 SCons
.Defaults
.StaticObjectEmitter
)
123 def shared_object_emitter(target
, source
, env
):
124 return object_emitter(target
, source
, env
,
125 SCons
.Defaults
.SharedObjectEmitter
)
127 pch_action
= SCons
.Action
.Action('$PCHCOM', '$PCHCOMSTR')
128 pch_builder
= SCons
.Builder
.Builder(action
=pch_action
, suffix
='.pch',
130 source_scanner
=SCons
.Tool
.SourceFileScanner
)
131 res_action
= SCons
.Action
.Action('$RCCOM', '$RCCOMSTR')
132 res_builder
= SCons
.Builder
.Builder(action
=res_action
,
136 source_scanner
=SCons
.Tool
.SourceFileScanner
)
137 SCons
.Tool
.SourceFileScanner
.add_scanner('.rc', SCons
.Defaults
.CScan
)
140 """Add Builders and construction variables for MSVC++ to an Environment."""
141 static_obj
, shared_obj
= SCons
.Tool
.createObjBuilders(env
)
143 for suffix
in CSuffixes
:
144 static_obj
.add_action(suffix
, SCons
.Defaults
.CAction
)
145 shared_obj
.add_action(suffix
, SCons
.Defaults
.ShCAction
)
146 static_obj
.add_emitter(suffix
, static_object_emitter
)
147 shared_obj
.add_emitter(suffix
, shared_object_emitter
)
149 for suffix
in CXXSuffixes
:
150 static_obj
.add_action(suffix
, SCons
.Defaults
.CXXAction
)
151 shared_obj
.add_action(suffix
, SCons
.Defaults
.ShCXXAction
)
152 static_obj
.add_emitter(suffix
, static_object_emitter
)
153 shared_obj
.add_emitter(suffix
, shared_object_emitter
)
155 env
['CCPDBFLAGS'] = SCons
.Util
.CLVar(['${(PDB and "/Z7") or ""}'])
156 env
['CCPCHFLAGS'] = SCons
.Util
.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'])
157 env
['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
159 env
['CCFLAGS'] = SCons
.Util
.CLVar('/nologo')
160 env
['CFLAGS'] = SCons
.Util
.CLVar('')
161 env
['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CCCOMFLAGS'
163 env
['SHCCFLAGS'] = SCons
.Util
.CLVar('$CCFLAGS')
164 env
['SHCFLAGS'] = SCons
.Util
.CLVar('$CFLAGS')
165 env
['SHCCCOM'] = '$SHCC $SHCFLAGS $SHCCFLAGS $CCCOMFLAGS'
167 env
['CXXFLAGS'] = SCons
.Util
.CLVar('$CCFLAGS $( /TP $)')
168 env
['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS'
169 env
['SHCXX'] = '$CXX'
170 env
['SHCXXFLAGS'] = SCons
.Util
.CLVar('$CXXFLAGS')
171 env
['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS'
172 env
['CPPDEFPREFIX'] = '/D'
173 env
['CPPDEFSUFFIX'] = ''
174 env
['INCPREFIX'] = '/I'
175 env
['INCSUFFIX'] = ''
176 # env.Append(OBJEMITTER = [static_object_emitter])
177 # env.Append(SHOBJEMITTER = [shared_object_emitter])
178 env
['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
181 env
['RCFLAGS'] = SCons
.Util
.CLVar('')
182 env
['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
183 env
['BUILDERS']['RES'] = res_builder
184 env
['OBJPREFIX'] = ''
185 env
['OBJSUFFIX'] = '.obj'
186 env
['SHOBJPREFIX'] = '$OBJPREFIX'
187 env
['SHOBJSUFFIX'] = '$OBJSUFFIX'
190 include_path
, lib_path
, exe_path
= get_winddk_paths(env
)
192 # since other tools can set these, we just make sure that the
193 # relevant stuff from MSVS is in there somewhere.
194 env
.PrependENVPath('INCLUDE', include_path
)
195 env
.PrependENVPath('LIB', lib_path
)
196 env
.PrependENVPath('PATH', exe_path
)
197 except (SCons
.Util
.RegError
, SCons
.Errors
.InternalError
):
200 env
['CFILESUFFIX'] = '.c'
201 env
['CXXFILESUFFIX'] = '.cc'
203 env
['PCHPDBFLAGS'] = SCons
.Util
.CLVar(['${(PDB and "/Yd") or ""}'])
204 env
['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS'
205 env
['BUILDERS']['PCH'] = pch_builder
208 env
['ARFLAGS'] = SCons
.Util
.CLVar('/nologo')
209 env
['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}"
210 env
['LIBPREFIX'] = ''
211 env
['LIBSUFFIX'] = '.lib'
213 SCons
.Tool
.mslink
.generate(env
)
216 # - WINDDK's bin/makefile.new for more info.
217 # - http://alter.org.ua/docs/nt_kernel/vc8_proj/
218 env
.Append(CPPDEFINES
= [
224 ('CONDITION_HANDLING', '1'),
228 ('_WIN32_WINNT', '0x0500'), # minimum required OS version
229 ('WIN32_LEAN_AND_MEAN', '1'),
234 '/GF', # Enable String Pooling
235 #'/EHsc', # Enable C++ Exceptions
236 '/Zp8', # 8bytes struct member alignment
237 #'/GS-', # No Buffer Security Check
238 #'/GR-', # Disable Run-Time Type Info
239 '/Gz', # __stdcall Calling convention
241 env
.Append(CFLAGS
= cflags
)
242 env
.Append(CXXFLAGS
= cflags
)
244 env
.Append(LINKFLAGS
= [
251 #'-subsystem:native,4.00',
254 '-entry:DrvEnableDriver',
257 if not env
.has_key('ENV'):
259 if not env
['ENV'].has_key('SystemRoot'): # required for dlls in the winsxs folders
260 env
['ENV']['SystemRoot'] = SCons
.Platform
.win32
.get_system_root()
263 return env
.Detect('cl')