• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Default pw build script for upstream Pigweed.
15
16Usage:
17
18   pw build --list
19   pw build --recipe default_gn
20   pw build --recipe default_* --watch
21   pw build --step gn_combined_build_check --step gn_python_*
22   pw build -C out/gn --watch
23"""
24
25import argparse
26import logging
27from pathlib import Path
28import shutil
29import sys
30
31import pw_cli.env
32import pw_presubmit.pigweed_presubmit
33from pw_presubmit.build import gn_args
34
35from pw_build.build_recipe import (
36    BuildCommand,
37    BuildRecipe,
38    should_gn_gen,
39    should_regenerate_cmake,
40)
41from pw_build.project_builder_presubmit_runner import (
42    get_parser,
43    main,
44)
45
46
47_LOG = logging.getLogger('pw_build')
48
49_PW_ENV = pw_cli.env.pigweed_environment()
50_REPO_ROOT = _PW_ENV.PW_PROJECT_ROOT
51_PACKAGE_ROOT = _PW_ENV.PW_PACKAGE_ROOT
52
53
54def gn_recipe() -> BuildRecipe:
55    """Return the default_gn recipe."""
56    default_gn_gen_command = [
57        'gn',
58        'gen',
59        # NOTE: Not an f-string. BuildRecipe will replace with the out dir.
60        '{build_dir}',
61        '--export-compile-commands',
62    ]
63
64    if shutil.which('ccache'):
65        default_gn_gen_command.append(gn_args(pw_command_launcher='ccache'))
66
67    return BuildRecipe(
68        build_dir=Path('out/gn'),
69        title='default_gn',
70        steps=[
71            BuildCommand(
72                run_if=should_gn_gen,
73                command=default_gn_gen_command,
74            ),
75            BuildCommand(
76                build_system_command='ninja',
77                targets=['default'],
78            ),
79        ],
80    )
81
82
83def bazel_recipe() -> BuildRecipe:
84    """Return the default_bazel recipe."""
85    default_bazel_targets = ['//...:all']
86
87    return BuildRecipe(
88        build_dir=Path('out/bazel'),
89        title='default_bazel',
90        steps=[
91            BuildCommand(
92                build_system_command='bazel',
93                build_system_extra_args=[
94                    'build',
95                    '--verbose_failures',
96                    '--worker_verbose',
97                ],
98                targets=default_bazel_targets,
99            ),
100            BuildCommand(
101                build_system_command='bazel',
102                build_system_extra_args=[
103                    'test',
104                    '--test_output=errors',
105                ],
106                targets=default_bazel_targets,
107            ),
108        ],
109    )
110
111
112def cmake_recipe() -> BuildRecipe:
113    """Construct the default_cmake recipe."""
114    toolchain_path = (
115        _REPO_ROOT / 'pw_toolchain' / 'host_clang' / 'toolchain.cmake'
116    )
117
118    cmake_generate_command = [
119        'cmake',
120        '--fresh',
121        '--debug-output',
122        '-DCMAKE_MESSAGE_LOG_LEVEL=WARNING',
123        '-S',
124        str(_REPO_ROOT),
125        '-B',
126        # NOTE: Not an f-string. BuildRecipe will replace with the out dir.
127        '{build_dir}',
128        '-G',
129        'Ninja',
130        f'-DCMAKE_TOOLCHAIN_FILE={toolchain_path}',
131        '-DCMAKE_EXPORT_COMPILE_COMMANDS=1',
132        f'-Ddir_pw_third_party_nanopb={_PACKAGE_ROOT / "nanopb"}',
133        '-Dpw_third_party_nanopb_ADD_SUBDIRECTORY=ON',
134        f'-Ddir_pw_third_party_emboss={_PACKAGE_ROOT / "emboss"}',
135        f'-Ddir_pw_third_party_boringssl={_PACKAGE_ROOT / "boringssl"}',
136    ]
137
138    if shutil.which('ccache'):
139        cmake_generate_command.append("-DCMAKE_C_COMPILER_LAUNCHER=ccache")
140        cmake_generate_command.append("-DCMAKE_CXX_COMPILER_LAUNCHER=ccache")
141
142    pw_package_install_steps = [
143        BuildCommand(
144            command=['pw', '--no-banner', 'package', 'install', package],
145        )
146        for package in ['emboss', 'nanopb', 'boringssl']
147    ]
148
149    return BuildRecipe(
150        build_dir=Path('out/cmake'),
151        title='default_cmake',
152        steps=pw_package_install_steps
153        + [
154            BuildCommand(
155                run_if=should_regenerate_cmake(cmake_generate_command),
156                command=cmake_generate_command,
157            ),
158            BuildCommand(
159                build_system_command='ninja',
160                targets=pw_presubmit.pigweed_presubmit.CMAKE_TARGETS,
161            ),
162        ],
163    )
164
165
166def pigweed_upstream_main() -> int:
167    """Entry point for Pigweed upstream ``pw build`` command.
168
169    Defines one or more BuildRecipes and passes that along with all of Pigweed
170    upstream presubmit programs to the project_builder_presubmit_runner.main to
171    start a pw build invocation.
172
173    Returns:
174      An int representing the success or failure status of the build; 0 if
175      successful, 1 if failed.
176
177    Command line usage examples:
178
179    .. code-block:: bash
180
181       pw build --list
182       pw build --recipe default_gn
183       pw build --recipe default_* --watch
184       pw build --step gn_combined_build_check --step gn_python_*
185       pw build -C out/gn --watch
186    """
187
188    return main(
189        presubmit_programs=pw_presubmit.pigweed_presubmit.PROGRAMS,
190        build_recipes=[
191            gn_recipe(),
192            bazel_recipe(),
193            cmake_recipe(),
194        ],
195        default_root_logfile=Path('out/build.txt'),
196    )
197
198
199def _build_argument_parser() -> argparse.ArgumentParser:
200    return get_parser(
201        pw_presubmit.pigweed_presubmit.PROGRAMS,
202        [
203            gn_recipe(),
204            bazel_recipe(),
205            cmake_recipe(),
206        ],
207    )
208
209
210if __name__ == '__main__':
211    sys.exit(pigweed_upstream_main())
212