3424c015d30bf20a148c4482164a7a5c387c74de
[platform/upstream/nodejs.git] / tools / gyp / pylib / gyp / win_tool.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2012 Google Inc. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 """Utility functions for Windows builds.
8
9 These functions are executed via gyp-win-tool when using the ninja generator.
10 """
11
12 import os
13 import shutil
14 import subprocess
15 import sys
16
17 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
18
19
20 def main(args):
21   executor = WinTool()
22   exit_code = executor.Dispatch(args)
23   if exit_code is not None:
24     sys.exit(exit_code)
25
26
27 class WinTool(object):
28   """This class performs all the Windows tooling steps. The methods can either
29   be executed directly, or dispatched from an argument list."""
30
31   def Dispatch(self, args):
32     """Dispatches a string command to a method."""
33     if len(args) < 1:
34       raise Exception("Not enough arguments")
35
36     method = "Exec%s" % self._CommandifyName(args[0])
37     return getattr(self, method)(*args[1:])
38
39   def _CommandifyName(self, name_string):
40     """Transforms a tool name like recursive-mirror to RecursiveMirror."""
41     return name_string.title().replace('-', '')
42
43   def _GetEnv(self, arch):
44     """Gets the saved environment from a file for a given architecture."""
45     # The environment is saved as an "environment block" (see CreateProcess
46     # and msvs_emulation for details). We convert to a dict here.
47     # Drop last 2 NULs, one for list terminator, one for trailing vs. separator.
48     pairs = open(arch).read()[:-2].split('\0')
49     kvs = [item.split('=', 1) for item in pairs]
50     return dict(kvs)
51
52   def ExecStamp(self, path):
53     """Simple stamp command."""
54     open(path, 'w').close()
55
56   def ExecRecursiveMirror(self, source, dest):
57     """Emulation of rm -rf out && cp -af in out."""
58     if os.path.exists(dest):
59       if os.path.isdir(dest):
60         shutil.rmtree(dest)
61       else:
62         os.unlink(dest)
63     if os.path.isdir(source):
64       shutil.copytree(source, dest)
65     else:
66       shutil.copy2(source, dest)
67
68   def ExecLinkWrapper(self, arch, *args):
69     """Filter diagnostic output from link that looks like:
70     '   Creating library ui.dll.lib and object ui.dll.exp'
71     This happens when there are exports from the dll or exe.
72     """
73     env = self._GetEnv(arch)
74     popen = subprocess.Popen(args, shell=True, env=env,
75                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
76     out, _ = popen.communicate()
77     for line in out.splitlines():
78       if not line.startswith('   Creating library '):
79         print line
80     return popen.returncode
81
82   def ExecManifestWrapper(self, arch, *args):
83     """Run manifest tool with environment set. Strip out undesirable warning
84     (some XML blocks are recognized by the OS loader, but not the manifest
85     tool)."""
86     env = self._GetEnv(arch)
87     popen = subprocess.Popen(args, shell=True, env=env,
88                              stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
89     out, _ = popen.communicate()
90     for line in out.splitlines():
91       if line and 'manifest authoring warning 81010002' not in line:
92         print line
93     return popen.returncode
94
95   def ExecManifestToRc(self, arch, *args):
96     """Creates a resource file pointing a SxS assembly manifest.
97     |args| is tuple containing path to resource file, path to manifest file
98     and resource name which can be "1" (for executables) or "2" (for DLLs)."""
99     manifest_path, resource_path, resource_name = args
100     with open(resource_path, 'wb') as output:
101       output.write('#include <windows.h>\n%s RT_MANIFEST "%s"' % (
102         resource_name,
103         os.path.abspath(manifest_path).replace('\\', '/')))
104
105   def ExecMidlWrapper(self, arch, outdir, tlb, h, dlldata, iid, proxy, idl,
106                       *flags):
107     """Filter noisy filenames output from MIDL compile step that isn't
108     quietable via command line flags.
109     """
110     args = ['midl', '/nologo'] + list(flags) + [
111         '/out', outdir,
112         '/tlb', tlb,
113         '/h', h,
114         '/dlldata', dlldata,
115         '/iid', iid,
116         '/proxy', proxy,
117         idl]
118     env = self._GetEnv(arch)
119     popen = subprocess.Popen(args, shell=True, env=env,
120                              stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
121     out, _ = popen.communicate()
122     # Filter junk out of stdout, and write filtered versions. Output we want
123     # to filter is pairs of lines that look like this:
124     # Processing C:\Program Files (x86)\Microsoft SDKs\...\include\objidl.idl
125     # objidl.idl
126     lines = out.splitlines()
127     prefix = 'Processing '
128     processing = set(os.path.basename(x) for x in lines if x.startswith(prefix))
129     for line in lines:
130       if not line.startswith(prefix) and line not in processing:
131         print line
132     return popen.returncode
133
134   def ExecAsmWrapper(self, arch, *args):
135     """Filter logo banner from invocations of asm.exe."""
136     env = self._GetEnv(arch)
137     # MSVS doesn't assemble x64 asm files.
138     if arch == 'environment.x64':
139       return 0
140     popen = subprocess.Popen(args, shell=True, env=env,
141                              stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
142     out, _ = popen.communicate()
143     for line in out.splitlines():
144       if (not line.startswith('Copyright (C) Microsoft Corporation') and
145           not line.startswith('Microsoft (R) Macro Assembler') and
146           not line.startswith(' Assembling: ') and
147           line):
148         print line
149     return popen.returncode
150
151   def ExecRcWrapper(self, arch, *args):
152     """Filter logo banner from invocations of rc.exe. Older versions of RC
153     don't support the /nologo flag."""
154     env = self._GetEnv(arch)
155     popen = subprocess.Popen(args, shell=True, env=env,
156                              stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
157     out, _ = popen.communicate()
158     for line in out.splitlines():
159       if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and
160           not line.startswith('Copyright (C) Microsoft Corporation') and
161           line):
162         print line
163     return popen.returncode
164
165   def ExecActionWrapper(self, arch, rspfile, *dir):
166     """Runs an action command line from a response file using the environment
167     for |arch|. If |dir| is supplied, use that as the working directory."""
168     env = self._GetEnv(arch)
169     args = open(rspfile).read()
170     dir = dir[0] if dir else None
171     popen = subprocess.Popen(args, shell=True, env=env, cwd=dir)
172     popen.wait()
173     return popen.returncode
174
175 if __name__ == '__main__':
176   sys.exit(main(sys.argv[1:]))