3 Builders and other things for the local site. Here's where we'll
4 duplicate the functionality of autoconf until we move it into the
5 installation procedure or use something like qmconf.
7 The code that reads the registry to find MSVC components was borrowed
8 from distutils.msvccompiler.
13 # Copyright (c) 2001, 2002 Steven Knight
15 # Permission is hereby granted, free of charge, to any person obtaining
16 # a copy of this software and associated documentation files (the
17 # "Software"), to deal in the Software without restriction, including
18 # without limitation the rights to use, copy, modify, merge, publish,
19 # distribute, sublicense, and/or sell copies of the Software, and to
20 # permit persons to whom the Software is furnished to do so, subject to
21 # the following conditions:
23 # The above copyright notice and this permission notice shall be included
24 # in all copies or substantial portions of the Software.
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
48 import SCons.Node.Alias
50 import SCons.Scanner.C
51 import SCons.Scanner.Prog
54 class SharedCmdGenerator:
55 """A callable class that acts as a command generator.
56 It is designed to hold on to 2 actions, and return
57 one if the shared=1 keyword arg is supplied to the
58 Builder method, and the other if not.
60 Also, all target nodes will have the shared attribute
61 set to match the vaue of the shared keyword argument,
63 def __init__(self, static, shared):
64 self.action_static = static
65 self.action_shared = shared
67 def __call__(self, target, source, env, shared=0):
70 if src.attributes.shared != shared:
71 raise UserError("Source file: %s must be built with shared=%s in order to be compatible with the selected target." % (src, str(shared)))
72 except AttributeError:
75 t.attributes.shared = shared
77 return self.action_shared
79 return self.action_static
81 CFile = SCons.Builder.Builder(name = 'CFile',
82 action = { '.l' : '$LEXCOM',
85 suffix = '$CFILESUFFIX')
87 CXXFile = SCons.Builder.Builder(name = 'CXXFile',
88 action = { '.ll' : '$LEXCOM',
91 suffix = '$CXXFILESUFFIX')
93 CXXAction = SCons.Action.Action("$CXXCOM")
94 ShCXXAction = SCons.Action.Action("$SHCXXCOM")
95 F77Action = SCons.Action.Action("$F77COM")
96 ShF77Action = SCons.Action.Action("$SHF77COM")
97 F77PPAction = SCons.Action.Action("$F77PPCOM")
98 ShF77PPAction = SCons.Action.Action("$SHF77PPCOM")
100 shared_obj = SCons.Builder.DictCmdGenerator({ ".C" : ShCXXAction,
102 ".cpp" : ShCXXAction,
103 ".cxx" : ShCXXAction,
104 ".c++" : ShCXXAction,
105 ".C++" : ShCXXAction,
108 ".for" : ShF77Action,
109 ".FOR" : ShF77Action,
110 ".F" : ShF77PPAction,
111 ".fpp" : ShF77PPAction,
112 ".FPP" : ShF77PPAction })
114 static_obj = SCons.Builder.DictCmdGenerator({ ".C" : CXXAction,
125 ".fpp" : F77PPAction,
126 ".FPP" : F77PPAction })
128 Object = SCons.Builder.Builder(name = 'Object',
130 SharedCmdGenerator(static=SCons.Action.CommandGeneratorAction(static_obj),
131 shared=SCons.Action.CommandGeneratorAction(shared_obj)),
132 prefix = '$OBJPREFIX',
133 suffix = '$OBJSUFFIX',
134 src_suffix = static_obj.src_suffixes(),
135 src_builder = [CFile, CXXFile])
137 def win32LinkGenerator(env, target, source, **kw):
139 for a in [env['LINKFLAGS'],
140 '/OUT:' + str(target[0]),
143 map(lambda x: str(x), source)]:
144 if SCons.Util.is_List(a):
148 argstring = string.join(args, " ")
149 if len(argstring) <= 2048:
150 return env['LINK'] + " " + argstring
153 tmp = tempfile.mktemp()
154 open(tmp, 'w').write(argstring + "\n")
155 return [ env['LINK'] + " @" + tmp,
160 'prefix' : '$PROGPREFIX',
161 'suffix' : '$PROGSUFFIX',
162 'src_suffix' : '$OBJSUFFIX',
163 'src_builder' : Object,
164 'scanner' : SCons.Scanner.Prog.ProgScan()
167 if sys.platform == 'win32':
168 kw['generator'] = win32LinkGenerator
170 kw['action'] = '$LINKCOM'
172 Program = apply(SCons.Builder.Builder, (), kw)
174 class LibAffixGenerator:
175 def __init__(self, static, shared):
176 self.static_affix = static
177 self.shared_affix = shared
179 def __call__(self, shared=0, win32=0):
181 return self.shared_affix
182 return self.static_affix
184 def win32LibGenerator(target, source, env, shared=1):
185 listCmd = [ "$SHLINK", "$SHLINKFLAGS" ]
188 ext = os.path.splitext(str(tgt))[1]
189 if ext == env.subst("$LIBSUFFIX"):
190 # Put it on the command line as an import library.
191 listCmd.append("${WIN32IMPLIBPREFIX}%s" % tgt)
193 listCmd.append("${WIN32DLLPREFIX}%s" % tgt)
195 listCmd.extend([ '$_LIBDIRFLAGS', '$_LIBFLAGS' ])
197 ext = os.path.splitext(str(src))[1]
198 if ext == env.subst("$WIN32DEFSUFFIX"):
199 # Treat this source as a .def file.
200 listCmd.append("${WIN32DEFPREFIX}%s" % src)
202 # Just treat it as a generic source file.
203 listCmd.append(str(src))
206 def win32LibEmitter(target, source, env, shared=0):
210 ext = os.path.splitext(str(tgt))[1]
211 if ext == env.subst("$SHLIBSUFFIX"):
215 raise UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX"))
217 if env.has_key("WIN32_INSERT_DEF") and \
218 env["WIN32_INSERT_DEF"] and \
219 not '.def' in map(lambda x: os.path.split(str(x))[1],
222 # append a def file to the list of sources
223 source.append("%s%s" % (os.path.splitext(str(dll))[0],
224 env.subst("$WIN32DEFSUFFIX")))
225 if not env.subst("$LIBSUFFIX") in \
226 map(lambda x: os.path.split(str(x))[1], target):
227 # Append an import library to the list of targets.
228 target.append("%s%s%s" % (env.subst("$LIBPREFIX"),
229 os.path.splitext(str(dll))[0],
230 env.subst("$LIBSUFFIX")))
231 return (target, source)
233 PosixLibrary = SCons.Builder.Builder(name = 'Library',
235 SharedCmdGenerator(shared="$SHLINKCOM",
238 LibAffixGenerator(static='$LIBPREFIX',
239 shared='$SHLIBPREFIX'),
241 LibAffixGenerator(static='$LIBSUFFIX',
242 shared='$SHLIBSUFFIX'),
243 src_suffix = '$OBJSUFFIX',
244 src_builder = Object)
246 Win32Library = SCons.Builder.Builder(name = 'Library',
248 SharedCmdGenerator(shared=SCons.Action.CommandGeneratorAction(win32LibGenerator),
250 emitter = win32LibEmitter,
252 LibAffixGenerator(static='$LIBPREFIX',
253 shared='$SHLIBPREFIX'),
255 LibAffixGenerator(static='$LIBSUFFIX',
256 shared='$SHLIBSUFFIX'),
257 src_suffix = '$OBJSUFFIX',
258 src_builder = Object)
260 LaTeXAction = SCons.Action.Action('$LATEXCOM')
262 DVI = SCons.Builder.Builder(name = 'DVI',
263 action = { '.tex' : '$TEXCOM',
264 '.ltx' : LaTeXAction,
265 '.latex' : LaTeXAction,
267 # The suffix is not configurable via a
268 # construction variable like $DVISUFFIX
269 # because the output file name is
270 # hard-coded within TeX.
273 PDF = SCons.Builder.Builder(name = 'PDF',
275 prefix = '$PDFPREFIX',
276 suffix = '$PDFSUFFIX',
280 PostScript = SCons.Builder.Builder(name = 'PostScript',
282 prefix = '$PSPREFIX',
283 suffix = '$PSSUFFIX',
287 CScan = SCons.Scanner.C.CScan()
289 def alias_builder(env, target, source):
292 Alias = SCons.Builder.Builder(name = 'Alias',
293 action = alias_builder,
294 target_factory = SCons.Node.Alias.default_ans.Alias,
295 source_factory = SCons.Node.FS.default_fs.Entry)
297 def get_devstudio_versions ():
299 Get list of devstudio versions from the Windows registry. Return a
300 list of strings containing version numbers; an exception will be raised
301 if we were unable to access the registry (eg. couldn't import
302 a registry-access module) or the appropriate registry keys weren't
306 if not SCons.Util.can_read_reg:
307 raise SCons.Errors.InternalError, "No Windows registry module was found"
309 K = 'Software\\Microsoft\\Devstudio'
311 for base in (SCons.Util.HKEY_CLASSES_ROOT,
312 SCons.Util.HKEY_LOCAL_MACHINE,
313 SCons.Util.HKEY_CURRENT_USER,
314 SCons.Util.HKEY_USERS):
316 k = SCons.Util.RegOpenKeyEx(base,K)
320 p = SCons.Util.RegEnumKey(k,i)
321 if p[0] in '123456789' and p not in L:
323 except SCons.Util.RegError:
326 except SCons.Util.RegError:
330 raise SCons.Errors.InternalError, "DevStudio was not found."
336 def get_msvc_path (path, version, platform='x86'):
338 Get a list of devstudio directories (include, lib or path). Return
339 a string delimited by ';'. An exception will be raised if unable to
340 access the registry or appropriate registry keys not found.
343 if not SCons.Util.can_read_reg:
344 raise SCons.Errors.InternalError, "No Windows registry module was found"
348 path = string.upper(path + ' Dirs')
349 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
350 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
352 for base in (SCons.Util.HKEY_CLASSES_ROOT,
353 SCons.Util.HKEY_LOCAL_MACHINE,
354 SCons.Util.HKEY_CURRENT_USER,
355 SCons.Util.HKEY_USERS):
357 k = SCons.Util.RegOpenKeyEx(base,K)
361 (p,v,t) = SCons.Util.RegEnumValue(k,i)
362 if string.upper(p) == path:
365 except SCons.Util.RegError:
367 except SCons.Util.RegError:
370 # if we got here, then we didn't find the registry entries:
371 raise SCons.Errors.InternalError, "%s was not found in the registry."%path
373 def get_msdev_dir(version):
374 """Returns the root directory of the MSDev installation from the
375 registry if it can be found, otherwise we guess."""
376 if SCons.Util.can_read_reg:
377 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
378 'Products\\Microsoft Visual C++') % \
380 for base in (SCons.Util.HKEY_LOCAL_MACHINE,
381 SCons.Util.HKEY_CURRENT_USER):
383 k = SCons.Util.RegOpenKeyEx(base,K)
384 val, tok = SCons.Util.RegQueryValueEx(k, 'ProductDir')
385 return os.path.split(val)[0]
386 except SCons.Util.RegError:
389 def make_win32_env_from_paths(include, lib, path):
391 Build a dictionary of construction variables for a win32 platform.
392 include - include path
394 path - executable path
398 'CCFLAGS' : '/nologo',
399 'CCCOM' : '$CC $CCFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
401 'SHCCFLAGS' : '$CCFLAGS',
402 'SHCCCOM' : '$SHCC $SHCCFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
403 'CFILESUFFIX' : '.c',
405 'CXXFLAGS' : '$CCFLAGS',
406 'CXXCOM' : '$CXX $CXXFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
408 'SHCXXFLAGS' : '$CXXFLAGS',
409 'SHCXXCOM' : '$SHCXX $SHCXXFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
410 'CXXFILESUFFIX' : '.cc',
413 'F77COM' : '$F77 $F77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
414 'F77PPCOM' : '$F77 $F77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
416 'SHF77FLAGS' : '$F77FLAGS',
417 'SHF77COM' : '$SHF77 $SHF77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
418 'SHF77PPCOM' : '$SHF77 $SHF77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
420 'LINKFLAGS' : '/nologo',
421 # XXX - We'd like to do this as follows, but '$LINKCOM' in
422 # a Builder above gets expanded too soon to stick a function
423 # right in the environment like this. Revisit this when this
424 # capability has been added (cf. bug report #537058).
425 #'LINKCOM' : win32Link,
427 'SHLINKFLAGS': '$LINKFLAGS /dll',
428 'SHLINKCOM' : '$SHLINK $SHLINKFLAGS /OUT:$TARGET $_LIBDIRFLAGS $_LIBFLAGS $SOURCES',
430 'ARFLAGS' : '/nologo',
431 'ARCOM' : '$AR $ARFLAGS /OUT:$TARGET $SOURCES',
433 'SHLIBSUFFIX': '.dll',
436 'LEXCOM' : '$LEX $LEXFLAGS -t $SOURCES > $TARGET',
439 'YACCCOM' : '$YACC $YACCFLAGS -o $TARGET $SOURCES',
442 'TEXCOM' : '$TEX $TEXFLAGS $SOURCES',
445 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES',
448 'PDFCOM' : '$DVIPDF $DVIPDFFLAGS $SOURCES $TARGET',
450 'PDFSUFFIX' : '.pdf',
453 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES',
456 'BUILDERS' : [Alias, CFile, CXXFile, DVI, Win32Library, Object,
457 PDF, PostScript, Program],
458 'SCANNERS' : [CScan],
460 'OBJSUFFIX' : '.obj',
462 'PROGSUFFIX' : '.exe',
464 'LIBPREFIXES': '$LIBPREFIX',
465 'LIBSUFFIX' : '.lib',
466 'LIBSUFFIXES': '$LIBSUFFIX',
467 'LIBDIRPREFIX' : '/LIBPATH:',
469 'LIBLINKPREFIX' : '',
470 'LIBLINKSUFFIX' : '$LIBSUFFIX',
473 'WIN32DEFPREFIX' : '/def:',
474 'WIN32DEFSUFFIX' : '.def',
475 'WIN32DLLPREFIX' : '/out:',
476 'WIN32IMPLIBPREFIX' : '/implib:',
477 'WIN32_INSERT_DEF' : 0,
482 'PATHEXT' : '.COM;.EXE;.BAT;.CMD',
486 def make_win32_env(version):
488 Build a dictionary of construction variables for a win32 platform.
489 ver - the version string of DevStudio to use (e.g. "6.0")
491 return make_win32_env_from_paths(get_msvc_path("include", version),
492 get_msvc_path("lib", version),
493 get_msvc_path("path", version)
494 + ";" + os.environ['PATH'])
497 if os.name == 'posix':
498 Library = PosixLibrary
500 arcom = '$AR $ARFLAGS $TARGET $SOURCES'
502 if SCons.Util.WhereIs(ranlib):
503 arcom = arcom + '\n$RANLIB $RANLIBFLAGS $TARGET'
505 ConstructionEnvironment = {
508 'CCCOM' : '$CC $CCFLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
510 'SHCCFLAGS' : '$CCFLAGS -fPIC',
511 'SHCCCOM' : '$SHCC $SHCCFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
512 'CFILESUFFIX' : '.c',
514 'CXXFLAGS' : '$CCFLAGS',
515 'CXXCOM' : '$CXX $CXXFLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
516 'CXXFILESUFFIX' : '.cc',
518 'SHCXXFLAGS' : '$CXXFLAGS -fPIC',
519 'SHCXXCOM' : '$SHCXX $SHCXXFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
522 'F77COM' : '$F77 $F77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
523 'F77PPCOM' : '$F77 $F77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
524 'SHF77FLAGS' : '$F77FLAGS -fPIC',
525 'SHF77COM' : '$F77 $SHF77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
526 'SHF77PPCOM' : '$F77 $SHF77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
528 'SHF77FLAGS' : '$F77FLAGS -fPIC',
529 'SHF77COM' : '$SHF77 $SHF77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
530 'SHF77PPCOM' : '$SHF77 $SHF77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
533 'LINKCOM' : '$LINK $LINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS',
535 'SHLINKFLAGS': '$LINKFLAGS -shared',
536 'SHLINKCOM' : '$SHLINK $SHLINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS',
542 'SHLIBPREFIX': '$LIBPREFIX',
543 'SHLIBSUFFIX': '.so',
546 'LEXCOM' : '$LEX $LEXFLAGS -t $SOURCES > $TARGET',
549 'YACCCOM' : '$YACC $YACCFLAGS -o $TARGET $SOURCES',
552 'TEXCOM' : '$TEX $TEXFLAGS $SOURCES',
555 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES',
557 'PDFCOM' : '$DVIPDF $DVIPDFFLAGS $SOURCES $TARGET',
559 'PDFSUFFIX' : '.pdf',
561 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES',
564 'BUILDERS' : [Alias, CFile, CXXFile, DVI, PosixLibrary, Object,
565 PDF, PostScript, Program],
566 'SCANNERS' : [CScan],
570 'PROGSUFFIX' : (sys.platform == 'cygwin') and '.exe' or '',
572 'LIBPREFIXES': '$LIBPREFIX',
574 'LIBSUFFIXES': [ '$LIBSUFFIX', '$SHLIBSUFFIX' ],
575 'LIBDIRPREFIX' : '-L',
577 'LIBLINKPREFIX' : '-l',
578 'LIBLINKSUFFIX' : '',
581 'ENV' : { 'PATH' : '/usr/local/bin:/bin:/usr/bin' },
584 elif os.name == 'nt':
585 Library = Win32Library
589 versions = get_devstudio_versions()
590 ConstructionEnvironment = make_win32_env(versions[0]) #use highest version
591 except (SCons.Util.RegError, SCons.Errors.InternalError):
592 # Could not get the configured directories from the registry.
593 # However, the configured directories only appear if the user
594 # changes them from the default. Therefore, we'll see if
595 # we can get the path to the MSDev base installation from
596 # the registry and deduce the default directories.
599 MVSdir = get_msdev_dir(versions[0])
601 MVSVCdir = r'%s\VC98' % MVSdir
602 MVSCommondir = r'%s\Common' % MVSdir
604 extra_path = os.pathsep + os.environ['PATH']
607 ConstructionEnvironment = make_win32_env_from_paths(
608 r'%s\atl\include;%s\mfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir),
609 r'%s\mfc\lib;%s\lib' % (MVSVCdir, MVSVCdir),
610 (r'%s\MSDev98\Bin;%s\Bin' % (MVSCommondir, MVSVCdir)) + extra_path)
612 # The DevStudio environment variables don't exist,
613 # so just use the variables from the source environment.
614 MVSdir = r'C:\Program Files\Microsoft Visual Studio'
615 MVSVCdir = r'%s\VC98' % MVSdir
616 MVSCommondir = r'%s\Common' % MVSdir
618 include_path = os.environ['INCLUDE']
622 lib_path = os.environ['LIB']
626 exe_path = os.environ['PATH']
629 ConstructionEnvironment = make_win32_env_from_paths(