Support foreign language installs of Visual Studio (bug 6055, r=ds). default tip
1.1 --- a/ambuild2/frontend/amb2/gen.py Sat Feb 15 12:24:48 2014 -0800
1.2 +++ b/ambuild2/frontend/amb2/gen.py Sat Feb 15 20:57:39 2014 -0800
1.3 @@ -17,7 +17,6 @@
1.4 import os
1.5 from ambuild2 import util
1.6 from ambuild2 import nodetypes
1.7 -from ambuild2.frontend.cpp import DetectCompiler
1.8 from ambuild2.frontend import base_gen
1.9 from ambuild2 import database
1.10
1.11 @@ -163,6 +162,18 @@
1.12 'options': self.options,
1.13 'args': self.args
1.14 }
1.15 +
1.16 + # Save any extra compiler info that must be communicated to the backend.
1.17 + if self.compiler is not None:
1.18 + compilers = [
1.19 + ('cc', self.compiler.cc),
1.20 + ('cxx', self.compiler.cxx),
1.21 + ]
1.22 + for prefix, comp in compilers:
1.23 + for prop_name in comp.extra_props:
1.24 + key = '{0}_{1}'.format(prefix, prop_name)
1.25 + vars[key] = comp.extra_props[prop_name]
1.26 +
1.27 with open(os.path.join(self.cacheFolder, 'vars'), 'wb') as fp:
1.28 util.DiskPickle(vars, fp)
1.29
2.1 --- a/ambuild2/frontend/cpp.py Sat Feb 15 12:24:48 2014 -0800
2.2 +++ b/ambuild2/frontend/cpp.py Sat Feb 15 20:57:39 2014 -0800
2.3 @@ -27,6 +27,7 @@
2.4 self.command = command
2.5 self.objSuffix = objSuffix
2.6 self.debuginfo_argv = []
2.7 + self.extra_props = {}
2.8
2.9 class MSVC(Vendor):
2.10 def __init__(self, command, version):
2.11 @@ -115,6 +116,18 @@
2.12 }
2.13 }
2.14
2.15 +def DetectMicrosoftInclusionPattern(text):
2.16 + for line in [raw.strip() for raw in text.split('\n')]:
2.17 + m = re.match(r'(.*)\s+([A-Za-z]:\\.*stdio\.h)$', line)
2.18 + if m is None:
2.19 + continue
2.20 +
2.21 + phrase = m.group(1)
2.22 + return re.escape(phrase) + r'\s+([A-Za-z]:\\.*)$'
2.23 +
2.24 + raise Exception('Could not find compiler inclusion pattern')
2.25 +
2.26 +
2.27 def DetectCompiler(cx, env, var):
2.28 if var in env:
2.29 trys = [env[var]]
2.30 @@ -191,6 +204,12 @@
2.31 # if vendor == 'gcc' and mode == 'CXX':
2.32 # args.extend(['-fno-exceptions', '-fno-rtti'])
2.33 args.extend([filename, '-o', executable])
2.34 +
2.35 + # For MSVC, we need to detect the inclusion pattern for foreign-language
2.36 + # systems.
2.37 + if vendor == 'msvc':
2.38 + args += ['-nologo', '-showIncludes']
2.39 +
2.40 util.con_out(
2.41 util.ConsoleHeader,
2.42 'Checking {0} compiler (vendor test {1})... '.format(mode, vendor),
2.43 @@ -206,6 +225,10 @@
2.44 print('failed with return code {0}'.format(p.returncode))
2.45 return False
2.46
2.47 + inclusion_pattern = None
2.48 + if vendor == 'msvc':
2.49 + inclusion_pattern = DetectMicrosoftInclusionPattern(p.stdoutText)
2.50 +
2.51 exe = util.MakePath('.', executable)
2.52 p = util.CreateProcess([executable], executable = exe)
2.53 if p == None:
2.54 @@ -235,6 +258,9 @@
2.55 print('Unknown vendor {0}'.format(vendor))
2.56 return False
2.57
2.58 + if inclusion_pattern is not None:
2.59 + v.extra_props['inclusion_pattern'] = inclusion_pattern
2.60 +
2.61 util.con_out(
2.62 util.ConsoleHeader,
2.63 'found {0} version {1}'.format(vendor, version),
3.1 --- a/ambuild2/task.py Sat Feb 15 12:24:48 2014 -0800
3.2 +++ b/ambuild2/task.py Sat Feb 15 20:57:39 2014 -0800
3.3 @@ -44,10 +44,11 @@
3.4 return (' '.join([arg for arg in self.data]))
3.5
3.6 class WorkerChild(ChildProcessListener):
3.7 - def __init__(self, pump, channel, buildPath):
3.8 + def __init__(self, pump, channel, vars):
3.9 super(WorkerChild, self).__init__(pump, channel)
3.10 - self.buildPath = buildPath
3.11 + self.buildPath = vars['buildPath']
3.12 self.pid = os.getpid()
3.13 + self.vars = vars
3.14 self.messageMap = {
3.15 'task': lambda channel, message: self.receiveTask(channel, message)
3.16 }
3.17 @@ -200,7 +201,7 @@
3.18 if cc_type == 'gcc':
3.19 err, deps = util.ParseGCCDeps(err)
3.20 elif cc_type == 'msvc':
3.21 - out, deps = util.ParseMSVCDeps(out)
3.22 + out, deps = util.ParseMSVCDeps(self.vars, out)
3.23 elif cc_type == 'sun':
3.24 err, deps = util.ParseSunDeps(err)
3.25 else:
3.26 @@ -226,7 +227,7 @@
3.27 with util.FolderChanger(task_folder):
3.28 # Includes go to stderr when we preprocess to stdout.
3.29 p, out, err = util.Execute(cl_argv)
3.30 - out, deps = util.ParseMSVCDeps(err)
3.31 + out, deps = util.ParseMSVCDeps(self.vars, err)
3.32 paths = self.rewriteDeps(deps)
3.33
3.34 if p.returncode == 0:
3.35 @@ -263,7 +264,7 @@
3.36
3.37 # The TaskMasterChild is in the same process as the WorkerParent.
3.38 class TaskMasterChild(ChildProcessListener):
3.39 - def __init__(self, pump, channel, task_graph, buildPath, num_processes):
3.40 + def __init__(self, pump, channel, task_graph, vars, num_processes):
3.41 super(TaskMasterChild, self).__init__(pump, channel)
3.42 self.task_graph = task_graph
3.43 self.outstanding = {}
3.44 @@ -279,7 +280,7 @@
3.45 self.procman.spawn(
3.46 WorkerParent(self),
3.47 WorkerChild,
3.48 - args=(buildPath,)
3.49 + args=(vars,)
3.50 )
3.51
3.52 self.channel.send({
3.53 @@ -456,7 +457,7 @@
3.54 self.taskMaster = cx.procman.spawn(
3.55 self,
3.56 TaskMasterChild,
3.57 - args=(task_graph, cx.buildPath, num_processes)
3.58 + args=(task_graph, cx.vars, num_processes)
3.59 )
3.60
3.61 def receiveDone(self, message):
4.1 --- a/ambuild2/util.py Sat Feb 15 12:24:48 2014 -0800
4.2 +++ b/ambuild2/util.py Sat Feb 15 20:57:39 2014 -0800
4.3 @@ -88,8 +88,8 @@
4.4
4.5 def WaitForProcess(process):
4.6 out, err = process.communicate()
4.7 - process.stdoutText = DecodeConsoleText(sys.stdout, process.stdout, out)
4.8 - process.stderrText = DecodeConsoleText(sys.stderr, process.stderr, err)
4.9 + process.stdoutText = DecodeConsoleText(sys.stdout, out)
4.10 + process.stderrText = DecodeConsoleText(sys.stderr, err)
4.11 return process.returncode
4.12
4.13 def CreateProcess(argv, executable = None):
4.14 @@ -152,8 +152,8 @@
4.15 shell=shell
4.16 )
4.17 stdout, stderr = p.communicate()
4.18 - out = stdout.decode('utf8')
4.19 - err = stderr.decode('utf8')
4.20 + out = DecodeConsoleText(sys.stdout, stdout)
4.21 + err = DecodeConsoleText(sys.stderr, stderr)
4.22 return p, out, err
4.23
4.24 def typeof(x):
4.25 @@ -222,15 +222,22 @@
4.26 new_text += line + '\n'
4.27 return new_text, deps
4.28
4.29 -def ParseMSVCDeps(out):
4.30 +def ParseMSVCDeps(vars, out):
4.31 + if 'cc_inclusion_pattern' in vars:
4.32 + pattern = vars['cc_inclusion_pattern']
4.33 + elif 'cxx_inclusion_pattern' in vars:
4.34 + pattern = vars['cxx_inclusion_pattern']
4.35 + else:
4.36 + pattern = 'Note: including file:\s+(.+)$'
4.37 +
4.38 deps = []
4.39 new_text = ''
4.40 out = out.replace('\r\n', '\n')
4.41 out = out.replace('\r', '\n')
4.42 for line in out.split('\n'):
4.43 - m = re.match('Note: including file:\s+(.+)$', line)
4.44 + m = re.search(pattern, line)
4.45 if m != None:
4.46 - file = m.groups()[0].strip()
4.47 + file = m.group(1).strip()
4.48 deps.append(file)
4.49 else:
4.50 new_text += line + '\n'
4.51 @@ -364,23 +371,19 @@
4.52 ConsoleNormal)
4.53 raise
4.54
4.55 -def try_decode_with_pipe(pipe, text):
4.56 +def DecodeConsoleText(origin, text):
4.57 try:
4.58 - if hasattr(pipe, 'encoding') and pipe.encoding:
4.59 - return text.decode(pipe.encoding, 'replace')
4.60 + if origin.encoding:
4.61 + return text.decode(origin.encoding, 'replace')
4.62 except:
4.63 - return None
4.64 + pass
4.65
4.66 -def DecodeConsoleText(origin, pipe, text):
4.67 - result = try_decode_with_pipe(pipe, text)
4.68 - if result is None:
4.69 - result = try_decode_with_pipe(origin, text)
4.70 - if result is None:
4.71 - try:
4.72 - result = text.decode(locale.getpreferredencoding(), 'replace')
4.73 - except:
4.74 - result = text
4.75 - return result.encode('utf8')
4.76 + try:
4.77 + return text.decode(locale.getpreferredencoding(), 'replace')
4.78 + except:
4.79 + pass
4.80 +
4.81 + return text.decode('utf8', 'replace')
4.82
4.83 def WriteEncodedText(fd, text):
4.84 if not hasattr(fd, 'encoding') or fd.encoding == None: