OLD | NEW |
(Empty) | |
| 1 # |
| 2 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S
Cons Foundation |
| 3 # |
| 4 # Permission is hereby granted, free of charge, to any person obtaining |
| 5 # a copy of this software and associated documentation files (the |
| 6 # "Software"), to deal in the Software without restriction, including |
| 7 # without limitation the rights to use, copy, modify, merge, publish, |
| 8 # distribute, sublicense, and/or sell copies of the Software, and to |
| 9 # permit persons to whom the Software is furnished to do so, subject to |
| 10 # the following conditions: |
| 11 # |
| 12 # The above copyright notice and this permission notice shall be included |
| 13 # in all copies or substantial portions of the Software. |
| 14 # |
| 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 # |
| 23 |
| 24 __revision__ = "src/engine/SCons/Tool/MSCommon/common.py 5134 2010/08/16 23:02:4
0 bdeegan" |
| 25 |
| 26 __doc__ = """ |
| 27 Common helper functions for working with the Microsoft tool chain. |
| 28 """ |
| 29 |
| 30 import copy |
| 31 import os |
| 32 import subprocess |
| 33 import re |
| 34 |
| 35 import SCons.Util |
| 36 |
| 37 |
| 38 logfile = os.environ.get('SCONS_MSCOMMON_DEBUG') |
| 39 if logfile == '-': |
| 40 def debug(x): |
| 41 print x |
| 42 elif logfile: |
| 43 try: |
| 44 import logging |
| 45 except ImportError: |
| 46 debug = lambda x: open(logfile, 'a').write(x + '\n') |
| 47 else: |
| 48 logging.basicConfig(filename=logfile, level=logging.DEBUG) |
| 49 debug = logging.debug |
| 50 else: |
| 51 debug = lambda x: None |
| 52 |
| 53 |
| 54 _is_win64 = None |
| 55 |
| 56 def is_win64(): |
| 57 """Return true if running on windows 64 bits. |
| 58 |
| 59 Works whether python itself runs in 64 bits or 32 bits.""" |
| 60 # Unfortunately, python does not provide a useful way to determine |
| 61 # if the underlying Windows OS is 32-bit or 64-bit. Worse, whether |
| 62 # the Python itself is 32-bit or 64-bit affects what it returns, |
| 63 # so nothing in sys.* or os.* help. |
| 64 |
| 65 # Apparently the best solution is to use env vars that Windows |
| 66 # sets. If PROCESSOR_ARCHITECTURE is not x86, then the python |
| 67 # process is running in 64 bit mode (on a 64-bit OS, 64-bit |
| 68 # hardware, obviously). |
| 69 # If this python is 32-bit but the OS is 64, Windows will set |
| 70 # ProgramW6432 and PROCESSOR_ARCHITEW6432 to non-null. |
| 71 # (Checking for HKLM\Software\Wow6432Node in the registry doesn't |
| 72 # work, because some 32-bit installers create it.) |
| 73 global _is_win64 |
| 74 if _is_win64 is None: |
| 75 # I structured these tests to make it easy to add new ones or |
| 76 # add exceptions in the future, because this is a bit fragile. |
| 77 _is_win64 = False |
| 78 if os.environ.get('PROCESSOR_ARCHITECTURE','x86') != 'x86': |
| 79 _is_win64 = True |
| 80 if os.environ.get('PROCESSOR_ARCHITEW6432'): |
| 81 _is_win64 = True |
| 82 if os.environ.get('ProgramW6432'): |
| 83 _is_win64 = True |
| 84 return _is_win64 |
| 85 |
| 86 |
| 87 def read_reg(value): |
| 88 return SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, value)[0] |
| 89 |
| 90 def has_reg(value): |
| 91 """Return True if the given key exists in HKEY_LOCAL_MACHINE, False |
| 92 otherwise.""" |
| 93 try: |
| 94 SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, value) |
| 95 ret = True |
| 96 except WindowsError: |
| 97 ret = False |
| 98 return ret |
| 99 |
| 100 # Functions for fetching environment variable settings from batch files. |
| 101 |
| 102 def normalize_env(env, keys, force=False): |
| 103 """Given a dictionary representing a shell environment, add the variables |
| 104 from os.environ needed for the processing of .bat files; the keys are |
| 105 controlled by the keys argument. |
| 106 |
| 107 It also makes sure the environment values are correctly encoded. |
| 108 |
| 109 If force=True, then all of the key values that exist are copied |
| 110 into the returned dictionary. If force=false, values are only |
| 111 copied if the key does not already exist in the copied dictionary. |
| 112 |
| 113 Note: the environment is copied.""" |
| 114 normenv = {} |
| 115 if env: |
| 116 for k in env.keys(): |
| 117 normenv[k] = copy.deepcopy(env[k]).encode('mbcs') |
| 118 |
| 119 for k in keys: |
| 120 if k in os.environ and (force or not k in normenv): |
| 121 normenv[k] = os.environ[k].encode('mbcs') |
| 122 |
| 123 return normenv |
| 124 |
| 125 def get_output(vcbat, args = None, env = None): |
| 126 """Parse the output of given bat file, with given args.""" |
| 127 |
| 128 if env is None: |
| 129 # Create a blank environment, for use in launching the tools |
| 130 env = SCons.Environment.Environment(tools=[]) |
| 131 |
| 132 # TODO: This is a hard-coded list of the variables that (may) need |
| 133 # to be imported from os.environ[] for v[sc]*vars*.bat file |
| 134 # execution to work. This list should really be either directly |
| 135 # controlled by vc.py, or else derived from the common_tools_var |
| 136 # settings in vs.py. |
| 137 vars = [ |
| 138 'COMSPEC', |
| 139 'VS90COMNTOOLS', |
| 140 'VS80COMNTOOLS', |
| 141 'VS71COMNTOOLS', |
| 142 'VS70COMNTOOLS', |
| 143 'VS60COMNTOOLS', |
| 144 ] |
| 145 env['ENV'] = normalize_env(env['ENV'], vars, force=False) |
| 146 |
| 147 if args: |
| 148 debug("Calling '%s %s'" % (vcbat, args)) |
| 149 popen = SCons.Action._subproc(env, |
| 150 '"%s" %s & set' % (vcbat, args), |
| 151 stdin = 'devnull', |
| 152 stdout=subprocess.PIPE, |
| 153 stderr=subprocess.PIPE) |
| 154 else: |
| 155 debug("Calling '%s'" % vcbat) |
| 156 popen = SCons.Action._subproc(env, |
| 157 '"%s" & set' % vcbat, |
| 158 stdin = 'devnull', |
| 159 stdout=subprocess.PIPE, |
| 160 stderr=subprocess.PIPE) |
| 161 |
| 162 # Use the .stdout and .stderr attributes directly because the |
| 163 # .communicate() method uses the threading module on Windows |
| 164 # and won't work under Pythons not built with threading. |
| 165 stdout = popen.stdout.read() |
| 166 stderr = popen.stderr.read() |
| 167 if stderr: |
| 168 # TODO: find something better to do with stderr; |
| 169 # this at least prevents errors from getting swallowed. |
| 170 import sys |
| 171 sys.stderr.write(stderr) |
| 172 if popen.wait() != 0: |
| 173 raise IOError(stderr.decode("mbcs")) |
| 174 |
| 175 output = stdout.decode("mbcs") |
| 176 return output |
| 177 |
| 178 def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")): |
| 179 # dkeep is a dict associating key: path_list, where key is one item from |
| 180 # keep, and pat_list the associated list of paths |
| 181 |
| 182 dkeep = dict([(i, []) for i in keep]) |
| 183 |
| 184 # rdk will keep the regex to match the .bat file output line starts |
| 185 rdk = {} |
| 186 for i in keep: |
| 187 rdk[i] = re.compile('%s=(.*)' % i, re.I) |
| 188 |
| 189 def add_env(rmatch, key, dkeep=dkeep): |
| 190 plist = rmatch.group(1).split(os.pathsep) |
| 191 for p in plist: |
| 192 # Do not add empty paths (when a var ends with ;) |
| 193 if p: |
| 194 p = p.encode('mbcs') |
| 195 # XXX: For some reason, VC98 .bat file adds "" around the PATH |
| 196 # values, and it screws up the environment later, so we strip |
| 197 # it. |
| 198 p = p.strip('"') |
| 199 dkeep[key].append(p) |
| 200 |
| 201 for line in output.splitlines(): |
| 202 for k,v in rdk.items(): |
| 203 m = v.match(line) |
| 204 if m: |
| 205 add_env(m, k) |
| 206 |
| 207 return dkeep |
| 208 |
| 209 # TODO(sgk): unused |
| 210 def output_to_dict(output): |
| 211 """Given an output string, parse it to find env variables. |
| 212 |
| 213 Return a dict where keys are variables names, and values their content""" |
| 214 envlinem = re.compile(r'^([a-zA-z0-9]+)=([\S\s]*)$') |
| 215 parsedenv = {} |
| 216 for line in output.splitlines(): |
| 217 m = envlinem.match(line) |
| 218 if m: |
| 219 parsedenv[m.group(1)] = m.group(2) |
| 220 return parsedenv |
| 221 |
| 222 # TODO(sgk): unused |
| 223 def get_new(l1, l2): |
| 224 """Given two list l1 and l2, return the items in l2 which are not in l1. |
| 225 Order is maintained.""" |
| 226 |
| 227 # We don't try to be smart: lists are small, and this is not the bottleneck |
| 228 # is any case |
| 229 new = [] |
| 230 for i in l2: |
| 231 if i not in l1: |
| 232 new.append(i) |
| 233 |
| 234 return new |
| 235 |
| 236 # Local Variables: |
| 237 # tab-width:4 |
| 238 # indent-tabs-mode:nil |
| 239 # End: |
| 240 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |