-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
Copy pathbuild_examples.py
executable file
·241 lines (207 loc) · 7.29 KB
/
build_examples.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/env -S python3 -B
# Copyright (c) 2021 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import logging
import os
import sys
import click
import coloredlogs
from builders.builder import BuilderOptions
from runner import PrintOnlyRunner, ShellRunner
import build
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
# Supported log levels, mapping string values required for argument
# parsing into logging constants
__LOG_LEVELS__ = {
'debug': logging.DEBUG,
'info': logging.INFO,
'warn': logging.WARN,
'fatal': logging.FATAL,
}
def CommaSeparate(items) -> str:
return ', '.join([x for x in items])
def ValidateRepoPath(context, parameter, value):
"""
Validates that the given path looks like a valid chip repository checkout.
"""
if value.startswith('/TEST/'):
# Hackish command to allow for unit testing
return value
for name in ['BUILD.gn', '.gn', os.path.join('scripts', 'bootstrap.sh')]:
expected_file = os.path.join(value, name)
if not os.path.exists(expected_file):
raise click.BadParameter(
("'%s' does not look like a valid repository path: "
"%s not found.") % (value, expected_file))
return value
def ValidateTargetNames(context, parameter, values):
"""
Validates that the given target name is valid.
"""
for value in values:
if not any(target.StringIntoTargetParts(value.lower())
for target in build.targets.BUILD_TARGETS):
raise click.BadParameter(
"'%s' is not a valid target name." % value)
return values
@click.group(chain=True)
@click.option(
'--log-level',
default='INFO',
type=click.Choice(__LOG_LEVELS__.keys(), case_sensitive=False),
help='Determines the verbosity of script output.')
@click.option(
'--target',
default=[],
multiple=True,
callback=ValidateTargetNames,
help='Build target(s)')
@click.option(
'--enable-link-map-file',
default=False,
is_flag=True,
help='Enable generation of link map files.')
@click.option(
'--enable-flashbundle',
default=False,
is_flag=True,
help='Also generate the flashbundles for the app.')
@click.option(
'--repo',
default='.',
callback=ValidateRepoPath,
help='Path to the root of the CHIP SDK repository checkout.')
@click.option(
'--out-prefix',
default='./out',
type=click.Path(file_okay=False, resolve_path=True),
help='Prefix for the generated file output.')
@click.option(
'--ninja-jobs',
type=int,
is_flag=False,
flag_value=0,
default=None,
help='Number of ninja jobs')
@click.option(
'--pregen-dir',
default=None,
type=click.Path(file_okay=False, resolve_path=True),
help='Directory where generated files have been pre-generated.')
@click.option(
'--clean',
default=False,
is_flag=True,
help='Clean output directory before running the command')
@click.option(
'--dry-run',
default=False,
is_flag=True,
help='Only print out shell commands that would be executed')
@click.option(
'--dry-run-output',
default="-",
type=click.File("wt"),
help='Where to write the dry run output')
@click.option(
'--no-log-timestamps',
default=False,
is_flag=True,
help='Skip timestaps in log output')
@click.option(
'--pw-command-launcher',
help=(
'Set pigweed command launcher. E.g.: "--pw-command-launcher=ccache" '
'for using ccache when building examples.'))
@click.pass_context
def main(context, log_level, target, enable_link_map_file, repo,
out_prefix, ninja_jobs, pregen_dir, clean, dry_run, dry_run_output,
enable_flashbundle, no_log_timestamps, pw_command_launcher):
# Ensures somewhat pretty logging of what is going on
log_fmt = '%(asctime)s %(levelname)-7s %(message)s'
if no_log_timestamps:
log_fmt = '%(levelname)-7s %(message)s'
coloredlogs.install(level=__LOG_LEVELS__[log_level], fmt=log_fmt)
if 'PW_PROJECT_ROOT' not in os.environ:
raise click.UsageError("""
PW_PROJECT_ROOT not set in the current environment.
Please make sure you `source scripts/bootstrap.sh` or `source scripts/activate.sh`
before running this script.
""".strip())
if dry_run:
runner = PrintOnlyRunner(dry_run_output, root=repo)
else:
runner = ShellRunner(root=repo)
requested_targets = set([t.lower() for t in target])
logging.info('Building targets: %s', CommaSeparate(requested_targets))
context.obj = build.Context(
repository_path=repo, output_prefix=out_prefix, ninja_jobs=ninja_jobs, runner=runner)
context.obj.SetupBuilders(targets=requested_targets, options=BuilderOptions(
enable_link_map_file=enable_link_map_file,
enable_flashbundle=enable_flashbundle,
pw_command_launcher=pw_command_launcher,
pregen_dir=pregen_dir,
))
if clean:
context.obj.CleanOutputDirectories()
@main.command(
'gen', help='Generate ninja/makefiles (but does not run the compilation)')
@click.pass_context
def cmd_generate(context):
context.obj.Generate()
@main.command(
'targets',
help=('Lists the targets that can be used with the build and gen commands'))
@click.option(
'--format',
default='summary',
type=click.Choice(['summary', 'expanded', 'json'], case_sensitive=False),
help="""
summary - list of shorthand strings summarzing the available targets;
expanded - list all possible targets rather than the shorthand string;
json - a JSON representation of the available targets
""")
@click.pass_context
def cmd_targets(context, format):
if format == 'expanded':
for target in build.targets.BUILD_TARGETS:
build.target.report_rejected_parts = False
for s in target.AllVariants():
print(s)
elif format == 'json':
print(json.dumps([target.ToDict() for target in build.targets.BUILD_TARGETS], indent=4))
else:
for target in build.targets.BUILD_TARGETS:
print(target.HumanString())
@main.command('build', help='generate and run ninja/make as needed to compile')
@click.option(
'--copy-artifacts-to',
default=None,
type=click.Path(file_okay=False, resolve_path=True),
help='Prefix for the generated file output.')
@click.option(
'--create-archives',
default=None,
type=click.Path(file_okay=False, resolve_path=True),
help='Prefix of compressed archives of the generated files.')
@click.pass_context
def cmd_build(context, copy_artifacts_to, create_archives):
context.obj.Build()
if copy_artifacts_to:
context.obj.CopyArtifactsTo(copy_artifacts_to)
if create_archives:
context.obj.CreateArtifactArchives(create_archives)
if __name__ == '__main__':
main(auto_envvar_prefix='CHIP')