local-sdk.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env python
  2. # Copyright 2017 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. from __future__ import print_function
  6. import hashlib
  7. import json
  8. import os
  9. import shutil
  10. import subprocess
  11. import sys
  12. import tarfile
  13. import tempfile
  14. SELF_FILE = os.path.normpath(os.path.abspath(__file__))
  15. REPOSITORY_ROOT = os.path.abspath(
  16. os.path.join(os.path.dirname(__file__), '..', '..'))
  17. def Run(*args):
  18. print('Run:', ' '.join(args))
  19. subprocess.check_call(args)
  20. def EnsureEmptyDir(path):
  21. if os.path.isdir(path):
  22. shutil.rmtree(path)
  23. if not os.path.exists(path):
  24. print('Creating directory', path)
  25. os.makedirs(path)
  26. def BuildForArch(arch):
  27. Run('scripts/fx', '--dir', 'out/release-{}'.format(arch), 'set',
  28. 'terminal.qemu-{}'.format(arch), '--args=is_debug=false',
  29. '--args=build_sdk_archives=true')
  30. Run('scripts/fx', 'build', 'sdk', 'build/images')
  31. def _CopyFilesIntoExistingDirectory(src, dst):
  32. for entry in os.listdir(src):
  33. src_path = os.path.join(src, entry)
  34. dst_path = os.path.join(dst, entry)
  35. if os.path.isdir(src_path):
  36. if not os.path.exists(dst_path):
  37. os.mkdir(dst_path)
  38. _CopyFilesIntoExistingDirectory(src_path, dst_path)
  39. else:
  40. shutil.copy(src_path, dst_path)
  41. def main(args):
  42. if len(args) == 0 or len(args) > 2 or not os.path.isdir(args[0]):
  43. print("""usage: %s <path_to_fuchsia_tree> [architecture]""" % SELF_FILE)
  44. return 1
  45. target_archs = []
  46. if len(args) > 1:
  47. arch = args[1]
  48. if arch not in ['x64', 'arm64']:
  49. print('Unknown architecture: ' + arch)
  50. print('Must be "x64" or "arm64".')
  51. return 1
  52. target_archs = [arch]
  53. else:
  54. target_archs = ['x64', 'arm64']
  55. # Nuke the SDK from DEPS, put our just-built one there, and set a fake .hash
  56. # file. This means that on next gclient runhooks, we'll restore to the
  57. # real DEPS-determined SDK.
  58. sdk_output_dir = os.path.join(REPOSITORY_ROOT, 'third_party', 'fuchsia-sdk',
  59. 'sdk')
  60. images_output_dir = os.path.join(REPOSITORY_ROOT, 'third_party',
  61. 'fuchsia-sdk', 'images')
  62. EnsureEmptyDir(sdk_output_dir)
  63. EnsureEmptyDir(images_output_dir)
  64. original_dir = os.getcwd()
  65. fuchsia_root = os.path.abspath(args[0])
  66. merged_manifest = None
  67. manifest_parts = set()
  68. # Switch to the Fuchsia tree and build the SDKs.
  69. os.chdir(fuchsia_root)
  70. for arch in target_archs:
  71. BuildForArch(arch)
  72. arch_output_dir = os.path.join(fuchsia_root, 'out', 'release-' + arch)
  73. sdk_tarballs = ['core.tar.gz', 'core_testing.tar.gz']
  74. for sdk_tar in sdk_tarballs:
  75. sdk_tar_path = os.path.join(arch_output_dir, 'sdk', 'archive', sdk_tar)
  76. sdk_gn_dir = os.path.join(arch_output_dir, 'sdk', 'gn-' + sdk_tar)
  77. # Process the Core SDK tarball to generate the GN SDK.
  78. Run('scripts/sdk/gn/generate.py', '--archive', sdk_tar_path, '--output',
  79. sdk_gn_dir)
  80. _CopyFilesIntoExistingDirectory(sdk_gn_dir, sdk_output_dir)
  81. # Merge the manifests.
  82. manifest_path = os.path.join(sdk_output_dir, 'meta', 'manifest.json')
  83. if os.path.isfile(manifest_path):
  84. manifest = json.load(open(manifest_path))
  85. os.remove(manifest_path)
  86. if not merged_manifest:
  87. merged_manifest = manifest
  88. for part in manifest['parts']:
  89. manifest_parts.add(part['meta'])
  90. else:
  91. for part in manifest['parts']:
  92. if part['meta'] not in manifest_parts:
  93. manifest_parts.add(part['meta'])
  94. merged_manifest['parts'].append(part)
  95. arch_image_dir = os.path.join(images_output_dir, arch, 'qemu')
  96. os.mkdir(os.path.join(images_output_dir, arch))
  97. os.mkdir(arch_image_dir)
  98. # Stage the image directory using entries specified in the build image
  99. # manifest.
  100. images_json = json.load(open(os.path.join(arch_output_dir, 'images.json')))
  101. for entry in images_json:
  102. if entry['type'] not in ['blk', 'zbi', 'kernel']:
  103. continue
  104. # Not all images are actually built. Only copy images with the 'archive'
  105. # tag.
  106. if not entry.get('archive'):
  107. continue
  108. shutil.copyfile(
  109. os.path.join(arch_output_dir, entry['path']),
  110. os.path.join(arch_image_dir, entry['name']) + '.' + entry['type'])
  111. # Write merged manifest file.
  112. with open(manifest_path, 'w') as manifest_file:
  113. json.dump(merged_manifest, manifest_file, indent=2)
  114. print('Hashing sysroot...')
  115. # Hash the sysroot to catch updates to the headers, but don't hash the whole
  116. # tree, as we want to avoid rebuilding all of Chromium if it's only e.g. the
  117. # kernel blob has changed. https://crbug.com/793956.
  118. sysroot_hash_obj = hashlib.sha1()
  119. for root, dirs, files in os.walk(os.path.join(sdk_output_dir, 'sysroot')):
  120. for f in files:
  121. path = os.path.join(root, f)
  122. sysroot_hash_obj.update(path)
  123. sysroot_hash_obj.update(open(path, 'rb').read())
  124. sysroot_hash = sysroot_hash_obj.hexdigest()
  125. hash_filename = os.path.join(sdk_output_dir, '.hash')
  126. with open(hash_filename, 'w') as f:
  127. f.write('locally-built-sdk-' + sysroot_hash)
  128. # Clean up.
  129. os.chdir(original_dir)
  130. return 0
  131. if __name__ == '__main__':
  132. sys.exit(main(sys.argv[1:]))