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
21 from mozpack
.files
import FileFinder
22 from mozpack
.mozjar
import JarWriter
23 import mozpack
.path
as mozpath
25 SDK_RELEASE
= "10.0.17134.0"
29 "srcdir": "%(vs_path)s/DIA SDK",
34 "ignore": ("bin/arm/**",),
40 "pattern": "include/**",
44 "ignore": ("lib/arm/**",),
49 "srcdir": "%(vs_path)s/VC/Tools/MSVC/14.16.27023",
52 # ATL is needed by Breakpad.
54 "pattern": "atlmfc/include/**",
57 "pattern": "atlmfc/lib/arm64/atls.*",
60 "pattern": "atlmfc/lib/x64/atls.*",
63 "pattern": "atlmfc/lib/x86/atls.*",
65 # ARM64 PGO-instrumented builds require ARM64 pgort140.dll.
67 "pattern": "bin/arm64/pgort140.dll",
70 "pattern": "bin/Hostx64/**",
72 # 32-bit PGO-instrumented builds require 32-bit pgort140.dll.
74 "pattern": "bin/Hostx86/x86/pgort140.dll",
77 "pattern": "include/**",
91 "srcdir": "%(vs_path)s/VC/Redist/MSVC/14.16.27012",
92 "dstdir": "VC/redist",
95 "pattern": "arm64/Microsoft.VC141.CRT/**",
98 "pattern": "x64/Microsoft.VC141.CRT/**",
101 "pattern": "x86/Microsoft.VC141.CRT/**",
106 "srcdir": "%(sdk_path)s",
110 "pattern": "bin/%s/x64/**" % SDK_RELEASE
,
113 "pattern": "Include/%s/**" % SDK_RELEASE
,
116 "pattern": "Lib/%s/ucrt/arm64/**" % SDK_RELEASE
,
119 "pattern": "Lib/%s/ucrt/x64/**" % SDK_RELEASE
,
122 "pattern": "Lib/%s/ucrt/x86/**" % SDK_RELEASE
,
125 "pattern": "Lib/%s/um/arm64/**" % SDK_RELEASE
,
128 "pattern": "Lib/%s/um/x64/**" % SDK_RELEASE
,
131 "pattern": "Lib/%s/um/x86/**" % SDK_RELEASE
,
134 "pattern": "Redist/D3D/**",
137 "pattern": "Redist/ucrt/DLLs/x64/**",
140 "pattern": "Redist/ucrt/DLLs/x86/**",
148 """Resolve source locations of files.
150 Returns a 2-tuple of (Visual Studio Path, SDK Path).
152 pf
= os
.environ
.get("ProgramFiles(x86)")
155 'No "ProgramFiles(x86)" environment variable. '
156 "Not running on 64-bit Windows?"
159 vs_path
= os
.path
.join(pf
, "Microsoft Visual Studio", "2017", "Community")
160 if not os
.path
.exists(vs_path
):
162 "%s does not exist; Visual Studio 2017 not installed?" % vs_path
165 sdk_path
= os
.path
.join(pf
, "Windows Kits", "10")
166 if not os
.path
.exists(sdk_path
):
167 raise Exception("%s does not exist; Windows 10 SDK not installed?" % sdk_path
)
169 sdk_fullver_path
= os
.path
.join(sdk_path
, "Include", SDK_RELEASE
)
170 if not os
.path
.exists(sdk_fullver_path
):
172 "%s does not exist; Wrong SDK version installed?" % sdk_fullver_path
175 return vs_path
, sdk_path
179 """Resolve the files that constitute a standalone toolchain.
181 This is a generator of (dest path, file) where the destination
182 path is relative and the file instance is a BaseFile from mozpack.
184 vs_path
, sdk_path
= find_vs_paths()
186 for entry
in PATTERNS
:
187 fullpath
= entry
["srcdir"] % {
189 "sdk_path": sdk_path
,
191 for pattern
in entry
["files"]:
192 finder
= FileFinder(fullpath
, ignore
=pattern
.get("ignore", []))
193 for p
, f
in finder
.find(pattern
["pattern"]):
194 dstpath
= "%s/%s" % (entry
["dstdir"], p
)
195 yield dstpath
.encode("utf-8"), f
198 def resolve_files_and_hash(manifest
):
199 """Resolve files and hash their data.
201 This is a generator of 3-tuples of (relpath, data, mode).
203 As data is read, the manifest is populated with metadata.
204 Keys are set to the relative file path. Values are 2-tuples
205 of (data length, sha-256).
207 assert manifest
== {}
208 for p
, f
in resolve_files():
211 sha256
= hashlib
.sha256()
213 manifest
[p
] = (len(data
), sha256
.hexdigest().encode("utf-8"))
215 yield p
, data
, f
.mode
218 def format_manifest(manifest
):
219 """Return formatted SHA-256 manifests as a byte strings."""
221 for path
, (length
, sha256
) in sorted(manifest
.items()):
222 sha256_lines
.append(b
"%s\t%d\t%s" % (sha256
, length
, path
))
225 sha256_lines
.append(b
"")
227 return b
"\n".join(sha256_lines
)
230 def write_zip(zip_path
, prefix
=None):
231 """Write toolchain data to a zip file."""
232 prefix
= six
.ensure_binary(prefix
, encoding
="utf-8")
234 with
JarWriter(file=zip_path
, compress_level
=5) as zip:
236 for p
, data
, mode
in resolve_files_and_hash(manifest
):
239 p
= mozpath
.join(prefix
, p
)
241 zip.add(p
, data
, mode
=mode
)
243 sha256_manifest
= format_manifest(manifest
)
245 sdk_path
= b
"SDK_VERSION"
246 sha256_path
= b
"MANIFEST.SHA256"
248 sdk_path
= mozpath
.join(prefix
, sdk_path
)
249 sha256_path
= mozpath
.join(prefix
, sha256_path
)
251 zip.add(sdk_path
, SDK_RELEASE
.encode("utf-8"))
252 zip.add(sha256_path
, sha256_manifest
)
255 if __name__
== "__main__":
256 if len(sys
.argv
) != 3:
257 print("usage: %s create-zip <path-prefix>" % sys
.argv
[0])
260 assert sys
.argv
[1] == "create-zip"
261 prefix
= os
.path
.basename(sys
.argv
[2])
262 destzip
= "%s.zip" % sys
.argv
[2]
263 write_zip(destzip
, prefix
=prefix
)
265 sha1
= hashlib
.sha1()
266 sha256
= hashlib
.sha256()
267 sha512
= hashlib
.sha512()
269 with
open(destzip
, "rb") as fh
:
275 print("Hashes of %s (size=%d)" % (destzip
, len(data
)))
276 print("SHA-1: %s" % sha1
.hexdigest())
277 print("SHA-256: %s" % sha256
.hexdigest())
278 print("SHA-512: %s" % sha512
.hexdigest())