xref: /aosp_15_r20/external/openscreen/build/scripts/install-sysroot.py (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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