xref: /aosp_15_r20/external/gsc-utils/firmware_builder.py (revision 4f2df630800bdcf1d4f0decf95d8a1cb87344f5f)
1*4f2df630SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*4f2df630SAndroid Build Coastguard Worker# Copyright 2023 The ChromiumOS Authors
3*4f2df630SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
4*4f2df630SAndroid Build Coastguard Worker# found in the LICENSE file.
5*4f2df630SAndroid Build Coastguard Worker
6*4f2df630SAndroid Build Coastguard Worker"""Build, bundle, or test all of the EC boards.
7*4f2df630SAndroid Build Coastguard Worker
8*4f2df630SAndroid Build Coastguard WorkerThis is the entry point for the custom firmware builder workflow recipe.  It
9*4f2df630SAndroid Build Coastguard Workergets invoked by chromite/api/controller/firmware.py.
10*4f2df630SAndroid Build Coastguard Worker"""
11*4f2df630SAndroid Build Coastguard Worker
12*4f2df630SAndroid Build Coastguard Workerimport argparse
13*4f2df630SAndroid Build Coastguard Workerimport multiprocessing
14*4f2df630SAndroid Build Coastguard Workerimport os
15*4f2df630SAndroid Build Coastguard Workerimport subprocess
16*4f2df630SAndroid Build Coastguard Workerimport sys
17*4f2df630SAndroid Build Coastguard Worker
18*4f2df630SAndroid Build Coastguard Worker# pylint: disable=import-error
19*4f2df630SAndroid Build Coastguard Workerfrom google.protobuf import json_format
20*4f2df630SAndroid Build Coastguard Worker
21*4f2df630SAndroid Build Coastguard Worker# TODO(crbug/1181505): Code outside of chromite should not be importing from
22*4f2df630SAndroid Build Coastguard Worker# chromite.api.gen.  Import json_format after that so we get the matching one.
23*4f2df630SAndroid Build Coastguard Workerfrom chromite.api.gen.chromite.api import firmware_pb2
24*4f2df630SAndroid Build Coastguard Worker
25*4f2df630SAndroid Build Coastguard Worker
26*4f2df630SAndroid Build Coastguard Workerdef build(opts):
27*4f2df630SAndroid Build Coastguard Worker    """Builds all targets in extra/usb_updater
28*4f2df630SAndroid Build Coastguard Worker
29*4f2df630SAndroid Build Coastguard Worker    Note that when we are building unit tests for code coverage, we don't
30*4f2df630SAndroid Build Coastguard Worker    need this step. It builds EC **firmware** targets, but unit tests with
31*4f2df630SAndroid Build Coastguard Worker    code coverage are all host-based. So if the --code-coverage flag is set,
32*4f2df630SAndroid Build Coastguard Worker    we don't need to build the firmware targets and we can return without
33*4f2df630SAndroid Build Coastguard Worker    doing anything but creating the metrics file and giving an informational
34*4f2df630SAndroid Build Coastguard Worker    message.
35*4f2df630SAndroid Build Coastguard Worker    """
36*4f2df630SAndroid Build Coastguard Worker    # Write empty metrics file as there is nothing to report but recipe needs
37*4f2df630SAndroid Build Coastguard Worker    # the file to exist.
38*4f2df630SAndroid Build Coastguard Worker    metrics = firmware_pb2.FwBuildMetricList()  # pylint: disable=no-member
39*4f2df630SAndroid Build Coastguard Worker    with open(opts.metrics, "w", encoding="utf-8") as f:
40*4f2df630SAndroid Build Coastguard Worker        f.write(json_format.MessageToJson(metrics))
41*4f2df630SAndroid Build Coastguard Worker
42*4f2df630SAndroid Build Coastguard Worker    cmd = [
43*4f2df630SAndroid Build Coastguard Worker        "make",
44*4f2df630SAndroid Build Coastguard Worker        "BOARD=cr50",
45*4f2df630SAndroid Build Coastguard Worker        f"-j{opts.cpus}",
46*4f2df630SAndroid Build Coastguard Worker        "-C",
47*4f2df630SAndroid Build Coastguard Worker        "extra/usb_updater",
48*4f2df630SAndroid Build Coastguard Worker    ]
49*4f2df630SAndroid Build Coastguard Worker    print(f'# Running {" ".join(cmd)}.')
50*4f2df630SAndroid Build Coastguard Worker    subprocess.run(cmd, cwd=os.path.dirname(__file__), check=True)
51*4f2df630SAndroid Build Coastguard Worker
52*4f2df630SAndroid Build Coastguard Worker
53*4f2df630SAndroid Build Coastguard Workerdef bundle(opts):
54*4f2df630SAndroid Build Coastguard Worker    """Bundles all of the EC targets."""
55*4f2df630SAndroid Build Coastguard Worker    # Provide an empty metadata file since the file is required, but we
56*4f2df630SAndroid Build Coastguard Worker    # don't have any artifacts that needs to be uploadeddd
57*4f2df630SAndroid Build Coastguard Worker    if opts.metadata:
58*4f2df630SAndroid Build Coastguard Worker        metadata = (
59*4f2df630SAndroid Build Coastguard Worker            firmware_pb2.FirmwareArtifactInfo()  # pylint: disable=no-member
60*4f2df630SAndroid Build Coastguard Worker        )
61*4f2df630SAndroid Build Coastguard Worker        with open(opts.metadata, "w", encoding="utf-8") as f:
62*4f2df630SAndroid Build Coastguard Worker            f.write(json_format.MessageToJson(metadata))
63*4f2df630SAndroid Build Coastguard Worker
64*4f2df630SAndroid Build Coastguard Worker
65*4f2df630SAndroid Build Coastguard Workerdef test(opts):
66*4f2df630SAndroid Build Coastguard Worker    """Tests all of the EC targets."""
67*4f2df630SAndroid Build Coastguard Worker    del opts  # Unused.
68*4f2df630SAndroid Build Coastguard Worker
69*4f2df630SAndroid Build Coastguard Worker
70*4f2df630SAndroid Build Coastguard Workerdef main(args):
71*4f2df630SAndroid Build Coastguard Worker    """Builds, bundles, or tests all of the EC targets.
72*4f2df630SAndroid Build Coastguard Worker
73*4f2df630SAndroid Build Coastguard Worker    Additionally, the tool reports build metrics.
74*4f2df630SAndroid Build Coastguard Worker    """
75*4f2df630SAndroid Build Coastguard Worker    opts = parse_args(args)
76*4f2df630SAndroid Build Coastguard Worker
77*4f2df630SAndroid Build Coastguard Worker    if not hasattr(opts, "func"):
78*4f2df630SAndroid Build Coastguard Worker        print("Must select a valid sub command!")
79*4f2df630SAndroid Build Coastguard Worker        return -1
80*4f2df630SAndroid Build Coastguard Worker
81*4f2df630SAndroid Build Coastguard Worker    # Run selected sub command function
82*4f2df630SAndroid Build Coastguard Worker    try:
83*4f2df630SAndroid Build Coastguard Worker        opts.func(opts)
84*4f2df630SAndroid Build Coastguard Worker    except subprocess.CalledProcessError:
85*4f2df630SAndroid Build Coastguard Worker        return 1
86*4f2df630SAndroid Build Coastguard Worker    else:
87*4f2df630SAndroid Build Coastguard Worker        return 0
88*4f2df630SAndroid Build Coastguard Worker
89*4f2df630SAndroid Build Coastguard Worker
90*4f2df630SAndroid Build Coastguard Workerdef parse_args(args):
91*4f2df630SAndroid Build Coastguard Worker    """Parses command-line arguments."""
92*4f2df630SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(description=__doc__)
93*4f2df630SAndroid Build Coastguard Worker
94*4f2df630SAndroid Build Coastguard Worker    parser.add_argument(
95*4f2df630SAndroid Build Coastguard Worker        "--cpus",
96*4f2df630SAndroid Build Coastguard Worker        default=multiprocessing.cpu_count(),
97*4f2df630SAndroid Build Coastguard Worker        help="The number of cores to use.",
98*4f2df630SAndroid Build Coastguard Worker    )
99*4f2df630SAndroid Build Coastguard Worker
100*4f2df630SAndroid Build Coastguard Worker    parser.add_argument(
101*4f2df630SAndroid Build Coastguard Worker        "--metrics",
102*4f2df630SAndroid Build Coastguard Worker        dest="metrics",
103*4f2df630SAndroid Build Coastguard Worker        required=True,
104*4f2df630SAndroid Build Coastguard Worker        help="File to write the json-encoded MetricsList proto message.",
105*4f2df630SAndroid Build Coastguard Worker    )
106*4f2df630SAndroid Build Coastguard Worker
107*4f2df630SAndroid Build Coastguard Worker    parser.add_argument(
108*4f2df630SAndroid Build Coastguard Worker        "--metadata",
109*4f2df630SAndroid Build Coastguard Worker        required=False,
110*4f2df630SAndroid Build Coastguard Worker        help="Full pathname for the file in which to write build artifact "
111*4f2df630SAndroid Build Coastguard Worker        "metadata.",
112*4f2df630SAndroid Build Coastguard Worker    )
113*4f2df630SAndroid Build Coastguard Worker
114*4f2df630SAndroid Build Coastguard Worker    parser.add_argument(
115*4f2df630SAndroid Build Coastguard Worker        "--output-dir",
116*4f2df630SAndroid Build Coastguard Worker        required=False,
117*4f2df630SAndroid Build Coastguard Worker        help="Full pathanme for the directory in which to bundle build "
118*4f2df630SAndroid Build Coastguard Worker        "artifacts.",
119*4f2df630SAndroid Build Coastguard Worker    )
120*4f2df630SAndroid Build Coastguard Worker
121*4f2df630SAndroid Build Coastguard Worker    parser.add_argument(
122*4f2df630SAndroid Build Coastguard Worker        "--code-coverage",
123*4f2df630SAndroid Build Coastguard Worker        required=False,
124*4f2df630SAndroid Build Coastguard Worker        action="store_true",
125*4f2df630SAndroid Build Coastguard Worker        help="Build host-based unit tests for code coverage.",
126*4f2df630SAndroid Build Coastguard Worker    )
127*4f2df630SAndroid Build Coastguard Worker
128*4f2df630SAndroid Build Coastguard Worker    parser.add_argument(
129*4f2df630SAndroid Build Coastguard Worker        "--bcs-version",
130*4f2df630SAndroid Build Coastguard Worker        dest="bcs_version",
131*4f2df630SAndroid Build Coastguard Worker        default="",
132*4f2df630SAndroid Build Coastguard Worker        required=False,
133*4f2df630SAndroid Build Coastguard Worker        # TODO(b/180008931): make this required=True.
134*4f2df630SAndroid Build Coastguard Worker        help="BCS version to include in metadata.",
135*4f2df630SAndroid Build Coastguard Worker    )
136*4f2df630SAndroid Build Coastguard Worker
137*4f2df630SAndroid Build Coastguard Worker    # Would make this required=True, but not available until 3.7
138*4f2df630SAndroid Build Coastguard Worker    sub_cmds = parser.add_subparsers()
139*4f2df630SAndroid Build Coastguard Worker
140*4f2df630SAndroid Build Coastguard Worker    build_cmd = sub_cmds.add_parser("build", help="Builds all firmware targets")
141*4f2df630SAndroid Build Coastguard Worker    build_cmd.set_defaults(func=build)
142*4f2df630SAndroid Build Coastguard Worker
143*4f2df630SAndroid Build Coastguard Worker    build_cmd = sub_cmds.add_parser(
144*4f2df630SAndroid Build Coastguard Worker        "bundle", help="Does nothing, kept for compatibility"
145*4f2df630SAndroid Build Coastguard Worker    )
146*4f2df630SAndroid Build Coastguard Worker    build_cmd.set_defaults(func=bundle)
147*4f2df630SAndroid Build Coastguard Worker
148*4f2df630SAndroid Build Coastguard Worker    test_cmd = sub_cmds.add_parser(
149*4f2df630SAndroid Build Coastguard Worker        "test", help="Does nothing, kept for compatibility"
150*4f2df630SAndroid Build Coastguard Worker    )
151*4f2df630SAndroid Build Coastguard Worker    test_cmd.set_defaults(func=test)
152*4f2df630SAndroid Build Coastguard Worker
153*4f2df630SAndroid Build Coastguard Worker    return parser.parse_args(args)
154*4f2df630SAndroid Build Coastguard Worker
155*4f2df630SAndroid Build Coastguard Worker
156*4f2df630SAndroid Build Coastguard Workerif __name__ == "__main__":
157*4f2df630SAndroid Build Coastguard Worker    sys.exit(main(sys.argv[1:]))
158