3 Tool-specific initialization for Microsoft Visual C/C++ Toolkit Commandline
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) 2004 John Connors
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.
43 import SCons
.Platform
.win32
48 CSuffixes
= ['.c', '.C']
49 CXXSuffixes
= ['.cc', '.cpp', '.cxx', '.c++', '.C++']
51 def get_msvctoolkit_paths():
52 """Return a 4-tuple of (INCLUDE, LIB, PATH, TOOLKIT) as the values of those
53 three environment variables that should be set in order to execute
54 the MSVC .NET tools properly, if the information wasn't available
63 # First, we get the shell folder for this user:
64 if not SCons
.Util
.can_read_reg
:
65 raise SCons
.Errors
.InternalError
, "No Windows registry module was found"
68 if os
.environ
.has_key('VCToolkitInstallDir'):
69 MSToolkitDir
= os
.path
.normpath(os
.environ
['VCToolkitInstallDir'])
71 # last resort -- default install location
72 MSToolkitDir
= r
'C:\Program Files\Microsoft Visual C++ Toolkit 2003'
74 # look for platform sdk
75 if os
.environ
.has_key('MSSdk'):
76 PlatformSDKDir
= os
.path
.normpath(os
.environ
['MSSdk'])
79 PlatformSDKDir
= SCons
.Util
.RegGetValue(SCons
.Util
.HKEY_LOCAL_MACHINE
, r
'SOFTWARE\Microsoft\MicrosoftSDK\Directories\Install Dir')[0]
80 PlatformSDKDir
= str(PlatformSDKDir
)
81 except SCons
.Util
.RegError
:
82 raise SCons
.Errors
.InternalError
, "The Platform SDK directory was not found in the registry or in the `MSSdk` environment variable."
84 # look for DX Sdk (expecting DX9)
85 # dxsdk docs have a directory key, look for it, extract path
89 # dxsdkdocs = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\DirectX SDK\DX9SDK Doc Path')
90 #except SCons.Util.RegError:
91 # raise SCons.Errors.InternalError, "The DXSDK directory was not found in the registry."
92 if os
.environ
.has_key('DXSDK_DIR'):
93 DXsdkDir
= os
.path
.normpath(os
.environ
['DXSDK_DIR'])
95 #DXsdkDir = os.path.split(dxsdkdocs[0])[0]
96 DXsdkDir
= os
.path
.split(DXsdkDir
)[0]
98 include_path
= r
'%s\include;%s\include;%s\include' % (MSToolkitDir
, PlatformSDKDir
, DXsdkDir
)
99 lib_path
= r
'%s\lib;%s\lib;%s\lib' % (MSToolkitDir
, PlatformSDKDir
, DXsdkDir
)
100 exe_path
= r
'%s\bin;%s\bin\win95;%s\bin' % (MSToolkitDir
, PlatformSDKDir
, PlatformSDKDir
)
101 return (include_path
, lib_path
, exe_path
, PlatformSDKDir
)
103 def validate_vars(env
):
104 """Validate the PDB, PCH, and PCHSTOP construction variables."""
105 if env
.has_key('PCH') and env
['PCH']:
106 if not env
.has_key('PCHSTOP'):
107 raise SCons
.Errors
.UserError
, "The PCHSTOP construction must be defined if PCH is defined."
108 if not SCons
.Util
.is_String(env
['PCHSTOP']):
109 raise SCons
.Errors
.UserError
, "The PCHSTOP construction variable must be a string: %r"%env
['PCHSTOP']
111 def pch_emitter(target
, source
, env
):
112 """Sets up the PDB dependencies for a pch file, and adds the object
121 if SCons
.Util
.splitext(str(t
))[1] == '.pch':
123 if SCons
.Util
.splitext(str(t
))[1] == '.obj':
127 obj
= SCons
.Util
.splitext(str(pch
))[0]+'.obj'
129 target
= [pch
, obj
] # pch must be first, and obj second for the PCHCOM to work
131 if env
.has_key('PDB') and env
['PDB']:
132 env
.SideEffect(env
['PDB'], target
)
133 env
.Precious(env
['PDB'])
135 return (target
, source
)
137 def object_emitter(target
, source
, env
, parent_emitter
):
138 """Sets up the PDB and PCH dependencies for an object file."""
142 parent_emitter(target
, source
, env
)
144 if env
.has_key('PDB') and env
['PDB']:
145 env
.SideEffect(env
['PDB'], target
)
146 env
.Precious(env
['PDB'])
148 if env
.has_key('PCH') and env
['PCH']:
149 env
.Depends(target
, env
['PCH'])
151 return (target
, source
)
153 def static_object_emitter(target
, source
, env
):
154 return object_emitter(target
, source
, env
,
155 SCons
.Defaults
.StaticObjectEmitter
)
157 def shared_object_emitter(target
, source
, env
):
158 return object_emitter(target
, source
, env
,
159 SCons
.Defaults
.SharedObjectEmitter
)
161 pch_builder
= SCons
.Builder
.Builder(action
='$PCHCOM', suffix
='.pch', emitter
=pch_emitter
)
162 res_builder
= SCons
.Builder
.Builder(action
='$RCCOM', suffix
='.res')
164 def pdbGenerator(env
, target
, source
, for_signature
):
165 if target
and env
.has_key('PDB') and env
['PDB']:
166 return ['/PDB:%s'%target
[0].File(env
['PDB']).get_string(for_signature
),
169 def win32ShlinkTargets(target
, source
, env
, for_signature
):
171 dll
= env
.FindIxes(target
, 'SHLIBPREFIX', 'SHLIBSUFFIX')
172 if dll
: listCmd
.append("/out:%s"%dll
.get_string(for_signature
))
174 implib
= env
.FindIxes(target
, 'LIBPREFIX', 'LIBSUFFIX')
175 if implib
: listCmd
.append("/implib:%s"%implib
.get_string(for_signature
))
179 def win32ShlinkSources(target
, source
, env
, for_signature
):
182 deffile
= env
.FindIxes(source
, "WIN32DEFPREFIX", "WIN32DEFSUFFIX")
185 # Treat this source as a .def file.
186 listCmd
.append("/def:%s" % src
.get_string(for_signature
))
188 # Just treat it as a generic source file.
192 def win32LibEmitter(target
, source
, env
):
193 # SCons.Tool.msvc.validate_vars(env)
195 dll
= env
.FindIxes(target
, "SHLIBPREFIX", "SHLIBSUFFIX")
196 no_import_lib
= env
.get('no_import_lib', 0)
199 raise SCons
.Errors
.UserError
, "A shared library should have exactly one target with the suffix: %s" % env
.subst("$SHLIBSUFFIX")
201 if env
.get("WIN32_INSERT_DEF", 0) and \
202 not env
.FindIxes(source
, "WIN32DEFPREFIX", "WIN32DEFSUFFIX"):
204 # append a def file to the list of sources
205 source
.append(env
.ReplaceIxes(dll
,
206 "SHLIBPREFIX", "SHLIBSUFFIX",
207 "WIN32DEFPREFIX", "WIN32DEFSUFFIX"))
209 if env
.has_key('PDB') and env
['PDB']:
210 env
.SideEffect(env
['PDB'], target
)
211 env
.Precious(env
['PDB'])
213 if not no_import_lib
and \
214 not env
.FindIxes(target
, "LIBPREFIX", "LIBSUFFIX"):
215 # Append an import library to the list of targets.
216 target
.append(env
.ReplaceIxes(dll
,
217 "SHLIBPREFIX", "SHLIBSUFFIX",
218 "LIBPREFIX", "LIBSUFFIX"))
219 # and .exp file is created if there are exports from a DLL
220 target
.append(env
.ReplaceIxes(dll
,
221 "SHLIBPREFIX", "SHLIBSUFFIX",
222 "WIN32EXPPREFIX", "WIN32EXPSUFFIX"))
224 return (target
, source
)
226 def prog_emitter(target
, source
, env
):
227 #SCons.Tool.msvc.validate_vars(env)
229 if env
.has_key('PDB') and env
['PDB']:
230 env
.SideEffect(env
['PDB'], target
)
231 env
.Precious(env
['PDB'])
233 return (target
,source
)
235 def RegServerFunc(target
, source
, env
):
236 if env
.has_key('register') and env
['register']:
237 ret
= regServerAction([target
[0]], [source
[0]], env
)
239 raise SCons
.Errors
.UserError
, "Unable to register %s" % target
[0]
241 print "Registered %s sucessfully" % target
[0]
245 regServerAction
= SCons
.Action
.Action("$REGSVRCOM")
246 regServerCheck
= SCons
.Action
.Action(RegServerFunc
, None)
247 shlibLinkAction
= SCons
.Action
.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $_SHLINK_SOURCES")}')
248 compositeLinkAction
= shlibLinkAction
+ regServerCheck
251 """Add Builders and construction variables for MSVC++ to an Environment."""
252 static_obj
, shared_obj
= SCons
.Tool
.createObjBuilders(env
)
254 for suffix
in CSuffixes
:
255 static_obj
.add_action(suffix
, SCons
.Defaults
.CAction
)
256 shared_obj
.add_action(suffix
, SCons
.Defaults
.ShCAction
)
258 for suffix
in CXXSuffixes
:
259 static_obj
.add_action(suffix
, SCons
.Defaults
.CXXAction
)
260 shared_obj
.add_action(suffix
, SCons
.Defaults
.ShCXXAction
)
262 SCons
.Tool
.createStaticLibBuilder(env
)
263 SCons
.Tool
.createSharedLibBuilder(env
)
264 SCons
.Tool
.createProgBuilder(env
)
266 env
['CCPDBFLAGS'] = SCons
.Util
.CLVar(['${(PDB and "/Zi /Fd%s"%File(PDB)) or ""}'])
267 env
['CCPCHFLAGS'] = SCons
.Util
.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'])
268 env
['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
270 env
['CCFLAGS'] = SCons
.Util
.CLVar('/nologo')
271 env
['CCCOM'] = '$CC $CCFLAGS $CCCOMFLAGS'
273 env
['SHCCFLAGS'] = SCons
.Util
.CLVar('$CCFLAGS')
274 env
['SHCCCOM'] = '$SHCC $SHCCFLAGS $CCCOMFLAGS'
276 env
['CXXFLAGS'] = SCons
.Util
.CLVar('$CCFLAGS $( /TP $)')
277 env
['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS'
278 env
['SHCXX'] = '$CXX'
279 env
['SHCXXFLAGS'] = SCons
.Util
.CLVar('$CXXFLAGS')
280 env
['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS'
281 env
['CPPDEFPREFIX'] = '/D'
282 env
['CPPDEFSUFFIX'] = ''
283 env
['INCPREFIX'] = '/I'
284 env
['INCSUFFIX'] = ''
285 env
['OBJEMITTER'] = static_object_emitter
286 env
['SHOBJEMITTER'] = shared_object_emitter
287 env
['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
290 env
['RCFLAGS'] = SCons
.Util
.CLVar('')
291 env
['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
292 CScan
= env
.get_scanner('.c')
294 CScan
.add_skey('.rc')
295 env
['BUILDERS']['RES'] = res_builder
297 include_path
, lib_path
, exe_path
, sdk_path
= get_msvctoolkit_paths()
298 env
.PrependENVPath('INCLUDE', include_path
)
299 env
.PrependENVPath('LIB', lib_path
)
300 env
.PrependENVPath('PATH', exe_path
)
302 env
['ENV']['CPU'] = 'i386'
303 env
['ENV']['MSSDK'] = sdk_path
304 env
['ENV']['BkOffice'] = sdk_path
305 env
['ENV']['Basemake'] = sdk_path
+ "\\Include\\BKOffice.Mak"
306 env
['ENV']['INETSDK'] = sdk_path
307 env
['ENV']['MSSDK'] = sdk_path
308 env
['ENV']['MSTOOLS'] = sdk_path
309 env
['ENV']['TARGETOS'] = 'WINNT'
310 env
['ENV']['APPVER'] = '5.0'
312 env
['CFILESUFFIX'] = '.c'
313 env
['CXXFILESUFFIX'] = '.cc'
315 env
['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS'
316 env
['BUILDERS']['PCH'] = pch_builder
318 env
['AR'] = 'lib.exe' #'"' +sdk_path + '\\bin\\Win64\\lib.exe"'
319 env
['ARFLAGS'] = SCons
.Util
.CLVar('/nologo')
320 env
['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}"
322 env
['SHLINK'] = '$LINK'
323 env
['SHLINKFLAGS'] = SCons
.Util
.CLVar('$LINKFLAGS /dll')
324 env
['_SHLINK_TARGETS'] = win32ShlinkTargets
325 env
['_SHLINK_SOURCES'] = win32ShlinkSources
326 env
['SHLINKCOM'] = compositeLinkAction
327 env
['SHLIBEMITTER']= win32LibEmitter
328 env
['LINK'] = 'link.exe' #'"' +sdk_path + '\\bin\\Win64\\' + 'link.exe"'
329 env
['LINKFLAGS'] = SCons
.Util
.CLVar('/nologo')
330 env
['_PDB'] = pdbGenerator
331 env
["TEMPFILE"] = SCons
.Platform
.win32
.TempFileMunge
332 env
['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $SOURCES")}'
333 env
['PROGEMITTER'] = prog_emitter
334 env
['LIBDIRPREFIX']='/LIBPATH:'
335 env
['LIBDIRSUFFIX']=''
336 env
['LIBLINKPREFIX']=''
337 env
['LIBLINKSUFFIX']='$LIBSUFFIX'
339 env
['WIN32DEFPREFIX'] = ''
340 env
['WIN32DEFSUFFIX'] = '.def'
341 env
['WIN32_INSERT_DEF'] = 0
343 env
['WIN32EXPPREFIX'] = ''
344 env
['WIN32EXPSUFFIX'] = '.exp'
346 env
['REGSVRACTION'] = regServerCheck
347 env
['REGSVR'] = os
.path
.join(SCons
.Platform
.win32
.get_system_root(),'System32','regsvr32')
348 env
['REGSVRFLAGS'] = '/s '
349 env
['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS $TARGET'
353 return env
.Detect('cl')