1*3f982cf4SFabien Sanglard#!/usr/bin/env python3 2*3f982cf4SFabien Sanglard 3*3f982cf4SFabien Sanglard# Copyright 2019 The Chromium Authors. All rights reserved. 4*3f982cf4SFabien Sanglard# Use of this source code is governed by a BSD-style license that can be 5*3f982cf4SFabien Sanglard# found in the LICENSE file. 6*3f982cf4SFabien Sanglard 7*3f982cf4SFabien Sanglard""" 8*3f982cf4SFabien SanglardInstall Debian sysroots for cross compiling Open Screen. 9*3f982cf4SFabien Sanglard""" 10*3f982cf4SFabien Sanglard 11*3f982cf4SFabien Sanglard# The sysroot is needed to ensure that binaries that get built will run on 12*3f982cf4SFabien Sanglard# the oldest stable version of Debian that we currently support. 13*3f982cf4SFabien Sanglard# This script can be run manually but is more often run as part of gclient 14*3f982cf4SFabien Sanglard# hooks. When run from hooks this script is a no-op on non-linux platforms. 15*3f982cf4SFabien Sanglard 16*3f982cf4SFabien Sanglard# The sysroot image could be constructed from scratch based on the current state 17*3f982cf4SFabien Sanglard# of the Debian archive but for consistency we use a pre-built root image (we 18*3f982cf4SFabien Sanglard# don't want upstream changes to Debian to affect the build until we 19*3f982cf4SFabien Sanglard# choose to pull them in). The sysroot images are stored in Chrome's common 20*3f982cf4SFabien Sanglard# data storage, and the sysroots.json file should be kept in sync with Chrome's 21*3f982cf4SFabien Sanglard# copy of it. 22*3f982cf4SFabien Sanglard 23*3f982cf4SFabien Sanglardfrom __future__ import print_function 24*3f982cf4SFabien Sanglard 25*3f982cf4SFabien Sanglardimport hashlib 26*3f982cf4SFabien Sanglardimport json 27*3f982cf4SFabien Sanglardimport platform 28*3f982cf4SFabien Sanglardimport argparse 29*3f982cf4SFabien Sanglardimport os 30*3f982cf4SFabien Sanglardimport re 31*3f982cf4SFabien Sanglardimport shutil 32*3f982cf4SFabien Sanglardimport subprocess 33*3f982cf4SFabien Sanglardimport sys 34*3f982cf4SFabien Sanglardtry: 35*3f982cf4SFabien Sanglard # For Python 3.0 and later 36*3f982cf4SFabien Sanglard from urllib.request import urlopen 37*3f982cf4SFabien Sanglardexcept ImportError: 38*3f982cf4SFabien Sanglard # Fall back to Python 2's urllib2 39*3f982cf4SFabien Sanglard from urllib2 import urlopen 40*3f982cf4SFabien Sanglard 41*3f982cf4SFabien SanglardSCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 42*3f982cf4SFabien SanglardPARENT_DIR = os.path.dirname(SCRIPT_DIR) 43*3f982cf4SFabien SanglardURL_PREFIX = 'https://storage.googleapis.com' 44*3f982cf4SFabien SanglardURL_PATH = 'openscreen-sysroots' 45*3f982cf4SFabien Sanglard 46*3f982cf4SFabien SanglardVALID_ARCHS = ('arm', 'arm64') 47*3f982cf4SFabien SanglardVALID_PLATFORMS = ('stretch', 'sid') 48*3f982cf4SFabien Sanglard 49*3f982cf4SFabien Sanglard 50*3f982cf4SFabien Sanglardclass Error(Exception): 51*3f982cf4SFabien Sanglard pass 52*3f982cf4SFabien Sanglard 53*3f982cf4SFabien Sanglard 54*3f982cf4SFabien Sanglarddef GetSha1(filename): 55*3f982cf4SFabien Sanglard """Generates a SHA1 hash for validating download. Done in chunks to avoid 56*3f982cf4SFabien Sanglard excess memory usage.""" 57*3f982cf4SFabien Sanglard BLOCKSIZE = 1024 * 1024 58*3f982cf4SFabien Sanglard sha1 = hashlib.sha1() 59*3f982cf4SFabien Sanglard with open(filename, 'rb') as f: 60*3f982cf4SFabien Sanglard chunk = f.read(BLOCKSIZE) 61*3f982cf4SFabien Sanglard while chunk: 62*3f982cf4SFabien Sanglard sha1.update(chunk) 63*3f982cf4SFabien Sanglard chunk = f.read(BLOCKSIZE) 64*3f982cf4SFabien Sanglard return sha1.hexdigest() 65*3f982cf4SFabien Sanglard 66*3f982cf4SFabien Sanglard 67*3f982cf4SFabien Sanglarddef GetSysrootDict(target_platform, target_arch): 68*3f982cf4SFabien Sanglard """Gets the sysroot information for a given platform and arch from the 69*3f982cf4SFabien Sanglard sysroots.json file.""" 70*3f982cf4SFabien Sanglard if target_arch not in VALID_ARCHS: 71*3f982cf4SFabien Sanglard raise Error('Unknown architecture: %s' % target_arch) 72*3f982cf4SFabien Sanglard 73*3f982cf4SFabien Sanglard sysroots_file = os.path.join(SCRIPT_DIR, 'sysroots.json') 74*3f982cf4SFabien Sanglard sysroots = json.load(open(sysroots_file)) 75*3f982cf4SFabien Sanglard sysroot_key = '%s_%s' % (target_platform, target_arch) 76*3f982cf4SFabien Sanglard if sysroot_key not in sysroots: 77*3f982cf4SFabien Sanglard raise Error('No sysroot for: %s' % (sysroot_key)) 78*3f982cf4SFabien Sanglard return sysroots[sysroot_key] 79*3f982cf4SFabien Sanglard 80*3f982cf4SFabien Sanglard 81*3f982cf4SFabien Sanglarddef DownloadFile(url, local_path): 82*3f982cf4SFabien Sanglard """Uses urllib to download a remote file into local_path.""" 83*3f982cf4SFabien Sanglard for _ in range(3): 84*3f982cf4SFabien Sanglard try: 85*3f982cf4SFabien Sanglard response = urlopen(url) 86*3f982cf4SFabien Sanglard with open(local_path, "wb") as f: 87*3f982cf4SFabien Sanglard f.write(response.read()) 88*3f982cf4SFabien Sanglard break 89*3f982cf4SFabien Sanglard except Exception: 90*3f982cf4SFabien Sanglard pass 91*3f982cf4SFabien Sanglard else: 92*3f982cf4SFabien Sanglard raise Error('Failed to download %s' % url) 93*3f982cf4SFabien Sanglard 94*3f982cf4SFabien Sanglarddef ValidateFile(local_path, expected_sum): 95*3f982cf4SFabien Sanglard """Generates the SHA1 hash of a local file to compare with an expected 96*3f982cf4SFabien Sanglard hashsum.""" 97*3f982cf4SFabien Sanglard sha1sum = GetSha1(local_path) 98*3f982cf4SFabien Sanglard if sha1sum != expected_sum: 99*3f982cf4SFabien Sanglard raise Error('Tarball sha1sum is wrong.' 100*3f982cf4SFabien Sanglard 'Expected %s, actual: %s' % (expected_sum, sha1sum)) 101*3f982cf4SFabien Sanglard 102*3f982cf4SFabien Sanglarddef InstallSysroot(target_platform, target_arch): 103*3f982cf4SFabien Sanglard """Downloads, validates, unpacks, and installs a sysroot image.""" 104*3f982cf4SFabien Sanglard sysroot_dict = GetSysrootDict(target_platform, target_arch) 105*3f982cf4SFabien Sanglard tarball_filename = sysroot_dict['Tarball'] 106*3f982cf4SFabien Sanglard tarball_sha1sum = sysroot_dict['Sha1Sum'] 107*3f982cf4SFabien Sanglard 108*3f982cf4SFabien Sanglard sysroot = os.path.join(PARENT_DIR, sysroot_dict['SysrootDir']) 109*3f982cf4SFabien Sanglard 110*3f982cf4SFabien Sanglard url = '%s/%s/%s/%s' % (URL_PREFIX, URL_PATH, tarball_sha1sum, 111*3f982cf4SFabien Sanglard tarball_filename) 112*3f982cf4SFabien Sanglard 113*3f982cf4SFabien Sanglard stamp = os.path.join(sysroot, '.stamp') 114*3f982cf4SFabien Sanglard if os.path.exists(stamp): 115*3f982cf4SFabien Sanglard with open(stamp) as s: 116*3f982cf4SFabien Sanglard if s.read() == url: 117*3f982cf4SFabien Sanglard return 118*3f982cf4SFabien Sanglard 119*3f982cf4SFabien Sanglard if os.path.isdir(sysroot): 120*3f982cf4SFabien Sanglard shutil.rmtree(sysroot) 121*3f982cf4SFabien Sanglard os.mkdir(sysroot) 122*3f982cf4SFabien Sanglard 123*3f982cf4SFabien Sanglard tarball_path = os.path.join(sysroot, tarball_filename) 124*3f982cf4SFabien Sanglard DownloadFile(url, tarball_path) 125*3f982cf4SFabien Sanglard ValidateFile(tarball_path, tarball_sha1sum) 126*3f982cf4SFabien Sanglard subprocess.check_call(['tar', 'xf', tarball_path, '-C', sysroot]) 127*3f982cf4SFabien Sanglard os.remove(tarball_path) 128*3f982cf4SFabien Sanglard 129*3f982cf4SFabien Sanglard with open(stamp, 'w') as s: 130*3f982cf4SFabien Sanglard s.write(url) 131*3f982cf4SFabien Sanglard 132*3f982cf4SFabien Sanglard 133*3f982cf4SFabien Sanglarddef parse_args(args): 134*3f982cf4SFabien Sanglard """Parses the passed in arguments into an object.""" 135*3f982cf4SFabien Sanglard p = argparse.ArgumentParser() 136*3f982cf4SFabien Sanglard p.add_argument( 137*3f982cf4SFabien Sanglard 'arch', 138*3f982cf4SFabien Sanglard help='Sysroot architecture: %s' % ', '.join(VALID_ARCHS)) 139*3f982cf4SFabien Sanglard p.add_argument( 140*3f982cf4SFabien Sanglard 'platform', 141*3f982cf4SFabien Sanglard help='Sysroot platform: %s' % ', '.join(VALID_PLATFORMS)) 142*3f982cf4SFabien Sanglard p.add_argument( 143*3f982cf4SFabien Sanglard '--print-hash', action="store_true", 144*3f982cf4SFabien Sanglard help='Print the hash of the sysroot for the specified arch.') 145*3f982cf4SFabien Sanglard 146*3f982cf4SFabien Sanglard return p.parse_args(args) 147*3f982cf4SFabien Sanglard 148*3f982cf4SFabien Sanglard 149*3f982cf4SFabien Sanglarddef main(args): 150*3f982cf4SFabien Sanglard if not (sys.platform.startswith('linux') or sys.platform == 'darwin'): 151*3f982cf4SFabien Sanglard print('Unsupported platform. Only Linux and Mac OS X are supported.') 152*3f982cf4SFabien Sanglard return 1 153*3f982cf4SFabien Sanglard 154*3f982cf4SFabien Sanglard parsed_args = parse_args(args) 155*3f982cf4SFabien Sanglard if parsed_args.print_hash: 156*3f982cf4SFabien Sanglard print(GetSysrootDict(parsed_args.platform, parsed_args.arch)['Sha1Sum']) 157*3f982cf4SFabien Sanglard 158*3f982cf4SFabien Sanglard InstallSysroot(parsed_args.platform, parsed_args.arch) 159*3f982cf4SFabien Sanglard return 0 160*3f982cf4SFabien Sanglard 161*3f982cf4SFabien Sanglard 162*3f982cf4SFabien Sanglardif __name__ == '__main__': 163*3f982cf4SFabien Sanglard try: 164*3f982cf4SFabien Sanglard sys.exit(main(sys.argv[1:])) 165*3f982cf4SFabien Sanglard except Error as e: 166*3f982cf4SFabien Sanglard sys.stderr.write('Installing sysroot error: {}\n'.format(e)) 167*3f982cf4SFabien Sanglard sys.exit(1) 168