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):
138 cmd = env.subst_list([ '$LINK', '$LINKFLAGS', '/OUT:' + str(target[0]) ])[0]
139 cmd.extend(['$('] + env.subst_list('$_LIBDIRFLAGS')[0] + ['$)'])
140 cmd.extend(env.subst_list('$_LIBFLAGS')[0])
141 cmd.extend(map(lambda x: str(x), source))
142 cmdlen = reduce(lambda x, y: x + len(y), cmd, 0) + len(cmd)
147 tmp = tempfile.mktemp()
148 args = filter(lambda x: x != '$(' and x != '$)', cmd[1:])
149 args = map(SCons.Util.quote_spaces, args)
150 open(tmp, 'w').write(string.join(args, " ") + "\n")
151 return [ [cmd[0], '@' + tmp],
156 'prefix' : '$PROGPREFIX',
157 'suffix' : '$PROGSUFFIX',
158 'src_suffix' : '$OBJSUFFIX',
159 'src_builder' : Object,
160 'scanner' : SCons.Scanner.Prog.ProgScan()
163 if sys.platform == 'win32':
164 kw['generator'] = win32LinkGenerator
166 kw['action'] = '$LINKCOM'
168 Program = apply(SCons.Builder.Builder, (), kw)
170 class LibAffixGenerator:
171 def __init__(self, static, shared):
172 self.static_affix = static
173 self.shared_affix = shared
175 def __call__(self, shared=0, win32=0):
177 return self.shared_affix
178 return self.static_affix
180 def win32LibGenerator(target, source, env, shared=1):
181 listCmd = [ "$SHLINK", "$SHLINKFLAGS" ]
184 ext = os.path.splitext(str(tgt))[1]
185 if ext == env.subst("$LIBSUFFIX"):
186 # Put it on the command line as an import library.
187 listCmd.append("${WIN32IMPLIBPREFIX}%s" % tgt)
189 listCmd.append("${WIN32DLLPREFIX}%s" % tgt)
191 listCmd.extend([ '$_LIBDIRFLAGS', '$_LIBFLAGS' ])
193 ext = os.path.splitext(str(src))[1]
194 if ext == env.subst("$WIN32DEFSUFFIX"):
195 # Treat this source as a .def file.
196 listCmd.append("${WIN32DEFPREFIX}%s" % src)
198 # Just treat it as a generic source file.
199 listCmd.append(str(src))
202 def win32LibEmitter(target, source, env, shared=0):
206 ext = os.path.splitext(str(tgt))[1]
207 if ext == env.subst("$SHLIBSUFFIX"):
211 raise UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX"))
213 if env.has_key("WIN32_INSERT_DEF") and \
214 env["WIN32_INSERT_DEF"] and \
215 not '.def' in map(lambda x: os.path.split(str(x))[1],
218 # append a def file to the list of sources
219 source.append("%s%s" % (os.path.splitext(str(dll))[0],
220 env.subst("$WIN32DEFSUFFIX")))
221 if not env.subst("$LIBSUFFIX") in \
222 map(lambda x: os.path.split(str(x))[1], target):
223 # Append an import library to the list of targets.
224 target.append("%s%s%s" % (env.subst("$LIBPREFIX"),
225 os.path.splitext(str(dll))[0],
226 env.subst("$LIBSUFFIX")))
227 return (target, source)
229 PosixLibrary = SCons.Builder.Builder(name = 'Library',
231 SharedCmdGenerator(shared="$SHLINKCOM",
234 LibAffixGenerator(static='$LIBPREFIX',
235 shared='$SHLIBPREFIX'),
237 LibAffixGenerator(static='$LIBSUFFIX',
238 shared='$SHLIBSUFFIX'),
239 src_suffix = '$OBJSUFFIX',
240 src_builder = Object)
242 Win32Library = SCons.Builder.Builder(name = 'Library',
244 SharedCmdGenerator(shared=SCons.Action.CommandGeneratorAction(win32LibGenerator),
246 emitter = win32LibEmitter,
248 LibAffixGenerator(static='$LIBPREFIX',
249 shared='$SHLIBPREFIX'),
251 LibAffixGenerator(static='$LIBSUFFIX',
252 shared='$SHLIBSUFFIX'),
253 src_suffix = '$OBJSUFFIX',
254 src_builder = Object)
256 LaTeXAction = SCons.Action.Action('$LATEXCOM')
258 DVI = SCons.Builder.Builder(name = 'DVI',
259 action = { '.tex' : '$TEXCOM',
260 '.ltx' : LaTeXAction,
261 '.latex' : LaTeXAction,
263 # The suffix is not configurable via a
264 # construction variable like $DVISUFFIX
265 # because the output file name is
266 # hard-coded within TeX.
269 PDF = SCons.Builder.Builder(name = 'PDF',
271 prefix = '$PDFPREFIX',
272 suffix = '$PDFSUFFIX',
276 PostScript = SCons.Builder.Builder(name = 'PostScript',
278 prefix = '$PSPREFIX',
279 suffix = '$PSSUFFIX',
283 CScan = SCons.Scanner.C.CScan()
285 def alias_builder(env, target, source):
288 Alias = SCons.Builder.Builder(name = 'Alias',
289 action = alias_builder,
290 target_factory = SCons.Node.Alias.default_ans.Alias,
291 source_factory = SCons.Node.FS.default_fs.Entry)
293 def get_devstudio_versions ():
295 Get list of devstudio versions from the Windows registry. Return a
296 list of strings containing version numbers; an exception will be raised
297 if we were unable to access the registry (eg. couldn't import
298 a registry-access module) or the appropriate registry keys weren't
302 if not SCons.Util.can_read_reg:
303 raise SCons.Errors.InternalError, "No Windows registry module was found"
305 K = 'Software\\Microsoft\\Devstudio'
307 for base in (SCons.Util.HKEY_CLASSES_ROOT,
308 SCons.Util.HKEY_LOCAL_MACHINE,
309 SCons.Util.HKEY_CURRENT_USER,
310 SCons.Util.HKEY_USERS):
312 k = SCons.Util.RegOpenKeyEx(base,K)
316 p = SCons.Util.RegEnumKey(k,i)
317 if p[0] in '123456789' and p not in L:
319 except SCons.Util.RegError:
322 except SCons.Util.RegError:
326 raise SCons.Errors.InternalError, "DevStudio was not found."
332 def get_msvc_path (path, version, platform='x86'):
334 Get a list of devstudio directories (include, lib or path). Return
335 a string delimited by ';'. An exception will be raised if unable to
336 access the registry or appropriate registry keys not found.
339 if not SCons.Util.can_read_reg:
340 raise SCons.Errors.InternalError, "No Windows registry module was found"
344 path = string.upper(path + ' Dirs')
345 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
346 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
348 for base in (SCons.Util.HKEY_CLASSES_ROOT,
349 SCons.Util.HKEY_LOCAL_MACHINE,
350 SCons.Util.HKEY_CURRENT_USER,
351 SCons.Util.HKEY_USERS):
353 k = SCons.Util.RegOpenKeyEx(base,K)
357 (p,v,t) = SCons.Util.RegEnumValue(k,i)
358 if string.upper(p) == path:
361 except SCons.Util.RegError:
363 except SCons.Util.RegError:
366 # if we got here, then we didn't find the registry entries:
367 raise SCons.Errors.InternalError, "%s was not found in the registry."%path
369 def get_msdev_dir(version):
370 """Returns the root directory of the MSDev installation from the
371 registry if it can be found, otherwise we guess."""
372 if SCons.Util.can_read_reg:
373 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
374 'Products\\Microsoft Visual C++') % \
376 for base in (SCons.Util.HKEY_LOCAL_MACHINE,
377 SCons.Util.HKEY_CURRENT_USER):
379 k = SCons.Util.RegOpenKeyEx(base,K)
380 val, tok = SCons.Util.RegQueryValueEx(k, 'ProductDir')
381 return os.path.split(val)[0]
382 except SCons.Util.RegError:
385 def make_win32_env_from_paths(include, lib, path):
387 Build a dictionary of construction variables for a win32 platform.
388 include - include path
390 path - executable path
394 'CCFLAGS' : '/nologo',
395 'CCCOM' : '$CC $CCFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
397 'SHCCFLAGS' : '$CCFLAGS',
398 'SHCCCOM' : '$SHCC $SHCCFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
399 'CFILESUFFIX' : '.c',
401 'CXXFLAGS' : '$CCFLAGS',
402 'CXXCOM' : '$CXX $CXXFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
404 'SHCXXFLAGS' : '$CXXFLAGS',
405 'SHCXXCOM' : '$SHCXX $SHCXXFLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET',
406 'CXXFILESUFFIX' : '.cc',
409 'F77COM' : '$F77 $F77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
410 'F77PPCOM' : '$F77 $F77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
412 'SHF77FLAGS' : '$F77FLAGS',
413 'SHF77COM' : '$SHF77 $SHF77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
414 'SHF77PPCOM' : '$SHF77 $SHF77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
416 'LINKFLAGS' : '/nologo',
417 # XXX - We'd like to do this as follows, but '$LINKCOM' in
418 # a Builder above gets expanded too soon to stick a function
419 # right in the environment like this. Revisit this when this
420 # capability has been added (cf. bug report #537058).
421 #'LINKCOM' : win32Link,
423 'SHLINKFLAGS': '$LINKFLAGS /dll',
424 'SHLINKCOM' : '$SHLINK $SHLINKFLAGS /OUT:$TARGET $_LIBDIRFLAGS $_LIBFLAGS $SOURCES',
426 'ARFLAGS' : '/nologo',
427 'ARCOM' : '$AR $ARFLAGS /OUT:$TARGET $SOURCES',
429 'SHLIBSUFFIX': '.dll',
432 'LEXCOM' : '$LEX $LEXFLAGS -t $SOURCES > $TARGET',
435 'YACCCOM' : '$YACC $YACCFLAGS -o $TARGET $SOURCES',
438 'TEXCOM' : '$TEX $TEXFLAGS $SOURCES',
441 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES',
444 'PDFCOM' : '$DVIPDF $DVIPDFFLAGS $SOURCES $TARGET',
446 'PDFSUFFIX' : '.pdf',
449 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES',
452 'BUILDERS' : [Alias, CFile, CXXFile, DVI, Win32Library, Object,
453 PDF, PostScript, Program],
454 'SCANNERS' : [CScan],
456 'OBJSUFFIX' : '.obj',
458 'PROGSUFFIX' : '.exe',
460 'LIBPREFIXES': '$LIBPREFIX',
461 'LIBSUFFIX' : '.lib',
462 'LIBSUFFIXES': '$LIBSUFFIX',
463 'LIBDIRPREFIX' : '/LIBPATH:',
465 'LIBLINKPREFIX' : '',
466 'LIBLINKSUFFIX' : '$LIBSUFFIX',
469 'WIN32DEFPREFIX' : '/def:',
470 'WIN32DEFSUFFIX' : '.def',
471 'WIN32DLLPREFIX' : '/out:',
472 'WIN32IMPLIBPREFIX' : '/implib:',
473 'WIN32_INSERT_DEF' : 0,
478 'PATHEXT' : '.COM;.EXE;.BAT;.CMD',
482 def make_win32_env(version):
484 Build a dictionary of construction variables for a win32 platform.
485 ver - the version string of DevStudio to use (e.g. "6.0")
487 return make_win32_env_from_paths(get_msvc_path("include", version),
488 get_msvc_path("lib", version),
489 get_msvc_path("path", version)
490 + ";" + os.environ['PATH'])
493 if os.name == 'posix':
494 Library = PosixLibrary
496 arcom = '$AR $ARFLAGS $TARGET $SOURCES'
498 if SCons.Util.WhereIs(ranlib):
499 arcom = arcom + '\n$RANLIB $RANLIBFLAGS $TARGET'
501 ConstructionEnvironment = {
504 'CCCOM' : '$CC $CCFLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
506 'SHCCFLAGS' : '$CCFLAGS -fPIC',
507 'SHCCCOM' : '$SHCC $SHCCFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
508 'CFILESUFFIX' : '.c',
510 'CXXFLAGS' : '$CCFLAGS',
511 'CXXCOM' : '$CXX $CXXFLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
512 'CXXFILESUFFIX' : '.cc',
514 'SHCXXFLAGS' : '$CXXFLAGS -fPIC',
515 'SHCXXCOM' : '$SHCXX $SHCXXFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
518 'F77COM' : '$F77 $F77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
519 'F77PPCOM' : '$F77 $F77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
520 'SHF77FLAGS' : '$F77FLAGS -fPIC',
521 'SHF77COM' : '$F77 $SHF77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
522 'SHF77PPCOM' : '$F77 $SHF77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
524 'SHF77FLAGS' : '$F77FLAGS -fPIC',
525 'SHF77COM' : '$SHF77 $SHF77FLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
526 'SHF77PPCOM' : '$SHF77 $SHF77FLAGS $CPPFLAGS $_INCFLAGS -c -o $TARGET $SOURCES',
529 'LINKCOM' : '$LINK $LINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS',
531 'SHLINKFLAGS': '$LINKFLAGS -shared',
532 'SHLINKCOM' : '$SHLINK $SHLINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS',
538 'SHLIBPREFIX': '$LIBPREFIX',
539 'SHLIBSUFFIX': '.so',
542 'LEXCOM' : '$LEX $LEXFLAGS -t $SOURCES > $TARGET',
545 'YACCCOM' : '$YACC $YACCFLAGS -o $TARGET $SOURCES',
548 'TEXCOM' : '$TEX $TEXFLAGS $SOURCES',
551 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES',
553 'PDFCOM' : '$DVIPDF $DVIPDFFLAGS $SOURCES $TARGET',
555 'PDFSUFFIX' : '.pdf',
557 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES',
560 'BUILDERS' : [Alias, CFile, CXXFile, DVI, PosixLibrary, Object,
561 PDF, PostScript, Program],
562 'SCANNERS' : [CScan],
566 'PROGSUFFIX' : (sys.platform == 'cygwin') and '.exe' or '',
568 'LIBPREFIXES': '$LIBPREFIX',
570 'LIBSUFFIXES': [ '$LIBSUFFIX', '$SHLIBSUFFIX' ],
571 'LIBDIRPREFIX' : '-L',
573 'LIBLINKPREFIX' : '-l',
574 'LIBLINKSUFFIX' : '',
577 'ENV' : { 'PATH' : '/usr/local/bin:/bin:/usr/bin' },
580 elif os.name == 'nt':
581 Library = Win32Library
585 versions = get_devstudio_versions()
586 ConstructionEnvironment = make_win32_env(versions[0]) #use highest version
587 except (SCons.Util.RegError, SCons.Errors.InternalError):
588 # Could not get the configured directories from the registry.
589 # However, the configured directories only appear if the user
590 # changes them from the default. Therefore, we'll see if
591 # we can get the path to the MSDev base installation from
592 # the registry and deduce the default directories.
595 MVSdir = get_msdev_dir(versions[0])
597 MVSVCdir = r'%s\VC98' % MVSdir
598 MVSCommondir = r'%s\Common' % MVSdir
600 extra_path = os.pathsep + os.environ['PATH']
603 ConstructionEnvironment = make_win32_env_from_paths(
604 r'%s\atl\include;%s\mfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir),
605 r'%s\mfc\lib;%s\lib' % (MVSVCdir, MVSVCdir),
606 (r'%s\MSDev98\Bin;%s\Bin' % (MVSCommondir, MVSVCdir)) + extra_path)
608 # The DevStudio environment variables don't exist,
609 # so just use the variables from the source environment.
610 MVSdir = r'C:\Program Files\Microsoft Visual Studio'
611 MVSVCdir = r'%s\VC98' % MVSdir
612 MVSCommondir = r'%s\Common' % MVSdir
614 include_path = os.environ['INCLUDE']
618 lib_path = os.environ['LIB']
622 exe_path = os.environ['PATH']
625 ConstructionEnvironment = make_win32_env_from_paths(