"""
#
-# Copyright (c) 2001, 2002 Steven Knight
+# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
import os
+import os.path
+import errno
+import shutil
import stat
-import string
+import time
import sys
-import os.path
import SCons.Action
import SCons.Builder
-import SCons.Errors
-import SCons.Node.Alias
-import SCons.Node.FS
-import SCons.Platform
-import SCons.Scanner.C
-import SCons.Scanner.Fortran
-import SCons.Scanner.Prog
-import SCons.Util
-
-def yaccEmitter(target, source, env, **kw):
- # Yacc can be configured to emit a .h file as well
- # as a .c file, if -d is specified on the command line.
- if len(source) and \
- os.path.splitext(SCons.Util.to_String(source[0]))[1] in \
- [ '.y', '.yy'] and \
- '-d' in string.split(env.subst("$YACCFLAGS")):
- target.append(os.path.splitext(SCons.Util.to_String(target[0]))[0] + \
- '.h')
+import SCons.CacheDir
+import SCons.Environment
+import SCons.PathList
+import SCons.Subst
+import SCons.Tool
+
+# A placeholder for a default Environment (for fetching source files
+# from source code management systems and the like). This must be
+# initialized later, after the top-level directory is set by the calling
+# interface.
+_default_env = None
+
+# Lazily instantiate the default environment so the overhead of creating
+# it doesn't apply when it's not needed.
+def _fetch_DefaultEnvironment(*args, **kw):
+ """
+ Returns the already-created default construction environment.
+ """
+ global _default_env
+ return _default_env
+
+def DefaultEnvironment(*args, **kw):
+ """
+ Initial public entry point for creating the default construction
+ Environment.
+
+ After creating the environment, we overwrite our name
+ (DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
+ which more efficiently returns the initialized default construction
+ environment without checking for its existence.
+
+ (This function still exists with its _default_check because someone
+ else (*cough* Script/__init__.py *cough*) may keep a reference
+ to this function. So we can't use the fully functional idiom of
+ having the name originally be a something that *only* creates the
+ construction environment and then overwrites the name.)
+ """
+ global _default_env
+ if not _default_env:
+ import SCons.Util
+ _default_env = SCons.Environment.Environment(*args, **kw)
+ if SCons.Util.md5:
+ _default_env.Decider('MD5')
+ else:
+ _default_env.Decider('timestamp-match')
+ global DefaultEnvironment
+ DefaultEnvironment = _fetch_DefaultEnvironment
+ _default_env._CacheDir_path = None
+ return _default_env
+
+# Emitters for setting the shared attribute on object files,
+# and an action for checking that all of the source files
+# going into a shared library are, in fact, shared.
+def StaticObjectEmitter(target, source, env):
+ for tgt in target:
+ tgt.attributes.shared = None
return (target, source)
-CFile = SCons.Builder.Builder(action = { '.l' : '$LEXCOM',
- '.y' : '$YACCCOM',
- },
- emitter = yaccEmitter,
- suffix = '$CFILESUFFIX')
-
-CXXFile = SCons.Builder.Builder(action = { '.ll' : '$LEXCOM',
- '.yy' : '$YACCCOM',
- },
- emitter = yaccEmitter,
- suffix = '$CXXFILESUFFIX')
-
-class SharedFlagChecker:
- """This is a callable class that is used as
- a build action for all objects, libraries, and programs.
- Its job is to run before the "real" action that builds the
- file, to make sure we aren't trying to link shared objects
- into a static library/program, or static objects into a
- shared library."""
-
- def __init__(self, shared):
- self.shared = shared
-
- def __call__(self, source, target, env, **kw):
- if kw.has_key('shared'):
- raise SCons.Errors.UserError, "The shared= parameter to Library() or Object() no longer works.\nUse SharedObject() or SharedLibrary() instead."
- for tgt in target:
- tgt.attributes.shared = self.shared
+def SharedObjectEmitter(target, source, env):
+ for tgt in target:
+ tgt.attributes.shared = 1
+ return (target, source)
+def SharedFlagChecker(source, target, env):
+ same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
+ if same == '0' or same == '' or same == 'False':
for src in source:
- if hasattr(src.attributes, 'shared'):
- if self.shared and not src.attributes.shared:
- raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
- elif not self.shared and src.attributes.shared:
- raise SCons.Errors.UserError, "Source file: %s is shared and is not compatible with static target: %s" % (src, target[0])
-
-SharedCheck = SharedFlagChecker(1)
-StaticCheck = SharedFlagChecker(0)
-
-CAction = SCons.Action.Action([ StaticCheck, "$CCCOM" ])
-ShCAction = SCons.Action.Action([ SharedCheck, "$SHCCCOM" ])
-CXXAction = SCons.Action.Action([ StaticCheck, "$CXXCOM" ])
-ShCXXAction = SCons.Action.Action([ SharedCheck, "$SHCXXCOM" ])
-F77Action = SCons.Action.Action([ StaticCheck, "$F77COM" ])
-ShF77Action = SCons.Action.Action([ SharedCheck, "$SHF77COM" ])
-F77PPAction = SCons.Action.Action([ StaticCheck, "$F77PPCOM" ])
-ShF77PPAction = SCons.Action.Action([ SharedCheck, "$SHF77PPCOM" ])
-
-if os.path.normcase('.c') == os.path.normcase('.C'):
- # We're on a case-insensitive system, so .[CF] (upper case)
- # files should be treated like .[cf] (lower case) files.
- C_static = CAction
- C_shared = ShCAction
- F_static = F77Action
- F_shared = ShF77Action
-else:
- # We're on a case-sensitive system, so .C (upper case) files
- # are C++, and .F (upper case) files get run through the C
- # preprocessor.
- C_static = CXXAction
- C_shared = ShCXXAction
- F_static = F77PPAction
- F_shared = ShF77PPAction
-
-StaticObject = SCons.Builder.Builder(action = { ".C" : C_static,
- ".cc" : CXXAction,
- ".cpp" : CXXAction,
- ".cxx" : CXXAction,
- ".c++" : CXXAction,
- ".C++" : CXXAction,
- ".c" : CAction,
- ".f" : F77Action,
- ".for" : F77Action,
- ".F" : F_static,
- ".FOR" : F77Action,
- ".fpp" : F77PPAction,
- ".FPP" : F77PPAction },
- prefix = '$OBJPREFIX',
- suffix = '$OBJSUFFIX',
- src_builder = [CFile, CXXFile])
-
-SharedObject = SCons.Builder.Builder(action = { ".C" : C_shared,
- ".cc" : ShCXXAction,
- ".cpp" : ShCXXAction,
- ".cxx" : ShCXXAction,
- ".c++" : ShCXXAction,
- ".C++" : ShCXXAction,
- ".c" : ShCAction,
- ".f" : ShF77Action,
- ".for" : ShF77Action,
- ".FOR" : ShF77Action,
- ".F" : F_shared,
- ".fpp" : ShF77PPAction,
- ".FPP" : ShF77PPAction },
- prefix = '$OBJPREFIX',
- suffix = '$OBJSUFFIX',
- src_builder = [CFile, CXXFile])
-
-def win32TempFileMunge(env, cmd_list, for_signature):
- """Given a list of command line arguments, see if it is too
- long to pass to the win32 command line interpreter. If so,
- create a temp file, then pass "@tempfile" as the sole argument
- to the supplied command (which is the first element of cmd_list).
- Otherwise, just return [cmd_list]."""
- cmd = env.subst_list(cmd_list)[0]
- if for_signature or \
- (reduce(lambda x, y: x + len(y), cmd, 0) + len(cmd)) <= 2048:
- return [cmd_list]
+ try:
+ shared = src.attributes.shared
+ except AttributeError:
+ shared = None
+ if not shared:
+ raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
+
+SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
+
+# Some people were using these variable name before we made
+# SourceFileScanner part of the public interface. Don't break their
+# SConscript files until we've given them some fair warning and a
+# transition period.
+CScan = SCons.Tool.CScanner
+DScan = SCons.Tool.DScanner
+LaTeXScan = SCons.Tool.LaTeXScanner
+ObjSourceScan = SCons.Tool.SourceFileScanner
+ProgScan = SCons.Tool.ProgramScanner
+
+# These aren't really tool scanners, so they don't quite belong with
+# the rest of those in Tool/__init__.py, but I'm not sure where else
+# they should go. Leave them here for now.
+import SCons.Scanner.Dir
+DirScanner = SCons.Scanner.Dir.DirScanner()
+DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
+
+# Actions for common languages.
+CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
+ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
+CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
+ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
+
+ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
+ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
+
+LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
+ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
+
+LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
+
+# Common tasks that we allow users to perform in platform-independent
+# ways by creating ActionFactory instances.
+ActionFactory = SCons.Action.ActionFactory
+
+def get_paths_str(dest):
+ # If dest is a list, we need to manually call str() on each element
+ if SCons.Util.is_List(dest):
+ elem_strs = []
+ for element in dest:
+ elem_strs.append('"' + str(element) + '"')
+ return '[' + ', '.join(elem_strs) + ']'
else:
- import tempfile
- # We do a normpath because mktemp() has what appears to be
- # a bug in Win32 that will use a forward slash as a path
- # delimiter. Win32's link mistakes that for a command line
- # switch and barfs.
- tmp = os.path.normpath(tempfile.mktemp())
- args = map(SCons.Util.quote_spaces, cmd[1:])
- open(tmp, 'w').write(string.join(args, " ") + "\n")
- return [ [cmd[0], '@' + tmp],
- ['del', tmp] ]
-
-def win32LinkGenerator(env, target, source, for_signature, **kw):
- args = [ '$LINK', '$LINKFLAGS', '/OUT:%s' % target[0],
- '$(', '$_LIBDIRFLAGS', '$)', '$_LIBFLAGS' ]
- args.extend(map(SCons.Util.to_String, source))
- return win32TempFileMunge(env, args, for_signature)
-
-ProgScan = SCons.Scanner.Prog.ProgScan()
+ return '"' + str(dest) + '"'
+
+def chmod_func(dest, mode):
+ SCons.Node.FS.invalidate_node_memos(dest)
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for element in dest:
+ os.chmod(str(element), mode)
+
+def chmod_strfunc(dest, mode):
+ return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
+
+Chmod = ActionFactory(chmod_func, chmod_strfunc)
+
+def copy_func(dest, src):
+ SCons.Node.FS.invalidate_node_memos(dest)
+ if SCons.Util.is_List(src) and os.path.isdir(dest):
+ for file in src:
+ shutil.copy2(file, dest)
+ return 0
+ elif os.path.isfile(src):
+ return shutil.copy2(src, dest)
+ else:
+ return shutil.copytree(src, dest, 1)
+
+Copy = ActionFactory(copy_func,
+ lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
+ convert=str)
+
+def delete_func(dest, must_exist=0):
+ SCons.Node.FS.invalidate_node_memos(dest)
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for entry in dest:
+ entry = str(entry)
+ if not must_exist and not os.path.exists(entry):
+ continue
+ if not os.path.exists(entry) or os.path.isfile(entry):
+ os.unlink(entry)
+ continue
+ else:
+ shutil.rmtree(entry, 1)
+ continue
-Program = SCons.Builder.Builder(action=[ StaticCheck, '$LINKCOM' ],
- prefix='$PROGPREFIX',
- suffix='$PROGSUFFIX',
- src_suffix='$OBJSUFFIX',
- src_builder=StaticObject,
- scanner = ProgScan)
+def delete_strfunc(dest, must_exist=0):
+ return 'Delete(%s)' % get_paths_str(dest)
-def win32LibGenerator(target, source, env, for_signature, no_import_lib=0):
- listCmd = [ "$SHLINK", "$SHLINKFLAGS" ]
+Delete = ActionFactory(delete_func, delete_strfunc)
- for tgt in target:
- ext = os.path.splitext(str(tgt))[1]
- if ext == env.subst("$LIBSUFFIX"):
- # Put it on the command line as an import library.
- if no_import_lib:
- raise SCons.Errors.UserError, "%s: You cannot specify a .lib file as a target of a shared library build if no_import_library is nonzero." % tgt
- listCmd.append("${WIN32IMPLIBPREFIX}%s" % tgt)
- else:
- listCmd.append("${WIN32DLLPREFIX}%s" % tgt)
-
- listCmd.extend([ '$_LIBDIRFLAGS', '$_LIBFLAGS' ])
- for src in source:
- ext = os.path.splitext(str(src))[1]
- if ext == env.subst("$WIN32DEFSUFFIX"):
- # Treat this source as a .def file.
- listCmd.append("${WIN32DEFPREFIX}%s" % src)
+def mkdir_func(dest):
+ SCons.Node.FS.invalidate_node_memos(dest)
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for entry in dest:
+ try:
+ os.makedirs(str(entry))
+ except os.error, e:
+ p = str(entry)
+ if (e[0] == errno.EEXIST or (sys.platform=='win32' and e[0]==183)) \
+ and os.path.isdir(str(entry)):
+ pass # not an error if already exists
+ else:
+ raise
+
+Mkdir = ActionFactory(mkdir_func,
+ lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
+
+def move_func(dest, src):
+ SCons.Node.FS.invalidate_node_memos(dest)
+ SCons.Node.FS.invalidate_node_memos(src)
+ shutil.move(src, dest)
+
+Move = ActionFactory(move_func,
+ lambda dest, src: 'Move("%s", "%s")' % (dest, src),
+ convert=str)
+
+def touch_func(dest):
+ SCons.Node.FS.invalidate_node_memos(dest)
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for file in dest:
+ file = str(file)
+ mtime = int(time.time())
+ if os.path.exists(file):
+ atime = os.path.getatime(file)
else:
- # Just treat it as a generic source file.
- listCmd.append(str(src))
- return win32TempFileMunge(env, listCmd, for_signature)
+ open(file, 'w')
+ atime = mtime
+ os.utime(file, (atime, mtime))
-def win32LibEmitter(target, source, env, no_import_lib=0):
- dll = None
- for tgt in target:
- ext = os.path.splitext(str(tgt))[1]
- if ext == env.subst("$SHLIBSUFFIX"):
- dll = tgt
- break
- if not dll:
- raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
-
- if env.has_key("WIN32_INSERT_DEF") and \
- env["WIN32_INSERT_DEF"] and \
- not '.def' in map(lambda x: os.path.split(str(x))[1],
- source):
-
- # append a def file to the list of sources
- source.append("%s%s" % (os.path.splitext(str(dll))[0],
- env.subst("$WIN32DEFSUFFIX")))
- if not no_import_lib and \
- not env.subst("$LIBSUFFIX") in \
- map(lambda x: os.path.split(str(x))[1], target):
- # Append an import library to the list of targets.
- target.append("%s%s%s" % (env.subst("$LIBPREFIX"),
- os.path.splitext(str(dll))[0],
- env.subst("$LIBSUFFIX")))
- return (target, source)
+Touch = ActionFactory(touch_func,
+ lambda file: 'Touch(%s)' % get_paths_str(file))
+
+# Internal utility functions
-StaticLibrary = SCons.Builder.Builder(action=[ StaticCheck, "$ARCOM" ],
- prefix = '$LIBPREFIX',
- suffix = '$LIBSUFFIX',
- src_suffix = '$OBJSUFFIX',
- src_builder = StaticObject)
-
-SharedLibrary = SCons.Builder.Builder(action=[ SharedCheck, "$SHLINKCOM" ],
- emitter="$LIBEMITTER",
- prefix = '$SHLIBPREFIX',
- suffix = '$SHLIBSUFFIX',
- scanner = ProgScan,
- src_suffix = '$OBJSUFFIX',
- src_builder = SharedObject)
-
-LaTeXAction = SCons.Action.Action('$LATEXCOM')
-
-DVI = SCons.Builder.Builder(action = { '.tex' : '$TEXCOM',
- '.ltx' : LaTeXAction,
- '.latex' : LaTeXAction,
- },
- # The suffix is not configurable via a
- # construction variable like $DVISUFFIX
- # because the output file name is
- # hard-coded within TeX.
- suffix = '.dvi')
-
-PDFLaTeXAction = SCons.Action.Action('$PDFLATEXCOM')
-
-PDF = SCons.Builder.Builder(action = { '.dvi' : '$PDFCOM',
- '.tex' : '$PDFTEXCOM',
- '.ltx' : PDFLaTeXAction,
- '.latex' : PDFLaTeXAction,
- },
- prefix = '$PDFPREFIX',
- suffix = '$PDFSUFFIX')
-
-PostScript = SCons.Builder.Builder(action = '$PSCOM',
- prefix = '$PSPREFIX',
- suffix = '$PSSUFFIX',
- src_suffix = '.dvi',
- src_builder = DVI)
-
-CScan = SCons.Scanner.C.CScan()
-
-FortranScan = SCons.Scanner.Fortran.FortranScan()
-
-def alias_builder(env, target, source):
- pass
-
-Alias = SCons.Builder.Builder(action = alias_builder,
- target_factory = SCons.Node.Alias.default_ans.Alias,
- source_factory = SCons.Node.FS.default_fs.Entry,
- multi = 1)
-
-def get_devstudio_versions ():
+def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
"""
- Get list of devstudio versions from the Windows registry. Return a
- list of strings containing version numbers; an exception will be raised
- if we were unable to access the registry (eg. couldn't import
- a registry-access module) or the appropriate registry keys weren't
- found.
+ Creates a new list from 'list' by first interpolating each element
+ in the list using the 'env' dictionary and then calling f on the
+ list, and finally calling _concat_ixes to concatenate 'prefix' and
+ 'suffix' onto each element of the list.
"""
+ if not list:
+ return list
- if not SCons.Util.can_read_reg:
- raise SCons.Errors.InternalError, "No Windows registry module was found"
+ l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
+ if l is not None:
+ list = l
- K = 'Software\\Microsoft\\Devstudio'
- L = []
- for base in (SCons.Util.HKEY_CLASSES_ROOT,
- SCons.Util.HKEY_LOCAL_MACHINE,
- SCons.Util.HKEY_CURRENT_USER,
- SCons.Util.HKEY_USERS):
- try:
- k = SCons.Util.RegOpenKeyEx(base,K)
- i = 0
- while 1:
- try:
- p = SCons.Util.RegEnumKey(k,i)
- if p[0] in '123456789' and p not in L:
- L.append(p)
- except SCons.Util.RegError:
- break
- i = i + 1
- except SCons.Util.RegError:
- pass
-
- if not L:
- raise SCons.Errors.InternalError, "DevStudio was not found."
-
- L.sort()
- L.reverse()
- return L
-
-def get_msvc_path (path, version, platform='x86'):
+ return _concat_ixes(prefix, list, suffix, env)
+
+def _concat_ixes(prefix, list, suffix, env):
"""
- Get a list of devstudio directories (include, lib or path). Return
- a string delimited by ';'. An exception will be raised if unable to
- access the registry or appropriate registry keys not found.
+ Creates a new list from 'list' by concatenating the 'prefix' and
+ 'suffix' arguments onto each element of the list. A trailing space
+ on 'prefix' or leading space on 'suffix' will cause them to be put
+ into separate list elements rather than being concatenated.
"""
- if not SCons.Util.can_read_reg:
- raise SCons.Errors.InternalError, "No Windows registry module was found"
-
- if path=='lib':
- path= 'Library'
- path = string.upper(path + ' Dirs')
- K = ('Software\\Microsoft\\Devstudio\\%s\\' +
- 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
- (version,platform)
- for base in (SCons.Util.HKEY_CLASSES_ROOT,
- SCons.Util.HKEY_LOCAL_MACHINE,
- SCons.Util.HKEY_CURRENT_USER,
- SCons.Util.HKEY_USERS):
- try:
- k = SCons.Util.RegOpenKeyEx(base,K)
- i = 0
- while 1:
- try:
- (p,v,t) = SCons.Util.RegEnumValue(k,i)
- if string.upper(p) == path:
- return v
- i = i + 1
- except SCons.Util.RegError:
- break
- except SCons.Util.RegError:
- pass
-
- # if we got here, then we didn't find the registry entries:
- raise SCons.Errors.InternalError, "%s was not found in the registry."%path
-
-def get_msdev_dir(version):
- """Returns the root directory of the MSDev installation from the
- registry if it can be found, otherwise we guess."""
- if SCons.Util.can_read_reg:
- K = ('Software\\Microsoft\\Devstudio\\%s\\' +
- 'Products\\Microsoft Visual C++') % \
- version
- for base in (SCons.Util.HKEY_LOCAL_MACHINE,
- SCons.Util.HKEY_CURRENT_USER):
- try:
- k = SCons.Util.RegOpenKeyEx(base,K)
- val, tok = SCons.Util.RegQueryValueEx(k, 'ProductDir')
- return os.path.split(val)[0]
- except SCons.Util.RegError:
- pass
+ result = []
-def make_win32_env_from_paths(include, lib, path):
+ # ensure that prefix and suffix are strings
+ prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
+ suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
+
+ for x in list:
+ if isinstance(x, SCons.Node.FS.File):
+ result.append(x)
+ continue
+ x = str(x)
+ if x:
+
+ if prefix:
+ if prefix[-1] == ' ':
+ result.append(prefix[:-1])
+ elif x[:len(prefix)] != prefix:
+ x = prefix + x
+
+ result.append(x)
+
+ if suffix:
+ if suffix[0] == ' ':
+ result.append(suffix[1:])
+ elif x[-len(suffix):] != suffix:
+ result[-1] = result[-1]+suffix
+
+ return result
+
+def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
"""
- Build a dictionary of construction variables for a win32 platform.
- include - include path
- lib - library path
- path - executable path
+ This is a wrapper around _concat()/_concat_ixes() that checks for
+ the existence of prefixes or suffixes on list items and strips them
+ where it finds them. This is used by tools (like the GNU linker)
+ that need to turn something like 'libfoo.a' into '-lfoo'.
"""
- return {
- 'CC' : 'cl',
- 'CCFLAGS' : '/nologo',
- 'CCCOM' : '$CC $CCFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET',
- 'SHCC' : '$CC',
- 'SHCCFLAGS' : '$CCFLAGS',
- 'SHCCCOM' : '$SHCC $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET',
- 'CFILESUFFIX' : '.c',
- 'CXX' : '$CC',
- 'CXXFLAGS' : '$CCFLAGS',
- 'CXXCOM' : '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET',
- 'SHCXX' : '$CXX',
- 'SHCXXFLAGS' : '$CXXFLAGS',
- 'SHCXXCOM' : '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET',
- 'CXXFILESUFFIX' : '.cc',
- 'F77' : 'g77',
- 'F77FLAGS' : '',
- 'F77COM' : '$F77 $F77FLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET',
- 'F77PPCOM' : '$F77 $F77FLAGS $CPPFLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET',
- 'SHF77' : '$F77',
- 'SHF77FLAGS' : '$F77FLAGS',
- 'SHF77COM' : '$SHF77 $SHF77FLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET',
- 'SHF77PPCOM' : '$SHF77 $SHF77FLAGS $CPPFLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET',
- 'LINK' : 'link',
- 'LINKFLAGS' : '/nologo',
- 'LINKCOM' : SCons.Action.CommandGenerator(win32LinkGenerator),
- 'SHLINK' : '$LINK',
- 'SHLINKFLAGS': '$LINKFLAGS /dll',
- 'SHLINKCOM' : SCons.Action.CommandGenerator(win32LibGenerator),
- 'AR' : 'lib',
- 'ARFLAGS' : '/nologo',
- 'ARCOM' : '$AR $ARFLAGS /OUT:$TARGET $SOURCES',
- 'LEX' : 'lex',
- 'LEXFLAGS' : '',
- 'LEXCOM' : '$LEX $LEXFLAGS -t $SOURCES > $TARGET',
- 'YACC' : 'yacc',
- 'YACCFLAGS' : '',
- 'YACCCOM' : '$YACC $YACCFLAGS -o $TARGET $SOURCES',
- 'TEX' : 'tex',
- 'TEXFLAGS' : '',
- 'TEXCOM' : '$TEX $TEXFLAGS $SOURCES',
- 'LATEX' : 'latex',
- 'LATEXFLAGS' : '',
- 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES',
- 'DVIPDF' : 'dvipdf',
- 'DVIPDFFLAGS' : '',
- 'PDFCOM' : '$DVIPDF $DVIPDFFLAGS $SOURCES $TARGET',
- 'PDFPREFIX' : '',
- 'PDFSUFFIX' : '.pdf',
- 'PDFTEX' : 'pdftex',
- 'PDFTEXFLAGS' : '',
- 'PDFTEXCOM' : '$PDFTEX $PDFTEXFLAGS $SOURCES $TARGET',
- 'PDFLATEX' : 'pdflatex',
- 'PDFLATEXFLAGS' : '',
- 'PDFLATEXCOM' : '$PDFLATEX $PDFLATEXFLAGS $SOURCES $TARGET',
- 'DVIPS' : 'dvips',
- 'DVIPSFLAGS' : '',
- 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES',
- 'PSPREFIX' : '',
- 'PSSUFFIX' : '.ps',
- 'BUILDERS' : { 'Alias' : Alias,
- 'CFile' : CFile,
- 'CXXFile' : CXXFile,
- 'DVI' : DVI,
- 'Library' : StaticLibrary,
- 'StaticLibrary' : StaticLibrary,
- 'SharedLibrary' : SharedLibrary,
- 'Object' : StaticObject,
- 'StaticObject' : StaticObject,
- 'SharedObject' : SharedObject,
- 'PDF' : PDF,
- 'PostScript' : PostScript,
- 'Program' : Program },
- 'SCANNERS' : [CScan, FortranScan],
- 'LIBDIRPREFIX' : '/LIBPATH:',
- 'LIBDIRSUFFIX' : '',
- 'LIBLINKPREFIX' : '',
- 'LIBLINKSUFFIX' : '$LIBSUFFIX',
- 'LIBEMITTER' : win32LibEmitter,
- 'INCPREFIX' : '/I',
- 'INCSUFFIX' : '',
- 'WIN32DEFPREFIX' : '/def:',
- 'WIN32DEFSUFFIX' : '.def',
- 'WIN32DLLPREFIX' : '/out:',
- 'WIN32IMPLIBPREFIX' : '/implib:',
- 'WIN32_INSERT_DEF' : 0,
- 'ENV' : {
- 'INCLUDE' : include,
- 'LIB' : lib,
- 'PATH' : path,
- },
- }
-
-def make_win32_env(version):
+
+ if not itms:
+ return itms
+
+ if not callable(c):
+ env_c = env['_concat']
+ if env_c != _concat and callable(env_c):
+ # There's a custom _concat() method in the construction
+ # environment, and we've allowed people to set that in
+ # the past (see test/custom-concat.py), so preserve the
+ # backwards compatibility.
+ c = env_c
+ else:
+ c = _concat_ixes
+
+ stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes)))
+ stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes)))
+
+ stripped = []
+ for l in SCons.PathList.PathList(itms).subst_path(env, None, None):
+ if isinstance(l, SCons.Node.FS.File):
+ stripped.append(l)
+ continue
+
+ if not SCons.Util.is_String(l):
+ l = str(l)
+
+ for stripprefix in stripprefixes:
+ lsp = len(stripprefix)
+ if l[:lsp] == stripprefix:
+ l = l[lsp:]
+ # Do not strip more than one prefix
+ break
+
+ for stripsuffix in stripsuffixes:
+ lss = len(stripsuffix)
+ if l[-lss:] == stripsuffix:
+ l = l[:-lss]
+ # Do not strip more than one suffix
+ break
+
+ stripped.append(l)
+
+ return c(prefix, stripped, suffix, env)
+
+def processDefines(defs):
+ """process defines, resolving strings, lists, dictionaries, into a list of
+ strings
"""
- Build a dictionary of construction variables for a win32 platform.
- ver - the version string of DevStudio to use (e.g. "6.0")
+ if SCons.Util.is_List(defs):
+ l = []
+ for d in defs:
+ if SCons.Util.is_List(d) or isinstance(d, tuple):
+ l.append(str(d[0]) + '=' + str(d[1]))
+ else:
+ l.append(str(d))
+ elif SCons.Util.is_Dict(defs):
+ # The items in a dictionary are stored in random order, but
+ # if the order of the command-line options changes from
+ # invocation to invocation, then the signature of the command
+ # line will change and we'll get random unnecessary rebuilds.
+ # Consequently, we have to sort the keys to ensure a
+ # consistent order...
+ l = []
+ for k,v in sorted(defs.items()):
+ if v is None:
+ l.append(str(k))
+ else:
+ l.append(str(k) + '=' + str(v))
+ else:
+ l = [str(defs)]
+ return l
+
+def _defines(prefix, defs, suffix, env, c=_concat_ixes):
+ """A wrapper around _concat_ixes that turns a list or string
+ into a list of C preprocessor command-line definitions.
"""
- return make_win32_env_from_paths(get_msvc_path("include", version),
- get_msvc_path("lib", version),
- get_msvc_path("path", version)
- + ";" + os.environ['PATH'])
-
-
-if os.name == 'posix':
- arcom = '$AR $ARFLAGS $TARGET $SOURCES'
- ranlib = 'ranlib'
- if SCons.Util.WhereIs(ranlib):
- arcom = arcom + '\n$RANLIB $RANLIBFLAGS $TARGET'
-
- ConstructionEnvironment = {
- 'CC' : 'cc',
- 'CCFLAGS' : '',
- 'CCCOM' : '$CC $CCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES',
- 'SHCC' : '$CC',
- 'SHCCFLAGS' : '$CCFLAGS -fPIC',
- 'SHCCCOM' : '$SHCC $SHCCFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES',
- 'CFILESUFFIX' : '.c',
- 'CXX' : 'c++',
- 'CXXFLAGS' : '$CCFLAGS',
- 'CXXCOM' : '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES',
- 'CXXFILESUFFIX' : '.cc',
- 'SHCXX' : '$CXX',
- 'SHCXXFLAGS' : '$CXXFLAGS -fPIC',
- 'SHCXXCOM' : '$SHCXX $SHCXXFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES',
- 'F77' : 'g77',
- 'F77FLAGS' : '',
- 'F77COM' : '$F77 $F77FLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES',
- 'F77PPCOM' : '$F77 $F77FLAGS $CPPFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES',
- 'SHF77FLAGS' : '$F77FLAGS -fPIC',
- 'SHF77COM' : '$F77 $SHF77FLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES',
- 'SHF77PPCOM' : '$F77 $SHF77FLAGS $CPPFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES',
- 'SHF77' : '$F77',
- 'SHF77FLAGS' : '$F77FLAGS -fPIC',
- 'SHF77COM' : '$SHF77 $SHF77FLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES',
- 'SHF77PPCOM' : '$SHF77 $SHF77FLAGS $CPPFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES',
- 'LINK' : '$CXX',
- 'LINKFLAGS' : '',
- 'LINKCOM' : '$LINK $LINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS',
- 'SHLINK' : '$LINK',
- 'SHLINKFLAGS': '$LINKFLAGS -shared',
- 'SHLINKCOM' : '$SHLINK $SHLINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS',
- 'AR' : 'ar',
- 'ARFLAGS' : 'r',
- 'RANLIB' : ranlib,
- 'RANLIBFLAGS' : '',
- 'ARCOM' : arcom,
- 'LEX' : 'lex',
- 'LEXFLAGS' : '',
- 'LEXCOM' : '$LEX $LEXFLAGS -t $SOURCES > $TARGET',
- 'YACC' : 'yacc',
- 'YACCFLAGS' : '',
- 'YACCCOM' : '$YACC $YACCFLAGS -o $TARGET $SOURCES',
- 'TEX' : 'tex',
- 'TEXFLAGS' : '',
- 'TEXCOM' : '$TEX $TEXFLAGS $SOURCES',
- 'LATEX' : 'latex',
- 'LATEXFLAGS' : '',
- 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES',
- 'DVIPDF' : 'dvipdf',
- 'PDFCOM' : '$DVIPDF $DVIPDFFLAGS $SOURCES $TARGET',
- 'PDFPREFIX' : '',
- 'PDFSUFFIX' : '.pdf',
- 'PDFTEX' : 'pdftex',
- 'PDFTEXFLAGS' : '',
- 'PDFTEXCOM' : '$PDFTEX $PDFTEXFLAGS $SOURCES $TARGET',
- 'PDFLATEX' : 'pdflatex',
- 'PDFLATEXFLAGS' : '',
- 'PDFLATEXCOM' : '$PDFLATEX $PDFLATEXFLAGS $SOURCES $TARGET',
- 'DVIPS' : 'dvips',
- 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES',
- 'PSPREFIX' : '',
- 'PSSUFFIX' : '.ps',
- 'BUILDERS' : { 'Alias' : Alias,
- 'CFile' : CFile,
- 'CXXFile' : CXXFile,
- 'DVI' : DVI,
- 'Library' : StaticLibrary,
- 'StaticLibrary' : StaticLibrary,
- 'SharedLibrary' : SharedLibrary,
- 'Object' : StaticObject,
- 'StaticObject' : StaticObject,
- 'SharedObject' : SharedObject,
- 'PDF' : PDF,
- 'PostScript' : PostScript,
- 'Program' : Program },
- 'SCANNERS' : [CScan, FortranScan],
- 'LIBDIRPREFIX' : '-L',
- 'LIBDIRSUFFIX' : '',
- 'LIBLINKPREFIX' : '-l',
- 'LIBLINKSUFFIX' : '',
- 'INCPREFIX' : '-I',
- 'INCSUFFIX' : '',
- }
-
-elif os.name == 'nt':
- versions = None
- try:
- versions = get_devstudio_versions()
- ConstructionEnvironment = make_win32_env(versions[0]) #use highest version
- except (SCons.Util.RegError, SCons.Errors.InternalError):
- # Could not get the configured directories from the registry.
- # However, the configured directories only appear if the user
- # changes them from the default. Therefore, we'll see if
- # we can get the path to the MSDev base installation from
- # the registry and deduce the default directories.
- MVSdir = None
- if versions:
- MVSdir = get_msdev_dir(versions[0])
- if MVSdir:
- MVSVCdir = r'%s\VC98' % MVSdir
- MVSCommondir = r'%s\Common' % MVSdir
- try:
- extra_path = os.pathsep + os.environ['PATH']
- except KeyError:
- extra_path = ''
- ConstructionEnvironment = make_win32_env_from_paths(
- r'%s\atl\include;%s\mfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir),
- r'%s\mfc\lib;%s\lib' % (MVSVCdir, MVSVCdir),
- (r'%s\MSDev98\Bin;%s\Bin' % (MVSCommondir, MVSVCdir)) + extra_path)
- else:
- # The DevStudio environment variables don't exist,
- # so just use the variables from the source environment.
- MVSdir = r'C:\Program Files\Microsoft Visual Studio'
- MVSVCdir = r'%s\VC98' % MVSdir
- MVSCommondir = r'%s\Common' % MVSdir
- try:
- include_path = os.environ['INCLUDE']
- except KeyError:
- include_path = ''
- try:
- lib_path = os.environ['LIB']
- except KeyError:
- lib_path = ''
- try:
- exe_path = os.environ['PATH']
- except KeyError:
- exe_path = ''
- ConstructionEnvironment = make_win32_env_from_paths(
- include_path,
- lib_path,
- exe_path)
+
+ return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
+
+class NullCmdGenerator:
+ """This is a callable class that can be used in place of other
+ command generators if you don't want them to do anything.
+
+ The __call__ method for this class simply returns the thing
+ you instantiated it with.
+
+ Example usage:
+ env["DO_NOTHING"] = NullCmdGenerator
+ env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
+ """
+
+ def __init__(self, cmd):
+ self.cmd = cmd
+
+ def __call__(self, target, source, env, for_signature=None):
+ return self.cmd
+
+class Variable_Method_Caller:
+ """A class for finding a construction variable on the stack and
+ calling one of its methods.
+
+ We use this to support "construction variables" in our string
+ eval()s that actually stand in for methods--specifically, use
+ of "RDirs" in call to _concat that should actually execute the
+ "TARGET.RDirs" method. (We used to support this by creating a little
+ "build dictionary" that mapped RDirs to the method, but this got in
+ the way of Memoizing construction environments, because we had to
+ create new environment objects to hold the variables.)
+ """
+ def __init__(self, variable, method):
+ self.variable = variable
+ self.method = method
+ def __call__(self, *args, **kw):
+ try: 1/0
+ except ZeroDivisionError:
+ # Don't start iterating with the current stack-frame to
+ # prevent creating reference cycles (f_back is safe).
+ frame = sys.exc_info()[2].tb_frame.f_back
+ variable = self.variable
+ while frame:
+ if variable in frame.f_locals:
+ v = frame.f_locals[variable]
+ if v:
+ method = getattr(v, self.method)
+ return method(*args, **kw)
+ frame = frame.f_back
+ return None
+
+ConstructionEnvironment = {
+ 'BUILDERS' : {},
+ 'SCANNERS' : [],
+ 'CONFIGUREDIR' : '#/.sconf_temp',
+ 'CONFIGURELOG' : '#/config.log',
+ 'CPPSUFFIXES' : SCons.Tool.CSuffixes,
+ 'DSUFFIXES' : SCons.Tool.DSuffixes,
+ 'ENV' : {},
+ 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
+# 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
+ '_concat' : _concat,
+ '_defines' : _defines,
+ '_stripixes' : _stripixes,
+ '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
+ '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
+ '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
+ '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
+ 'TEMPFILE' : NullCmdGenerator,
+ 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
+ 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
+ 'File' : Variable_Method_Caller('TARGET', 'File'),
+ 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
+}
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: