Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / build / vs_toolchain.py
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import json
6 import os
7 import pipes
8 import shutil
9 import subprocess
10 import sys
11
12
13 script_dir = os.path.dirname(os.path.realpath(__file__))
14 chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
15 SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16 sys.path.insert(1, os.path.join(chrome_src, 'tools'))
17 sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
18 json_data_file = os.path.join(script_dir, 'win_toolchain.json')
19
20
21 import gyp
22
23
24 def SetEnvironmentAndGetRuntimeDllDirs():
25   """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
26   returns the location of the VS runtime DLLs so they can be copied into
27   the output directory after gyp generation.
28   """
29   vs2013_runtime_dll_dirs = None
30   depot_tools_win_toolchain = \
31       bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
32   if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
33     if not os.path.exists(json_data_file):
34       Update()
35     with open(json_data_file, 'r') as tempf:
36       toolchain_data = json.load(tempf)
37
38     toolchain = toolchain_data['path']
39     version = toolchain_data['version']
40     version_is_pro = version[-1] != 'e'
41     win8sdk = toolchain_data['win8sdk']
42     wdk = toolchain_data['wdk']
43     # TODO(scottmg): The order unfortunately matters in these. They should be
44     # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
45     # below). http://crbug.com/345992
46     vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
47
48     os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
49     os.environ['GYP_MSVS_VERSION'] = version
50     # We need to make sure windows_sdk_path is set to the automated
51     # toolchain values in GYP_DEFINES, but don't want to override any
52     # otheroptions.express
53     # values there.
54     gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
55     gyp_defines_dict['windows_sdk_path'] = win8sdk
56     os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
57         for k, v in gyp_defines_dict.iteritems())
58     os.environ['WINDOWSSDKDIR'] = win8sdk
59     os.environ['WDK_DIR'] = wdk
60     # Include the VS runtime in the PATH in case it's not machine-installed.
61     runtime_path = ';'.join(vs2013_runtime_dll_dirs)
62     os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
63   return vs2013_runtime_dll_dirs
64
65
66 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
67   """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
68   directory so that even if not system-installed, built binaries are likely to
69   be able to run.
70
71   This needs to be run after gyp has been run so that the expected target
72   output directories are already created.
73   """
74   assert sys.platform.startswith(('win32', 'cygwin'))
75
76   def copy_runtime_impl(target, source):
77     """Copy |source| to |target| if it doesn't already exist or if it need to be
78     updated.
79     """
80     if (os.path.isdir(os.path.dirname(target)) and
81         (not os.path.isfile(target) or
82           os.stat(target).st_mtime != os.stat(source).st_mtime)):
83       print 'Copying %s to %s...' % (source, target)
84       if os.path.exists(target):
85         os.unlink(target)
86       shutil.copy2(source, target)
87
88   def copy_runtime(target_dir, source_dir, dll_pattern):
89     """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
90     exist, but the target directory does exist."""
91     for which in ('p', 'r'):
92       dll = dll_pattern % which
93       target = os.path.join(target_dir, dll)
94       source = os.path.join(source_dir, dll)
95       copy_runtime_impl(target, source)
96
97   x86, x64 = runtime_dirs
98   out_debug = os.path.join(output_dir, 'Debug')
99   out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
100   out_release = os.path.join(output_dir, 'Release')
101   out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
102   out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
103   out_release_x64 = os.path.join(output_dir, 'Release_x64')
104
105   if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
106     os.makedirs(out_debug_nacl64)
107   if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
108     os.makedirs(out_release_nacl64)
109   copy_runtime(out_debug,          x86, 'msvc%s120d.dll')
110   copy_runtime(out_release,        x86, 'msvc%s120.dll')
111   copy_runtime(out_debug_x64,      x64, 'msvc%s120d.dll')
112   copy_runtime(out_release_x64,    x64, 'msvc%s120.dll')
113   copy_runtime(out_debug_nacl64,   x64, 'msvc%s120d.dll')
114   copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
115
116   # Copy the PGO runtime library to the release directories.
117   if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
118     pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
119                                        'VC', 'bin')
120     pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
121     pgo_runtime_dll = 'pgort120.dll'
122     source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
123     if os.path.exists(source_x86):
124       copy_runtime_impl(os.path.join(out_release, pgo_runtime_dll), source_x86)
125     source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
126     if os.path.exists(source_x64):
127       copy_runtime_impl(os.path.join(out_release_x64, pgo_runtime_dll),
128                         source_x64)
129
130
131 def _GetDesiredVsToolchainHashes():
132   """Load a list of SHA1s corresponding to the toolchains that we want installed
133   to build with."""
134   sha1path = os.path.join(script_dir,
135                           '..', 'buildtools', 'toolchain_vs2013.hash')
136   with open(sha1path, 'rb') as f:
137     return f.read().strip().splitlines()
138
139
140 def Update():
141   """Requests an update of the toolchain to the specific hashes we have at
142   this revision. The update outputs a .json of the various configuration
143   information required to pass to gyp which we use in |GetToolchainDir()|.
144   """
145   depot_tools_win_toolchain = \
146       bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
147   if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
148     import find_depot_tools
149     depot_tools_path = find_depot_tools.add_depot_tools_to_path()
150     json_data_file = os.path.join(script_dir, 'win_toolchain.json')
151     get_toolchain_args = [
152         sys.executable,
153         os.path.join(depot_tools_path,
154                     'win_toolchain',
155                     'get_toolchain_if_necessary.py'),
156         '--output-json', json_data_file,
157       ] + _GetDesiredVsToolchainHashes()
158     subprocess.check_call(get_toolchain_args)
159
160   return 0
161
162
163 def GetToolchainDir():
164   """Gets location information about the current toolchain (must have been
165   previously updated by 'update'). This is used for the GN build."""
166   SetEnvironmentAndGetRuntimeDllDirs()
167   print '''vs_path = "%s"
168 sdk_path = "%s"
169 vs_version = "%s"
170 wdk_dir = "%s"
171 ''' % (
172       os.environ['GYP_MSVS_OVERRIDE_PATH'],
173       os.environ['WINDOWSSDKDIR'],
174       os.environ['GYP_MSVS_VERSION'],
175       os.environ.get('WDK_DIR', ''))
176
177
178 def main():
179   if not sys.platform.startswith(('win32', 'cygwin')):
180     return 0
181   commands = {
182       'update': Update,
183       'get_toolchain_dir': GetToolchainDir,
184       # TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
185       # CopyVsRuntimeDlls via import, currently).
186   }
187   if len(sys.argv) < 2 or sys.argv[1] not in commands:
188     print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
189     return 1
190   return commands[sys.argv[1]]()
191
192
193 if __name__ == '__main__':
194   sys.exit(main())