Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 1 | # Copyright (c) 2018 Foundries.io |
| 2 | # |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | |
| 5 | import argparse |
| 6 | import os |
Mikkel Jakobsen | 98eb316 | 2020-03-04 15:14:43 +0100 | [diff] [blame] | 7 | import pathlib |
Martí Bolívar | 0186ead | 2019-12-09 11:05:11 -0800 | [diff] [blame] | 8 | import shlex |
Torsten Rasmussen | ef3c5e5 | 2020-06-08 21:09:15 +0200 | [diff] [blame] | 9 | import sys |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 10 | import yaml |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 11 | |
| 12 | from west import log |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 13 | from west.configuration import config |
Jan Van Winkel | 4d975db | 2019-05-04 14:44:56 +0200 | [diff] [blame] | 14 | from zcmake import DEFAULT_CMAKE_GENERATOR, run_cmake, run_build, CMakeCache |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 15 | from build_helpers import is_zephyr_build, find_build_dir, load_domains, \ |
Carles Cufi | 98980c6 | 2019-06-05 16:04:29 +0200 | [diff] [blame] | 16 | FIND_BUILD_DIR_DESCRIPTION |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 17 | |
Carles Cufi | 31bdad5 | 2019-04-26 21:53:02 +0200 | [diff] [blame] | 18 | from zephyr_ext_common import Forceable |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 19 | |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 20 | _ARG_SEPARATOR = '--' |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 21 | |
Torsten Rasmussen | 5fe5d6b | 2021-11-22 13:35:06 +0100 | [diff] [blame] | 22 | SYSBUILD_PROJ_DIR = pathlib.Path(__file__).resolve().parent.parent.parent \ |
| 23 | / pathlib.Path('share/sysbuild') |
| 24 | |
Marti Bolivar | 1f5e6d8 | 2019-05-01 16:48:04 -0600 | [diff] [blame] | 25 | BUILD_USAGE = '''\ |
Gregers Gram Rygg | 4680180 | 2022-02-23 13:27:14 +0100 | [diff] [blame] | 26 | west build [-h] [-b BOARD[@REV]]] [-d BUILD_DIR] |
Marti Bolivar | 1f5e6d8 | 2019-05-01 16:48:04 -0600 | [diff] [blame] | 27 | [-t TARGET] [-p {auto, always, never}] [-c] [--cmake-only] |
Marti Bolivar | 3a486a8 | 2019-05-04 13:32:36 -0600 | [diff] [blame] | 28 | [-n] [-o BUILD_OPT] [-f] |
Torsten Rasmussen | 69f4fa6 | 2022-08-04 10:45:38 +0200 | [diff] [blame] | 29 | [--sysbuild | --no-sysbuild] [--domain DOMAIN] |
Marti Bolivar | 3a486a8 | 2019-05-04 13:32:36 -0600 | [diff] [blame] | 30 | [source_dir] -- [cmake_opt [cmake_opt ...]] |
Marti Bolivar | 1f5e6d8 | 2019-05-01 16:48:04 -0600 | [diff] [blame] | 31 | ''' |
| 32 | |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 33 | BUILD_DESCRIPTION = f'''\ |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 34 | Convenience wrapper for building Zephyr applications. |
| 35 | |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 36 | {FIND_BUILD_DIR_DESCRIPTION} |
| 37 | |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 38 | positional arguments: |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 39 | source_dir application source directory |
| 40 | cmake_opt extra options to pass to cmake; implies -c |
| 41 | (these must come after "--" as shown above) |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 42 | ''' |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 43 | |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 44 | PRISTINE_DESCRIPTION = """\ |
| 45 | A "pristine" build directory is empty. The -p option controls |
| 46 | whether the build directory is made pristine before the build |
| 47 | is done. A bare '--pristine' with no value is the same as |
| 48 | --pristine=always. Setting --pristine=auto uses heuristics to |
| 49 | guess if a pristine build may be necessary.""" |
| 50 | |
Marti Bolivar | e6873b8 | 2019-06-02 22:48:52 -0600 | [diff] [blame] | 51 | def _banner(msg): |
| 52 | log.inf('-- west build: ' + msg, colorize=True) |
| 53 | |
Marti Bolivar | d159503 | 2019-05-04 13:14:28 -0600 | [diff] [blame] | 54 | def config_get(option, fallback): |
| 55 | return config.get('build', option, fallback=fallback) |
| 56 | |
| 57 | def config_getboolean(option, fallback): |
| 58 | return config.getboolean('build', option, fallback=fallback) |
| 59 | |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 60 | class AlwaysIfMissing(argparse.Action): |
| 61 | |
Marti Bolivar | 69099e3 | 2019-05-04 13:16:15 -0600 | [diff] [blame] | 62 | def __call__(self, parser, namespace, values, option_string=None): |
| 63 | setattr(namespace, self.dest, values or 'always') |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 64 | |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 65 | class Build(Forceable): |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 66 | |
| 67 | def __init__(self): |
| 68 | super(Build, self).__init__( |
| 69 | 'build', |
Marti Bolivar | 808028b | 2019-01-28 10:45:02 -0700 | [diff] [blame] | 70 | # Keep this in sync with the string in west-commands.yml. |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 71 | 'compile a Zephyr application', |
| 72 | BUILD_DESCRIPTION, |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 73 | accepts_unknown_args=True) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 74 | |
| 75 | self.source_dir = None |
| 76 | '''Source directory for the build, or None on error.''' |
| 77 | |
| 78 | self.build_dir = None |
| 79 | '''Final build directory used to run the build, or None on error.''' |
| 80 | |
| 81 | self.created_build_dir = False |
| 82 | '''True if the build directory was created; False otherwise.''' |
| 83 | |
| 84 | self.run_cmake = False |
| 85 | '''True if CMake was run; False otherwise. |
| 86 | |
| 87 | Note: this only describes CMake runs done by this command. The |
| 88 | build system generated by CMake may also update itself due to |
| 89 | internal logic.''' |
| 90 | |
| 91 | self.cmake_cache = None |
| 92 | '''Final parsed CMake cache for the build, or None on error.''' |
| 93 | |
| 94 | def do_add_parser(self, parser_adder): |
| 95 | parser = parser_adder.add_parser( |
| 96 | self.name, |
| 97 | help=self.help, |
| 98 | formatter_class=argparse.RawDescriptionHelpFormatter, |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 99 | description=self.description, |
Marti Bolivar | 1f5e6d8 | 2019-05-01 16:48:04 -0600 | [diff] [blame] | 100 | usage=BUILD_USAGE) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 101 | |
Martí Bolívar | 0d5e6c1 | 2020-12-09 15:53:00 -0800 | [diff] [blame] | 102 | # Remember to update west-completion.bash if you add or remove |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 103 | # flags |
| 104 | |
Gregers Gram Rygg | 4680180 | 2022-02-23 13:27:14 +0100 | [diff] [blame] | 105 | parser.add_argument('-b', '--board', |
| 106 | help='board to build for with optional board revision') |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 107 | # Hidden option for backwards compatibility |
| 108 | parser.add_argument('-s', '--source-dir', help=argparse.SUPPRESS) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 109 | parser.add_argument('-d', '--build-dir', |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 110 | help='build directory to create or use') |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 111 | self.add_force_arg(parser) |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 112 | |
| 113 | group = parser.add_argument_group('cmake and build tool') |
| 114 | group.add_argument('-c', '--cmake', action='store_true', |
| 115 | help='force a cmake run') |
| 116 | group.add_argument('--cmake-only', action='store_true', |
| 117 | help="just run cmake; don't build (implies -c)") |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 118 | group.add_argument('--domain', action='append', |
| 119 | help='''execute build tool (make or ninja) only for |
| 120 | given domain''') |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 121 | group.add_argument('-t', '--target', |
Martí Bolívar | 0d5e6c1 | 2020-12-09 15:53:00 -0800 | [diff] [blame] | 122 | help='''run build system target TARGET |
| 123 | (try "-t usage")''') |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 124 | group.add_argument('-T', '--test-item', |
| 125 | help='''Build based on test data in testcase.yaml |
Maciej Perkowski | fb9a6af | 2023-08-29 16:51:58 +0200 | [diff] [blame] | 126 | or sample.yaml. If source directory is not used |
| 127 | an argument has to be defined as |
| 128 | SOURCE_PATH/TEST_NAME. |
| 129 | E.g. samples/hello_world/sample.basic.helloworld. |
| 130 | If source directory is passed |
| 131 | then "TEST_NAME" is enough.''') |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 132 | group.add_argument('-o', '--build-opt', default=[], action='append', |
| 133 | help='''options to pass to the build tool |
| 134 | (make or ninja); may be given more than once''') |
| 135 | group.add_argument('-n', '--just-print', '--dry-run', '--recon', |
| 136 | dest='dry_run', action='store_true', |
| 137 | help="just print build commands; don't run them") |
Marti Bolivar | 5880fee | 2023-01-09 16:17:51 -0800 | [diff] [blame] | 138 | group.add_argument('-S', '--snippet', dest='snippets', |
| 139 | action='append', default=[], |
| 140 | help='''add the argument to SNIPPET; may be given |
| 141 | multiple times. Forces CMake to run again if given. |
| 142 | Do not use this option with manually specified |
| 143 | -DSNIPPET... cmake arguments: the results are |
| 144 | undefined''') |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 145 | |
Torsten Rasmussen | 5fe5d6b | 2021-11-22 13:35:06 +0100 | [diff] [blame] | 146 | group = parser.add_mutually_exclusive_group() |
| 147 | group.add_argument('--sysbuild', action='store_true', |
| 148 | help='''create multi domain build system''') |
| 149 | group.add_argument('--no-sysbuild', action='store_true', |
| 150 | help='''do not create multi domain build system |
| 151 | (default)''') |
| 152 | |
Martí Bolívar | 6e4c2b9 | 2020-06-25 12:58:58 -0700 | [diff] [blame] | 153 | group = parser.add_argument_group('pristine builds', |
| 154 | PRISTINE_DESCRIPTION) |
| 155 | group.add_argument('-p', '--pristine', choices=['auto', 'always', |
| 156 | 'never'], action=AlwaysIfMissing, nargs='?', |
| 157 | help='pristine build folder setting') |
| 158 | |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 159 | return parser |
| 160 | |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 161 | def do_run(self, args, remainder): |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 162 | self.args = args # Avoid having to pass them around |
Marti Bolivar | 8b9b7e7 | 2019-05-23 09:31:31 -0600 | [diff] [blame] | 163 | self.config_board = config_get('board', None) |
Marti Bolivar | a1ef696 | 2019-05-01 17:06:15 -0600 | [diff] [blame] | 164 | log.dbg('args: {} remainder: {}'.format(args, remainder), |
| 165 | level=log.VERBOSE_EXTREME) |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 166 | # Store legacy -s option locally |
| 167 | source_dir = self.args.source_dir |
| 168 | self._parse_remainder(remainder) |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 169 | # Parse testcase.yaml or sample.yaml files for additional options. |
| 170 | if self.args.test_item: |
Anas Nashif | 79b955c | 2023-01-27 11:37:19 +0000 | [diff] [blame] | 171 | # we get path + testitem |
| 172 | item = os.path.basename(self.args.test_item) |
Maciej Perkowski | fb9a6af | 2023-08-29 16:51:58 +0200 | [diff] [blame] | 173 | if self.args.source_dir: |
| 174 | test_path = self.args.source_dir |
| 175 | else: |
| 176 | test_path = os.path.dirname(self.args.test_item) |
Anas Nashif | d4b0c48 | 2023-08-23 10:28:49 +0000 | [diff] [blame] | 177 | if test_path and os.path.exists(test_path): |
Anas Nashif | 79b955c | 2023-01-27 11:37:19 +0000 | [diff] [blame] | 178 | self.args.source_dir = test_path |
Anas Nashif | d4b0c48 | 2023-08-23 10:28:49 +0000 | [diff] [blame] | 179 | if not self._parse_test_item(item): |
| 180 | log.die("No test metadata found") |
| 181 | else: |
| 182 | log.die("test item path does not exist") |
| 183 | |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 184 | if source_dir: |
| 185 | if self.args.source_dir: |
| 186 | log.die("source directory specified twice:({} and {})".format( |
| 187 | source_dir, self.args.source_dir)) |
| 188 | self.args.source_dir = source_dir |
| 189 | log.dbg('source_dir: {} cmake_opts: {}'.format(self.args.source_dir, |
Marti Bolivar | a1ef696 | 2019-05-01 17:06:15 -0600 | [diff] [blame] | 190 | self.args.cmake_opts), |
| 191 | level=log.VERBOSE_EXTREME) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 192 | self._sanity_precheck() |
| 193 | self._setup_build_dir() |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 194 | |
| 195 | if args.pristine is not None: |
| 196 | pristine = args.pristine |
| 197 | else: |
| 198 | # Load the pristine={auto, always, never} configuration value |
Martí Bolívar | c19c6fb | 2021-01-15 09:17:01 -0800 | [diff] [blame] | 199 | pristine = config_get('pristine', 'never') |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 200 | if pristine not in ['auto', 'always', 'never']: |
Marti Bolivar | 69099e3 | 2019-05-04 13:16:15 -0600 | [diff] [blame] | 201 | log.wrn( |
| 202 | 'treating unknown build.pristine value "{}" as "never"'. |
| 203 | format(pristine)) |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 204 | pristine = 'never' |
Martí Bolívar | 1f9ab85 | 2023-03-09 13:10:28 -0800 | [diff] [blame] | 205 | self.auto_pristine = pristine == 'auto' |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 206 | |
| 207 | log.dbg('pristine: {} auto_pristine: {}'.format(pristine, |
Marti Bolivar | a1ef696 | 2019-05-01 17:06:15 -0600 | [diff] [blame] | 208 | self.auto_pristine), |
| 209 | level=log.VERBOSE_VERY) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 210 | if is_zephyr_build(self.build_dir): |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 211 | if pristine == 'always': |
Carles Cufi | 3a88dce | 2019-04-18 16:46:12 +0200 | [diff] [blame] | 212 | self._run_pristine() |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 213 | self.run_cmake = True |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 214 | else: |
| 215 | self._update_cache() |
Marti Bolivar | 1f5e6d8 | 2019-05-01 16:48:04 -0600 | [diff] [blame] | 216 | if (self.args.cmake or self.args.cmake_opts or |
Marti Bolivar | 5880fee | 2023-01-09 16:17:51 -0800 | [diff] [blame] | 217 | self.args.cmake_only or self.args.snippets): |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 218 | self.run_cmake = True |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 219 | else: |
| 220 | self.run_cmake = True |
Carles Cufi | 98980c6 | 2019-06-05 16:04:29 +0200 | [diff] [blame] | 221 | self.source_dir = self._find_source_dir() |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 222 | self._sanity_check() |
| 223 | |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 224 | board, origin = self._find_board() |
| 225 | self._run_cmake(board, origin, self.args.cmake_opts) |
Marti Bolivar | 1f5e6d8 | 2019-05-01 16:48:04 -0600 | [diff] [blame] | 226 | if args.cmake_only: |
| 227 | return |
| 228 | |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 229 | self._sanity_check() |
| 230 | self._update_cache() |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 231 | self.domains = load_domains(self.build_dir) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 232 | |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 233 | self._run_build(args.target, args.domain) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 234 | |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 235 | def _find_board(self): |
| 236 | board, origin = None, None |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 237 | if self.cmake_cache: |
| 238 | board, origin = (self.cmake_cache.get('CACHED_BOARD'), |
| 239 | 'CMakeCache.txt') |
Martí Bolívar | af5a79f | 2021-02-02 09:22:44 -0800 | [diff] [blame] | 240 | |
| 241 | # A malformed CMake cache may exist, but not have a board. |
| 242 | # This happens if there's a build error from a previous run. |
| 243 | if board is not None: |
| 244 | return (board, origin) |
| 245 | |
| 246 | if self.args.board: |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 247 | board, origin = self.args.board, 'command line' |
| 248 | elif 'BOARD' in os.environ: |
| 249 | board, origin = os.environ['BOARD'], 'env' |
Marti Bolivar | 8b9b7e7 | 2019-05-23 09:31:31 -0600 | [diff] [blame] | 250 | elif self.config_board is not None: |
| 251 | board, origin = self.config_board, 'configfile' |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 252 | return board, origin |
| 253 | |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 254 | def _parse_remainder(self, remainder): |
| 255 | self.args.source_dir = None |
| 256 | self.args.cmake_opts = None |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 257 | |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 258 | try: |
| 259 | # Only one source_dir is allowed, as the first positional arg |
| 260 | if remainder[0] != _ARG_SEPARATOR: |
| 261 | self.args.source_dir = remainder[0] |
| 262 | remainder = remainder[1:] |
| 263 | # Only the first argument separator is consumed, the rest are |
| 264 | # passed on to CMake |
| 265 | if remainder[0] == _ARG_SEPARATOR: |
| 266 | remainder = remainder[1:] |
Ulf Magnusson | 5d307c9 | 2019-09-02 15:35:56 +0200 | [diff] [blame] | 267 | if remainder: |
Carles Cufi | b710177 | 2019-02-21 15:58:19 +0100 | [diff] [blame] | 268 | self.args.cmake_opts = remainder |
| 269 | except IndexError: |
| 270 | return |
| 271 | |
Anas Nashif | 79b955c | 2023-01-27 11:37:19 +0000 | [diff] [blame] | 272 | def _parse_test_item(self, test_item): |
Anas Nashif | 1008124 | 2023-01-27 11:35:36 +0000 | [diff] [blame] | 273 | found_test_metadata = False |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 274 | for yp in ['sample.yaml', 'testcase.yaml']: |
| 275 | yf = os.path.join(self.args.source_dir, yp) |
| 276 | if not os.path.exists(yf): |
| 277 | continue |
Anas Nashif | 1008124 | 2023-01-27 11:35:36 +0000 | [diff] [blame] | 278 | found_test_metadata = True |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 279 | with open(yf, 'r') as stream: |
| 280 | try: |
| 281 | y = yaml.safe_load(stream) |
| 282 | except yaml.YAMLError as exc: |
| 283 | log.die(exc) |
Anas Nashif | 6fdfc91 | 2023-07-19 02:01:52 +0000 | [diff] [blame] | 284 | common = y.get('common') |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 285 | tests = y.get('tests') |
| 286 | if not tests: |
Anas Nashif | 1008124 | 2023-01-27 11:35:36 +0000 | [diff] [blame] | 287 | log.die(f"No tests found in {yf}") |
Anas Nashif | 79b955c | 2023-01-27 11:37:19 +0000 | [diff] [blame] | 288 | item = tests.get(test_item) |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 289 | if not item: |
Anas Nashif | 79b955c | 2023-01-27 11:37:19 +0000 | [diff] [blame] | 290 | log.die(f"Test item {test_item} not found in {yf}") |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 291 | |
Anas Nashif | 6fdfc91 | 2023-07-19 02:01:52 +0000 | [diff] [blame] | 292 | sysbuild = False |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 293 | extra_dtc_overlay_files = [] |
| 294 | extra_overlay_confs = [] |
| 295 | extra_conf_files = [] |
Jamie McCrae | bc97d8f | 2023-08-03 10:56:41 +0100 | [diff] [blame] | 296 | required_snippets = [] |
Anas Nashif | 6fdfc91 | 2023-07-19 02:01:52 +0000 | [diff] [blame] | 297 | for section in [common, item]: |
| 298 | if not section: |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 299 | continue |
Anas Nashif | 6fdfc91 | 2023-07-19 02:01:52 +0000 | [diff] [blame] | 300 | sysbuild = section.get('sysbuild', sysbuild) |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 301 | for data in [ |
| 302 | 'extra_args', |
| 303 | 'extra_configs', |
| 304 | 'extra_conf_files', |
| 305 | 'extra_overlay_confs', |
Jamie McCrae | bc97d8f | 2023-08-03 10:56:41 +0100 | [diff] [blame] | 306 | 'extra_dtc_overlay_files', |
| 307 | 'required_snippets' |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 308 | ]: |
Anas Nashif | 6fdfc91 | 2023-07-19 02:01:52 +0000 | [diff] [blame] | 309 | extra = section.get(data) |
| 310 | if not extra: |
| 311 | continue |
| 312 | if isinstance(extra, str): |
| 313 | arg_list = extra.split(" ") |
| 314 | else: |
| 315 | arg_list = extra |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 316 | |
Anas Nashif | 6fdfc91 | 2023-07-19 02:01:52 +0000 | [diff] [blame] | 317 | if data == 'extra_configs': |
| 318 | args = ["-D{}".format(arg.replace('"', '\"')) for arg in arg_list] |
| 319 | elif data == 'extra_args': |
Chaitanya Tata | 6b05af6 | 2023-09-05 01:47:48 +0530 | [diff] [blame] | 320 | # Retain quotes around config options |
| 321 | config_options = [arg for arg in arg_list if arg.startswith("CONFIG_")] |
| 322 | non_config_options = [arg for arg in arg_list if not arg.startswith("CONFIG_")] |
| 323 | args = ["-D{}".format(a.replace('"', '\"')) for a in config_options] |
| 324 | args.extend(["-D{}".format(arg.replace('"', '')) for arg in non_config_options]) |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 325 | elif data == 'extra_conf_files': |
| 326 | extra_conf_files.extend(arg_list) |
| 327 | continue |
| 328 | elif data == 'extra_overlay_confs': |
| 329 | extra_overlay_confs.extend(arg_list) |
| 330 | continue |
| 331 | elif data == 'extra_dtc_overlay_files': |
| 332 | extra_dtc_overlay_files.extend(arg_list) |
| 333 | continue |
Jamie McCrae | bc97d8f | 2023-08-03 10:56:41 +0100 | [diff] [blame] | 334 | elif data == 'required_snippets': |
| 335 | required_snippets.extend(arg_list) |
| 336 | continue |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 337 | |
Anas Nashif | 6fdfc91 | 2023-07-19 02:01:52 +0000 | [diff] [blame] | 338 | if self.args.cmake_opts: |
| 339 | self.args.cmake_opts.extend(args) |
| 340 | else: |
| 341 | self.args.cmake_opts = args |
| 342 | |
| 343 | self.args.sysbuild = sysbuild |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 344 | |
Anas Nashif | d4b0c48 | 2023-08-23 10:28:49 +0000 | [diff] [blame] | 345 | if found_test_metadata: |
| 346 | args = [] |
| 347 | if extra_conf_files: |
| 348 | args.append(f"CONF_FILE=\"{';'.join(extra_conf_files)}\"") |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 349 | |
Anas Nashif | d4b0c48 | 2023-08-23 10:28:49 +0000 | [diff] [blame] | 350 | if extra_dtc_overlay_files: |
| 351 | args.append(f"DTC_OVERLAY_FILE=\"{';'.join(extra_dtc_overlay_files)}\"") |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 352 | |
Anas Nashif | d4b0c48 | 2023-08-23 10:28:49 +0000 | [diff] [blame] | 353 | if extra_overlay_confs: |
| 354 | args.append(f"OVERLAY_CONFIG=\"{';'.join(extra_overlay_confs)}\"") |
Jamie McCrae | bc97d8f | 2023-08-03 10:56:41 +0100 | [diff] [blame] | 355 | |
| 356 | if required_snippets: |
| 357 | args.append(f"SNIPPET=\"{';'.join(required_snippets)}\"") |
| 358 | |
Anas Nashif | d4b0c48 | 2023-08-23 10:28:49 +0000 | [diff] [blame] | 359 | # Build the final argument list |
| 360 | args_expanded = ["-D{}".format(a.replace('"', '')) for a in args] |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 361 | |
Anas Nashif | d4b0c48 | 2023-08-23 10:28:49 +0000 | [diff] [blame] | 362 | if self.args.cmake_opts: |
| 363 | self.args.cmake_opts.extend(args_expanded) |
| 364 | else: |
| 365 | self.args.cmake_opts = args_expanded |
Anas Nashif | 47102de | 2023-07-21 12:03:58 +0000 | [diff] [blame] | 366 | |
Anas Nashif | 1008124 | 2023-01-27 11:35:36 +0000 | [diff] [blame] | 367 | return found_test_metadata |
Anas Nashif | 070cf6a | 2021-05-29 07:53:41 -0400 | [diff] [blame] | 368 | |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 369 | def _sanity_precheck(self): |
| 370 | app = self.args.source_dir |
| 371 | if app: |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 372 | self.check_force( |
| 373 | os.path.isdir(app), |
| 374 | 'source directory {} does not exist'.format(app)) |
| 375 | self.check_force( |
| 376 | 'CMakeLists.txt' in os.listdir(app), |
| 377 | "{} doesn't contain a CMakeLists.txt".format(app)) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 378 | |
| 379 | def _update_cache(self): |
| 380 | try: |
Carles Cufi | 31bdad5 | 2019-04-26 21:53:02 +0200 | [diff] [blame] | 381 | self.cmake_cache = CMakeCache.from_build_dir(self.build_dir) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 382 | except FileNotFoundError: |
| 383 | pass |
| 384 | |
| 385 | def _setup_build_dir(self): |
| 386 | # Initialize build_dir and created_build_dir attributes. |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 387 | # If we created the build directory, we must run CMake. |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 388 | log.dbg('setting up build directory', level=log.VERBOSE_EXTREME) |
Carles Cufi | 98980c6 | 2019-06-05 16:04:29 +0200 | [diff] [blame] | 389 | # The CMake Cache has not been loaded yet, so this is safe |
Ulf Magnusson | 89efaed | 2019-09-05 13:44:09 +0200 | [diff] [blame] | 390 | board, _ = self._find_board() |
Carles Cufi | 98980c6 | 2019-06-05 16:04:29 +0200 | [diff] [blame] | 391 | source_dir = self._find_source_dir() |
| 392 | app = os.path.split(source_dir)[1] |
| 393 | build_dir = find_build_dir(self.args.build_dir, board=board, |
| 394 | source_dir=source_dir, app=app) |
| 395 | if not build_dir: |
| 396 | log.die('Unable to determine a default build folder. Check ' |
| 397 | 'your build.dir-fmt configuration option') |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 398 | |
| 399 | if os.path.exists(build_dir): |
| 400 | if not os.path.isdir(build_dir): |
| 401 | log.die('build directory {} exists and is not a directory'. |
| 402 | format(build_dir)) |
| 403 | else: |
| 404 | os.makedirs(build_dir, exist_ok=False) |
| 405 | self.created_build_dir = True |
| 406 | self.run_cmake = True |
| 407 | |
| 408 | self.build_dir = build_dir |
| 409 | |
Carles Cufi | 98980c6 | 2019-06-05 16:04:29 +0200 | [diff] [blame] | 410 | def _find_source_dir(self): |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 411 | # Initialize source_dir attribute, either from command line argument, |
| 412 | # implicitly from the build directory's CMake cache, or using the |
| 413 | # default (current working directory). |
| 414 | log.dbg('setting up source directory', level=log.VERBOSE_EXTREME) |
| 415 | if self.args.source_dir: |
| 416 | source_dir = self.args.source_dir |
| 417 | elif self.cmake_cache: |
Marti Bolivar | acda257 | 2019-04-10 17:09:17 -0600 | [diff] [blame] | 418 | source_dir = self.cmake_cache.get('CMAKE_HOME_DIRECTORY') |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 419 | if not source_dir: |
Marti Bolivar | acda257 | 2019-04-10 17:09:17 -0600 | [diff] [blame] | 420 | # This really ought to be there. The build directory |
| 421 | # must be corrupted somehow. Let's see what we can do. |
| 422 | log.die('build directory', self.build_dir, |
| 423 | 'CMake cache has no CMAKE_HOME_DIRECTORY;', |
| 424 | 'please give a source_dir') |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 425 | else: |
| 426 | source_dir = os.getcwd() |
Carles Cufi | 98980c6 | 2019-06-05 16:04:29 +0200 | [diff] [blame] | 427 | return os.path.abspath(source_dir) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 428 | |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 429 | def _sanity_check_source_dir(self): |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 430 | if self.source_dir == self.build_dir: |
| 431 | # There's no forcing this. |
| 432 | log.die('source and build directory {} cannot be the same; ' |
| 433 | 'use --build-dir {} to specify a build directory'. |
| 434 | format(self.source_dir, self.build_dir)) |
| 435 | |
| 436 | srcrel = os.path.relpath(self.source_dir) |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 437 | self.check_force( |
| 438 | not is_zephyr_build(self.source_dir), |
| 439 | 'it looks like {srcrel} is a build directory: ' |
| 440 | 'did you mean --build-dir {srcrel} instead?'. |
| 441 | format(srcrel=srcrel)) |
| 442 | self.check_force( |
| 443 | 'CMakeLists.txt' in os.listdir(self.source_dir), |
| 444 | 'source directory "{srcrel}" does not contain ' |
| 445 | 'a CMakeLists.txt; is this really what you ' |
| 446 | 'want to build? (Use -s SOURCE_DIR to specify ' |
| 447 | 'the application source directory)'. |
| 448 | format(srcrel=srcrel)) |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 449 | |
| 450 | def _sanity_check(self): |
| 451 | # Sanity check the build configuration. |
| 452 | # Side effect: may update cmake_cache attribute. |
| 453 | log.dbg('sanity checking the build', level=log.VERBOSE_EXTREME) |
| 454 | self._sanity_check_source_dir() |
| 455 | |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 456 | if not self.cmake_cache: |
| 457 | return # That's all we can check without a cache. |
| 458 | |
Martí Bolívar | 877fc59 | 2020-04-10 15:39:55 -0700 | [diff] [blame] | 459 | if "CMAKE_PROJECT_NAME" not in self.cmake_cache: |
| 460 | # This happens sometimes when a build system is not |
| 461 | # completely generated due to an error during the |
| 462 | # CMake configuration phase. |
| 463 | self.run_cmake = True |
| 464 | |
Torsten Rasmussen | 5fe5d6b | 2021-11-22 13:35:06 +0100 | [diff] [blame] | 465 | cached_proj = self.cmake_cache.get('APPLICATION_SOURCE_DIR') |
| 466 | cached_app = self.cmake_cache.get('APP_DIR') |
| 467 | # if APP_DIR is None but APPLICATION_SOURCE_DIR is set, that indicates |
| 468 | # an older build folder, this still requires pristine. |
| 469 | if cached_app is None and cached_proj: |
| 470 | cached_app = cached_proj |
| 471 | |
| 472 | log.dbg('APP_DIR:', cached_app, level=log.VERBOSE_EXTREME) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 473 | source_abs = (os.path.abspath(self.args.source_dir) |
| 474 | if self.args.source_dir else None) |
| 475 | cached_abs = os.path.abspath(cached_app) if cached_app else None |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 476 | |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 477 | log.dbg('pristine:', self.auto_pristine, level=log.VERBOSE_EXTREME) |
Mikkel Jakobsen | 98eb316 | 2020-03-04 15:14:43 +0100 | [diff] [blame] | 478 | |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 479 | # If the build directory specifies a source app, make sure it's |
| 480 | # consistent with --source-dir. |
| 481 | apps_mismatched = (source_abs and cached_abs and |
Marc Herbert | c2524a0 | 2021-11-02 10:30:27 -0700 | [diff] [blame] | 482 | pathlib.Path(source_abs).resolve() != pathlib.Path(cached_abs).resolve()) |
Mikkel Jakobsen | 98eb316 | 2020-03-04 15:14:43 +0100 | [diff] [blame] | 483 | |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 484 | self.check_force( |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 485 | not apps_mismatched or self.auto_pristine, |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 486 | 'Build directory "{}" is for application "{}", but source ' |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 487 | 'directory "{}" was specified; please clean it, use --pristine, ' |
| 488 | 'or use --build-dir to set another build directory'. |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 489 | format(self.build_dir, cached_abs, source_abs)) |
Mikkel Jakobsen | 98eb316 | 2020-03-04 15:14:43 +0100 | [diff] [blame] | 490 | |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 491 | if apps_mismatched: |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 492 | self.run_cmake = True # If they insist, we need to re-run cmake. |
| 493 | |
Marti Bolivar | 8b9b7e7 | 2019-05-23 09:31:31 -0600 | [diff] [blame] | 494 | # If CACHED_BOARD is not defined, we need some other way to |
| 495 | # find the board. |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 496 | cached_board = self.cmake_cache.get('CACHED_BOARD') |
| 497 | log.dbg('CACHED_BOARD:', cached_board, level=log.VERBOSE_EXTREME) |
Marti Bolivar | 8b9b7e7 | 2019-05-23 09:31:31 -0600 | [diff] [blame] | 498 | # If apps_mismatched and self.auto_pristine are true, we will |
| 499 | # run pristine on the build, invalidating the cached |
| 500 | # board. In that case, we need some way of getting the board. |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 501 | self.check_force((cached_board and |
| 502 | not (apps_mismatched and self.auto_pristine)) |
Marti Bolivar | 8b9b7e7 | 2019-05-23 09:31:31 -0600 | [diff] [blame] | 503 | or self.args.board or self.config_board or |
| 504 | os.environ.get('BOARD'), |
| 505 | 'Cached board not defined, please provide it ' |
| 506 | '(provide --board, set default with ' |
| 507 | '"west config build.board <BOARD>", or set ' |
| 508 | 'BOARD in the environment)') |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 509 | |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 510 | # Check consistency between cached board and --board. |
| 511 | boards_mismatched = (self.args.board and cached_board and |
| 512 | self.args.board != cached_board) |
| 513 | self.check_force( |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 514 | not boards_mismatched or self.auto_pristine, |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 515 | 'Build directory {} targets board {}, but board {} was specified. ' |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 516 | '(Clean the directory, use --pristine, or use --build-dir to ' |
| 517 | 'specify a different one.)'. |
Marti Bolivar | 8c44799 | 2019-01-30 13:53:40 -0700 | [diff] [blame] | 518 | format(self.build_dir, cached_board, self.args.board)) |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 519 | |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 520 | if self.auto_pristine and (apps_mismatched or boards_mismatched): |
Carles Cufi | 3a88dce | 2019-04-18 16:46:12 +0200 | [diff] [blame] | 521 | self._run_pristine() |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 522 | self.cmake_cache = None |
| 523 | log.dbg('run_cmake:', True, level=log.VERBOSE_EXTREME) |
| 524 | self.run_cmake = True |
| 525 | |
| 526 | # Tricky corner-case: The user has not specified a build folder but |
| 527 | # there was one in the CMake cache. Since this is going to be |
| 528 | # invalidated, reset to CWD and re-run the basic tests. |
| 529 | if ((boards_mismatched and not apps_mismatched) and |
Marti Bolivar | 69099e3 | 2019-05-04 13:16:15 -0600 | [diff] [blame] | 530 | (not source_abs and cached_abs)): |
Carles Cufi | 98980c6 | 2019-06-05 16:04:29 +0200 | [diff] [blame] | 531 | self.source_dir = self._find_source_dir() |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 532 | self._sanity_check_source_dir() |
| 533 | |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 534 | def _run_cmake(self, board, origin, cmake_opts): |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 535 | if board is None and config_getboolean('board_warn', True): |
| 536 | log.wrn('This looks like a fresh build and BOARD is unknown;', |
| 537 | "so it probably won't work. To fix, use", |
| 538 | '--board=<your-board>.') |
| 539 | log.inf('Note: to silence the above message, run', |
| 540 | "'west config build.board_warn false'") |
| 541 | |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 542 | if not self.run_cmake: |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 543 | return |
| 544 | |
Marti Bolivar | e6873b8 | 2019-06-02 22:48:52 -0600 | [diff] [blame] | 545 | _banner('generating a build system') |
| 546 | |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 547 | if board is not None and origin != 'CMakeCache.txt': |
| 548 | cmake_opts = ['-DBOARD={}'.format(board)] |
| 549 | else: |
| 550 | cmake_opts = [] |
| 551 | if self.args.cmake_opts: |
| 552 | cmake_opts.extend(self.args.cmake_opts) |
Marti Bolivar | 5880fee | 2023-01-09 16:17:51 -0800 | [diff] [blame] | 553 | if self.args.snippets: |
| 554 | cmake_opts.append(f'-DSNIPPET={";".join(self.args.snippets)}') |
Marti Bolivar | 88fb8ba | 2019-05-04 13:14:57 -0600 | [diff] [blame] | 555 | |
Martí Bolívar | 0186ead | 2019-12-09 11:05:11 -0800 | [diff] [blame] | 556 | user_args = config_get('cmake-args', None) |
| 557 | if user_args: |
| 558 | cmake_opts.extend(shlex.split(user_args)) |
| 559 | |
Torsten Rasmussen | 5fe5d6b | 2021-11-22 13:35:06 +0100 | [diff] [blame] | 560 | config_sysbuild = config_getboolean('sysbuild', False) |
| 561 | if self.args.sysbuild or (config_sysbuild and not self.args.no_sysbuild): |
| 562 | cmake_opts.extend(['-S{}'.format(SYSBUILD_PROJ_DIR), |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 563 | '-DAPP_DIR:PATH={}'.format(self.source_dir)]) |
Torsten Rasmussen | 5fe5d6b | 2021-11-22 13:35:06 +0100 | [diff] [blame] | 564 | else: |
| 565 | # self.args.no_sysbuild == True or config sysbuild False |
| 566 | cmake_opts.extend(['-S{}'.format(self.source_dir)]) |
| 567 | |
Carles Cufi | 3c6584d | 2019-04-14 21:51:16 +0200 | [diff] [blame] | 568 | # Invoke CMake from the current working directory using the |
| 569 | # -S and -B options (officially introduced in CMake 3.13.0). |
| 570 | # This is important because users expect invocations like this |
| 571 | # to Just Work: |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 572 | # |
| 573 | # west build -- -DOVERLAY_CONFIG=relative-path.conf |
Torsten Rasmussen | c03e190 | 2023-05-15 11:59:52 +0200 | [diff] [blame] | 574 | final_cmake_args = ['-DWEST_PYTHON={}'.format(pathlib.Path(sys.executable).as_posix()), |
Torsten Rasmussen | ef3c5e5 | 2020-06-08 21:09:15 +0200 | [diff] [blame] | 575 | '-B{}'.format(self.build_dir), |
Marti Bolivar | bbe890a | 2019-05-01 16:53:32 -0600 | [diff] [blame] | 576 | '-G{}'.format(config_get('generator', |
| 577 | DEFAULT_CMAKE_GENERATOR))] |
Marti Bolivar | ab82264 | 2019-01-23 08:31:06 -0700 | [diff] [blame] | 578 | if cmake_opts: |
| 579 | final_cmake_args.extend(cmake_opts) |
Marti Bolivar | 8465cf2 | 2019-05-01 17:24:23 -0600 | [diff] [blame] | 580 | run_cmake(final_cmake_args, dry_run=self.args.dry_run) |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 581 | |
Carles Cufi | 3a88dce | 2019-04-18 16:46:12 +0200 | [diff] [blame] | 582 | def _run_pristine(self): |
Marti Bolivar | e6873b8 | 2019-06-02 22:48:52 -0600 | [diff] [blame] | 583 | _banner('making build dir {} pristine'.format(self.build_dir)) |
Carles Cufi | 3a88dce | 2019-04-18 16:46:12 +0200 | [diff] [blame] | 584 | if not is_zephyr_build(self.build_dir): |
Marti Bolivar | 69099e3 | 2019-05-04 13:16:15 -0600 | [diff] [blame] | 585 | log.die('Refusing to run pristine on a folder that is not a ' |
| 586 | 'Zephyr build system') |
Carles Cufi | 3a88dce | 2019-04-18 16:46:12 +0200 | [diff] [blame] | 587 | |
Torsten Rasmussen | e819fa4 | 2020-03-10 14:52:35 +0100 | [diff] [blame] | 588 | cache = CMakeCache.from_build_dir(self.build_dir) |
Torsten Rasmussen | 774103d | 2021-01-18 10:56:25 +0100 | [diff] [blame] | 589 | |
| 590 | app_src_dir = cache.get('APPLICATION_SOURCE_DIR') |
| 591 | app_bin_dir = cache.get('APPLICATION_BINARY_DIR') |
| 592 | |
| 593 | cmake_args = [f'-DBINARY_DIR={app_bin_dir}', |
| 594 | f'-DSOURCE_DIR={app_src_dir}', |
| 595 | '-P', cache['ZEPHYR_BASE'] + '/cmake/pristine.cmake'] |
Marti Bolivar | 8465cf2 | 2019-05-01 17:24:23 -0600 | [diff] [blame] | 596 | run_cmake(cmake_args, cwd=self.build_dir, dry_run=self.args.dry_run) |
Carles Cufi | 3a88dce | 2019-04-18 16:46:12 +0200 | [diff] [blame] | 597 | |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 598 | def _run_build(self, target, domain): |
Marti Bolivar | e6873b8 | 2019-06-02 22:48:52 -0600 | [diff] [blame] | 599 | if target: |
| 600 | _banner('running target {}'.format(target)) |
Martí Bolívar | 34a5916 | 2020-03-05 14:20:18 -0800 | [diff] [blame] | 601 | elif self.run_cmake: |
Marti Bolivar | e6873b8 | 2019-06-02 22:48:52 -0600 | [diff] [blame] | 602 | _banner('building application') |
Carles Cufi | b7c7591 | 2019-04-14 21:52:45 +0200 | [diff] [blame] | 603 | extra_args = ['--target', target] if target else [] |
Marti Bolivar | 3a486a8 | 2019-05-04 13:32:36 -0600 | [diff] [blame] | 604 | if self.args.build_opt: |
| 605 | extra_args.append('--') |
| 606 | extra_args.extend(self.args.build_opt) |
Marti Bolivar | 0396b6e | 2019-05-06 18:10:35 -0600 | [diff] [blame] | 607 | if self.args.verbose: |
| 608 | self._append_verbose_args(extra_args, |
| 609 | not bool(self.args.build_opt)) |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 610 | |
| 611 | domains = load_domains(self.build_dir) |
| 612 | build_dir_list = [] |
| 613 | |
| 614 | if domain is None: |
| 615 | # If no domain is specified, we just build top build dir as that |
| 616 | # will build all domains. |
| 617 | build_dir_list = [domains.get_top_build_dir()] |
| 618 | else: |
| 619 | _banner('building domain(s): {}'.format(' '.join(domain))) |
| 620 | domain_list = domains.get_domains(domain) |
| 621 | for d in domain_list: |
| 622 | build_dir_list.append(d.build_dir) |
| 623 | |
| 624 | for b in build_dir_list: |
| 625 | run_build(b, extra_args=extra_args, |
| 626 | dry_run=self.args.dry_run) |
Marti Bolivar | 0396b6e | 2019-05-06 18:10:35 -0600 | [diff] [blame] | 627 | |
| 628 | def _append_verbose_args(self, extra_args, add_dashes): |
| 629 | # These hacks are only needed for CMake versions earlier than |
| 630 | # 3.14. When Zephyr's minimum version is at least that, we can |
| 631 | # drop this nonsense and just run "cmake --build BUILD -v". |
| 632 | self._update_cache() |
| 633 | if not self.cmake_cache: |
| 634 | return |
| 635 | generator = self.cmake_cache.get('CMAKE_GENERATOR') |
| 636 | if not generator: |
| 637 | return |
| 638 | # Substring matching is for things like "Eclipse CDT4 - Ninja". |
| 639 | if 'Ninja' in generator: |
| 640 | if add_dashes: |
| 641 | extra_args.append('--') |
| 642 | extra_args.append('-v') |
| 643 | elif generator == 'Unix Makefiles': |
| 644 | if add_dashes: |
| 645 | extra_args.append('--') |
| 646 | extra_args.append('VERBOSE=1') |