Upstream version 7.36.149.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     with open(json_data_file, 'r') as tempf:
34       toolchain_data = json.load(tempf)
35
36     toolchain = toolchain_data['path']
37     version = toolchain_data['version']
38     version_is_pro = version[-1] != 'e'
39     win8sdk = toolchain_data['win8sdk']
40     wdk = toolchain_data['wdk']
41     # TODO(scottmg): The order unfortunately matters in these. They should be
42     # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
43     # below). http://crbug.com/345992
44     vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
45
46     os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
47     os.environ['GYP_MSVS_VERSION'] = version
48     # We need to make sure windows_sdk_path is set to the automated
49     # toolchain values in GYP_DEFINES, but don't want to override any
50     # otheroptions.express
51     # values there.
52     gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
53     gyp_defines_dict['windows_sdk_path'] = win8sdk
54     os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
55         for k, v in gyp_defines_dict.iteritems())
56     os.environ['WINDOWSSDKDIR'] = win8sdk
57     os.environ['WDK_DIR'] = wdk
58     # Include the VS runtime in the PATH in case it's not machine-installed.
59     runtime_path = ';'.join(vs2013_runtime_dll_dirs)
60     os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
61   return vs2013_runtime_dll_dirs
62
63
64 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
65   """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
66   directory so that even if not system-installed, built binaries are likely to
67   be able to run.
68
69   This needs to be run after gyp has been run so that the expected target
70   output directories are already created.
71   """
72   assert sys.platform.startswith(('win32', 'cygwin'))
73
74   def copy_runtime(target_dir, source_dir, dll_pattern):
75     """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
76     exist, but the target directory does exist."""
77     for which in ('p', 'r'):
78       dll = dll_pattern % which
79       target = os.path.join(target_dir, dll)
80       source = os.path.join(source_dir, dll)
81       # If gyp generated to that output dir, and the runtime isn't already
82       # there, then copy it over.
83       if (os.path.isdir(target_dir) and
84           (not os.path.isfile(target) or
85             os.stat(target).st_mtime != os.stat(source).st_mtime)):
86         print 'Copying %s to %s...' % (source, target)
87         if os.path.exists(target):
88           os.unlink(target)
89         shutil.copy2(source, target)
90
91   x86, x64 = runtime_dirs
92   out_debug = os.path.join(output_dir, 'Debug')
93   out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
94   out_release = os.path.join(output_dir, 'Release')
95   out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
96   out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
97   out_release_x64 = os.path.join(output_dir, 'Release_x64')
98
99   if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
100     os.makedirs(out_debug_nacl64)
101   if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
102     os.makedirs(out_release_nacl64)
103   copy_runtime(out_debug,          x86, 'msvc%s120d.dll')
104   copy_runtime(out_release,        x86, 'msvc%s120.dll')
105   copy_runtime(out_debug_x64,      x64, 'msvc%s120d.dll')
106   copy_runtime(out_release_x64,    x64, 'msvc%s120.dll')
107   copy_runtime(out_debug_nacl64,   x64, 'msvc%s120d.dll')
108   copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
109
110
111 def _GetDesiredVsToolchainHashes():
112   """Load a list of SHA1s corresponding to the toolchains that we want installed
113   to build with."""
114   sha1path = os.path.join(script_dir, 'toolchain_vs2013.hash')
115   with open(sha1path, 'rb') as f:
116     return f.read().strip().splitlines()
117
118
119 def Update():
120   """Requests an update of the toolchain to the specific hashes we have at
121   this revision. The update outputs a .json of the various configuration
122   information required to pass to gyp which we use in |GetToolchainDir()|.
123   """
124   depot_tools_win_toolchain = \
125       bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
126   if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
127     import find_depot_tools
128     depot_tools_path = find_depot_tools.add_depot_tools_to_path()
129     json_data_file = os.path.join(script_dir, 'win_toolchain.json')
130     get_toolchain_args = [
131         sys.executable,
132         os.path.join(depot_tools_path,
133                     'win_toolchain',
134                     'get_toolchain_if_necessary.py'),
135         '--output-json', json_data_file,
136       ] + _GetDesiredVsToolchainHashes()
137     subprocess.check_call(get_toolchain_args)
138
139   return 0
140
141
142 def GetToolchainDir():
143   """Gets location information about the current toolchain (must have been
144   previously updated by 'update')."""
145   SetEnvironmentAndGetRuntimeDllDirs()
146   print '["%s", "%s"]' % (
147       os.environ['GYP_MSVS_OVERRIDE_PATH'], os.environ['WINDOWSSDKDIR'])
148
149
150 def main():
151   if not sys.platform.startswith(('win32', 'cygwin')):
152     return 0
153   commands = {
154       'update': Update,
155       'get_toolchain_dir': GetToolchainDir,
156       # TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
157       # CopyVsRuntimeDlls via import, currently).
158   }
159   if len(sys.argv) < 2 or sys.argv[1] not in commands:
160     print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
161     return 1
162   return commands[sys.argv[1]]()
163
164
165 if __name__ == '__main__':
166   sys.exit(main())