1 #!/usr/bin/env python2.7
2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 # This script is used to create and manipulate archives containing
7 # files necessary to build Firefox on Windows (referred to as the
8 # "Windows toolchain").
10 # When updating behavior of this script, remember to update the docs
11 # in ``build/docs/toolchains.rst``.
13 from __future__
import absolute_import
, unicode_literals
19 from mozpack
.files
import (
22 from mozpack
.mozjar
import (
25 import mozpack
.path
as mozpath
27 SDK_RELEASE
= '10.0.17134.0'
31 'srcdir': '%(vs_path)s/DIA SDK',
44 'pattern': 'include/**',
55 'srcdir': '%(vs_path)s/VC/Tools/MSVC/14.15.26726',
58 # ATL is needed by Breakpad.
60 'pattern': 'atlmfc/include/**',
63 'pattern': 'atlmfc/lib/x86/atls.*',
66 'pattern': 'atlmfc/lib/x64/atls.*',
69 'pattern': 'bin/Hostx64/**',
71 # 32-bit PGO-instrumented builds require 32-bit pgort140.dll.
73 'pattern': 'bin/Hostx86/x86/pgort140.dll',
76 'pattern': 'include/**',
89 'srcdir': '%(vs_path)s/VC/Redist/MSVC/14.15.26706',
90 'dstdir': 'VC/redist',
93 'pattern': 'x64/Microsoft.VC141.CRT/**',
96 'pattern': 'x86/Microsoft.VC141.CRT/**',
101 'srcdir': '%(sdk_path)s',
105 'pattern': 'bin/%s/x64/**' % SDK_RELEASE
,
108 'pattern': 'Include/%s/**' % SDK_RELEASE
,
111 'pattern': 'Lib/%s/ucrt/x64/**' % SDK_RELEASE
,
114 'pattern': 'Lib/%s/ucrt/x86/**' % SDK_RELEASE
,
117 'pattern': 'Lib/%s/um/x64/**' % SDK_RELEASE
,
120 'pattern': 'Lib/%s/um/x86/**' % SDK_RELEASE
,
123 'pattern': 'Redist/D3D/**',
126 'pattern': 'Redist/ucrt/DLLs/x64/**',
129 'pattern': 'Redist/ucrt/DLLs/x86/**',
137 """Resolve source locations of files.
139 Returns a 2-tuple of (Visual Studio Path, SDK Path).
141 pf
= os
.environ
.get('ProgramFiles(x86)')
143 raise Exception('No "ProgramFiles(x86)" environment variable. '
144 'Not running on 64-bit Windows?')
146 vs_path
= os
.path
.join(pf
, 'Microsoft Visual Studio', '2017', 'Community')
147 if not os
.path
.exists(vs_path
):
148 raise Exception('%s does not exist; Visual Studio 2017 not installed?' %
151 sdk_path
= os
.path
.join(pf
, 'Windows Kits', '10')
152 if not os
.path
.exists(sdk_path
):
153 raise Exception('%s does not exist; Windows 10 SDK not installed?' %
156 sdk_fullver_path
= os
.path
.join(sdk_path
, 'Include', SDK_RELEASE
)
157 if not os
.path
.exists(sdk_fullver_path
):
158 raise Exception('%s does not exist; Wrong SDK version installed?' %
161 return vs_path
, sdk_path
165 """Resolve the files that constitute a standalone toolchain.
167 This is a generator of (dest path, file) where the destination
168 path is relative and the file instance is a BaseFile from mozpack.
170 vs_path
, sdk_path
= find_vs_paths()
172 for entry
in PATTERNS
:
173 fullpath
= entry
['srcdir'] % {
175 'sdk_path': sdk_path
,
177 for pattern
in entry
['files']:
178 finder
= FileFinder(fullpath
, ignore
=pattern
.get('ignore', []))
179 for p
, f
in finder
.find(pattern
['pattern']):
180 dstpath
= '%s/%s' % (entry
['dstdir'], p
)
181 yield dstpath
.encode('utf-8'), f
184 def resolve_files_and_hash(manifest
):
185 """Resolve files and hash their data.
187 This is a generator of 3-tuples of (relpath, data, mode).
189 As data is read, the manifest is populated with metadata.
190 Keys are set to the relative file path. Values are 2-tuples
191 of (data length, sha-256).
193 assert manifest
== {}
194 for p
, f
in resolve_files():
197 sha256
= hashlib
.sha256()
199 manifest
[p
] = (len(data
), sha256
.hexdigest())
201 yield p
, data
, f
.mode
204 def format_manifest(manifest
):
205 """Return formatted SHA-256 manifests as a byte strings."""
207 for path
, (length
, sha256
) in sorted(manifest
.items()):
208 sha256_lines
.append(b
'%s\t%d\t%s' % (sha256
, length
, path
))
211 sha256_lines
.append(b
'')
213 return b
'\n'.join(sha256_lines
)
216 def write_zip(zip_path
, prefix
=None):
217 """Write toolchain data to a zip file."""
218 if isinstance(prefix
, unicode): # noqa Special case for Python 2
219 prefix
= prefix
.encode('utf-8')
221 with
JarWriter(file=zip_path
, optimize
=False, compress_level
=5) as zip:
223 for p
, data
, mode
in resolve_files_and_hash(manifest
):
226 p
= mozpath
.join(prefix
, p
)
228 zip.add(p
, data
, mode
=mode
)
230 sha256_manifest
= format_manifest(manifest
)
232 sdk_path
= b
'SDK_VERSION'
233 sha256_path
= b
'MANIFEST.SHA256'
235 sdk_path
= mozpath
.join(prefix
, sdk_path
)
236 sha256_path
= mozpath
.join(prefix
, sha256_path
)
238 zip.add(sdk_path
, SDK_RELEASE
.encode('utf-8'))
239 zip.add(sha256_path
, sha256_manifest
)
242 if __name__
== '__main__':
243 if len(sys
.argv
) != 3:
244 print('usage: %s create-zip <path-prefix>' % sys
.argv
[0])
247 assert sys
.argv
[1] == 'create-zip'
248 prefix
= os
.path
.basename(sys
.argv
[2])
249 destzip
= '%s.zip' % sys
.argv
[2]
250 write_zip(destzip
, prefix
=prefix
)
252 sha1
= hashlib
.sha1()
253 sha256
= hashlib
.sha256()
254 sha512
= hashlib
.sha512()
256 with
open(destzip
, 'rb') as fh
:
262 print('Hashes of %s (size=%d)' % (destzip
, len(data
)))
263 print('SHA-1: %s' % sha1
.hexdigest())
264 print('SHA-256: %s' % sha256
.hexdigest())
265 print('SHA-512: %s' % sha512
.hexdigest())