AP_L1_Control: Fix NAVL1_PERIOD description typo
[ardupilot.git] / wscript
blobb63c432a4f63e82d88c971775bb41c7dd33a154c
1 #!/usr/bin/env python3
2 # encoding: utf-8
4 from __future__ import print_function
6 import os.path
7 import os
8 import sys
9 import subprocess
10 import json
11 import fnmatch
12 sys.path.insert(0, 'Tools/ardupilotwaf/')
13 sys.path.insert(0, 'Tools/scripts/')
15 import ardupilotwaf
16 import boards
17 import shutil
18 import build_options
20 from waflib import Build, ConfigSet, Configure, Context, Utils
21 from waflib.Configure import conf
23 # Ref: https://stackoverflow.com/questions/40590192/getting-an-error-attributeerror-module-object-has-no-attribute-run-while
24 try:
25     from subprocess import CompletedProcess
26 except ImportError:
27     # Python 2
28     class CompletedProcess:
30         def __init__(self, args, returncode, stdout=None, stderr=None):
31             self.args = args
32             self.returncode = returncode
33             self.stdout = stdout
34             self.stderr = stderr
36         def check_returncode(self):
37             if self.returncode != 0:
38                 err = subprocess.CalledProcessError(self.returncode, self.args, output=self.stdout)
39                 raise err
40             return self.returncode
42     def sp_run(*popenargs, **kwargs):
43         input = kwargs.pop("input", None)
44         check = kwargs.pop("handle", False)
45         kwargs.pop("capture_output", True)
46         if input is not None:
47             if 'stdin' in kwargs:
48                 raise ValueError('stdin and input arguments may not both be used.')
49             kwargs['stdin'] = subprocess.PIPE
50         process = subprocess.Popen(*popenargs, **kwargs)
51         try:
52             outs, errs = process.communicate(input)
53         except:
54             process.kill()
55             process.wait()
56             raise
57         returncode = process.poll()
58         if check and returncode:
59             raise subprocess.CalledProcessError(returncode, popenargs, output=outs)
60         return CompletedProcess(popenargs, returncode, stdout=outs, stderr=errs)
62     subprocess.run = sp_run
63     # ^ This monkey patch allows it work on Python 2 or 3 the same way
66 # TODO: implement a command 'waf help' that shows the basic tasks a
67 # developer might want to do: e.g. how to configure a board, compile a
68 # vehicle, compile all the examples, add a new example. Should fit in
69 # less than a terminal screen, ideally commands should be copy
70 # pastable. Add the 'export waf="$PWD/waf"' trick to be copy-pastable
71 # as well.
73 # TODO: replace defines with the use of the generated ap_config.h file
74 # this makes recompilation at least when defines change. which might
75 # be sufficient.
77 # Default installation prefix for Linux boards
78 default_prefix = '/usr/'
80 # Override Build execute and Configure post_recurse methods for autoconfigure purposes
81 Build.BuildContext.execute = ardupilotwaf.ap_autoconfigure(Build.BuildContext.execute)
82 Configure.ConfigurationContext.post_recurse = ardupilotwaf.ap_configure_post_recurse()
85 def _set_build_context_variant(board):
86     for c in Context.classes:
87         if not issubclass(c, Build.BuildContext):
88             continue
89         c.variant = board
91 # Remove all submodules and then sync
92 @conf
93 def submodule_force_clean(ctx):
94     whitelist = {
95                             'COLCON_IGNORE',
96                             'esp_idf',
97                           }
99     # Get all items in the modules folder
100     module_list = os.scandir('modules')
102     # Delete all directories except those in the whitelist
103     for module in module_list:
104         if (module.is_dir()) and (module.name not in whitelist):
105             shutil.rmtree(module)
107     submodulesync(ctx)
109 # run Tools/gittools/submodule-sync.sh to sync submodules
110 @conf
111 def submodulesync(ctx):
112     subprocess.call(['Tools/gittools/submodule-sync.sh'])
114 def init(ctx):
115     # Generate Task List, so that VS Code extension can keep track
116     # of changes to possible build targets
117     generate_tasklist(ctx, False)
118     env = ConfigSet.ConfigSet()
119     try:
120         p = os.path.join(Context.out_dir, Build.CACHE_DIR, Build.CACHE_SUFFIX)
121         env.load(p)
122     except EnvironmentError:
123         return
125     Configure.autoconfig = 'clobber' if env.AUTOCONFIG else False
127     board = ctx.options.board or env.BOARD
129     if not board:
130         return
132     # define the variant build commands according to the board
133     _set_build_context_variant(board)
135 def options(opt):
136     opt.load('compiler_cxx compiler_c waf_unit_test python')
137     opt.load('ardupilotwaf')
138     opt.load('build_summary')
140     g = opt.ap_groups['configure']
142     boards_names = boards.get_boards_names()
143     removed_names = boards.get_removed_boards()
144     g.add_option('--board',
145         action='store',
146         default=None,
147         help='Target board to build, choices are %s.' % ', '.join(boards_names))
149     g.add_option('--debug',
150         action='store_true',
151         default=False,
152         help='Configure as debug variant.')
154     g.add_option('--debug-symbols', '-g',
155         action='store_true',
156         default=False,
157         help='Add debug symbolds to build.')
159     g.add_option('--vs-launch',
160         action='store_true',
161         default=False,
162         help='Generate wscript environment variable to .vscode/setting.json for Visual Studio Code')
163     
164     g.add_option('--disable-watchdog',
165         action='store_true',
166         default=False,
167         help='Build with watchdog disabled.')
169     g.add_option('--coverage',
170                  action='store_true',
171                  default=False,
172                  help='Configure coverage flags.')
174     g.add_option('--Werror',
175         action='store_true',
176         default=None,
177         help='build with -Werror.')
179     g.add_option('--disable-Werror',
180         action='store_true',
181         default=None,
182         help='Disable -Werror.')
183     
184     g.add_option('--toolchain',
185         action='store',
186         default=None,
187         help='Override default toolchain used for the board. Use "native" for using the host toolchain.')
189     g.add_option('--disable-gccdeps',
190         action='store_true',
191         default=False,
192         help='Disable the use of GCC dependencies output method and use waf default method.')
194     g.add_option('--enable-asserts',
195         action='store_true',
196         default=False,
197         help='enable OS level asserts.')
199     g.add_option('--save-temps',
200         action='store_true',
201         default=False,
202         help='save compiler temporary files.')
203     
204     g.add_option('--enable-malloc-guard',
205         action='store_true',
206         default=False,
207         help='enable malloc guard regions.')
209     g.add_option('--enable-stats',
210         action='store_true',
211         default=False,
212         help='enable OS level thread statistics.')
214     g.add_option('--bootloader',
215         action='store_true',
216         default=False,
217         help='Configure for building a bootloader.')
219     g.add_option('--signed-fw',
220         action='store_true',
221         default=False,
222         help='Configure for signed firmware support.')
224     g.add_option('--private-key',
225                  action='store',
226                  default=None,
227             help='path to private key for signing firmware.')
228     
229     g.add_option('--no-autoconfig',
230         dest='autoconfig',
231         action='store_false',
232         default=True,
233         help='''Disable autoconfiguration feature. By default, the build system
234 triggers a reconfiguration whenever it thinks it's necessary - this
235 option disables that.
236 ''')
238     g.add_option('--no-submodule-update',
239         dest='submodule_update',
240         action='store_false',
241         default=True,
242         help='''Don't update git submodules. Useful for building with
243 submodules at specific revisions.
244 ''')
246     g.add_option('--enable-header-checks', action='store_true',
247         default=False,
248         help="Enable checking of headers")
250     g.add_option('--default-parameters',
251         default=None,
252         help='set default parameters to embed in the firmware')
254     g.add_option('--enable-math-check-indexes',
255                  action='store_true',
256                  default=False,
257                  help="Enable checking of math indexes")
259     g.add_option('--disable-scripting', action='store_true',
260                  default=False,
261                  help="Disable onboard scripting engine")
263     g.add_option('--enable-scripting', action='store_true',
264                  default=False,
265                  help="Enable onboard scripting engine")
267     g.add_option('--no-gcs', action='store_true',
268                  default=False,
269                  help="Disable GCS code")
270     
271     g.add_option('--scripting-checks', action='store_true',
272                  default=True,
273                  help="Enable runtime scripting sanity checks")
275     g.add_option('--enable-onvif', action='store_true',
276                  default=False,
277                  help="Enables and sets up ONVIF camera control")
279     g.add_option('--scripting-docs', action='store_true',
280                  default=False,
281                  help="enable generation of scripting documentation")
283     g.add_option('--enable-opendroneid', action='store_true',
284                  default=False,
285                  help="Enables OpenDroneID")
287     g.add_option('--enable-check-firmware', action='store_true',
288                  default=False,
289                  help="Enables firmware ID checking on boot")
291     g.add_option('--enable-custom-controller', action='store_true',
292                  default=False,
293                  help="Enables custom controller")
295     g.add_option('--enable-gps-logging', action='store_true',
296                  default=False,
297                  help="Enables GPS logging")
298     
299     g.add_option('--enable-dds', action='store_true',
300                  help="Enable the dds client to connect with ROS2/DDS.")
302     g.add_option('--disable-networking', action='store_true',
303                  help="Disable the networking API code")
305     g.add_option('--enable-networking-tests', action='store_true',
306                  help="Enable the networking test code. Automatically enables networking.")
307     
308     g.add_option('--enable-dronecan-tests', action='store_true',
309                  default=False,
310                  help="Enables DroneCAN tests in sitl")
312     g.add_option('--sitl-littlefs', action='store_true',
313                  default=False,
314                  help="Enable littlefs for filesystem access on SITL (under construction)")
316     g = opt.ap_groups['linux']
318     linux_options = ('--prefix', '--destdir', '--bindir', '--libdir')
319     for k in linux_options:
320         option = opt.parser.get_option(k)
321         if option:
322             opt.parser.remove_option(k)
323             g.add_option(option)
325     g.add_option('--apstatedir',
326         action='store',
327         default='',
328         help='''Where to save data like parameters, log and terrain.
329 This is the --localstatedir + ArduPilots subdirectory [default:
330 board-dependent, usually /var/lib/ardupilot]''')
332     g.add_option('--rsync-dest',
333         dest='rsync_dest',
334         action='store',
335         default='',
336         help='''Destination for the rsync Waf command. It can be passed during
337 configuration in order to save typing.
338 ''')
340     g.add_option('--enable-benchmarks',
341         action='store_true',
342         default=False,
343         help='Enable benchmarks.')
345     g.add_option('--enable-lttng', action='store_true',
346         default=False,
347         help="Enable lttng integration")
349     g.add_option('--disable-libiio', action='store_true',
350         default=False,
351         help="Don't use libiio even if supported by board and dependencies available")
353     g.add_option('--disable-tests', action='store_true',
354         default=False,
355         help="Disable compilation and test execution")
357     g.add_option('--enable-sfml', action='store_true',
358                  default=False,
359                  help="Enable SFML graphics library")
361     g.add_option('--enable-sfml-joystick', action='store_true',
362                  default=False,
363                  help="Enable SFML joystick input library")
365     g.add_option('--enable-sfml-audio', action='store_true',
366                  default=False,
367                  help="Enable SFML audio library")
369     g.add_option('--osd', action='store_true',
370                  default=False,
371                  help="Enable OSD support")
373     g.add_option('--osd-fonts', action='store_true',
374                  default=False,
375                  help="Enable OSD support with fonts")
376     
377     g.add_option('--sitl-osd', action='store_true',
378                  default=False,
379                  help="Enable SITL OSD")
381     g.add_option('--sitl-rgbled', action='store_true',
382                  default=False,
383                  help="Enable SITL RGBLed")
385     g.add_option('--force-32bit', action='store_true',
386                  default=False,
387                  help="Force 32bit build")
389     g.add_option('--build-dates', action='store_true',
390                  default=False,
391                  help="Include build date in binaries.  Appears in AUTOPILOT_VERSION.os_sw_version")
393     g.add_option('--sitl-flash-storage',
394         action='store_true',
395         default=False,
396         help='Use flash storage emulation.')
398     g.add_option('--ekf-double',
399         action='store_true',
400         default=False,
401         help='Configure EKF as double precision.')
403     g.add_option('--ekf-single',
404         action='store_true',
405         default=False,
406         help='Configure EKF as single precision.')
407     
408     g.add_option('--static',
409         action='store_true',
410         default=False,
411         help='Force a static build')
413     g.add_option('--postype-single',
414         action='store_true',
415         default=False,
416         help='force single precision postype_t')
418     g.add_option('--consistent-builds',
419         action='store_true',
420         default=False,
421         help='force consistent build outputs for things like __LINE__')
423     g.add_option('--extra-hwdef',
424             action='store',
425             default=None,
426             help='Extra hwdef.dat file for custom build.')
428     g.add_option('--assert-cc-version',
429                  default=None,
430                  help='fail configure if not using the specified gcc version')
432     g.add_option('--num-aux-imus',
433                  type='int',
434                  default=0,
435                  help='number of auxiliary IMUs')
437     g.add_option('--board-start-time',
438                  type='int',
439                  default=0,
440                  help='zero time on boot in microseconds')
442     g.add_option('--enable-iomcu-profiled-support',
443                     action='store_true',
444                     default=False,
445                     help='enable iomcu profiled support')
447     g.add_option('--enable-new-checking',
448         action='store_true',
449         default=False,
450         help='enables checking of new to ensure NEW_NOTHROW is used')
452     # support enabling any option in build_options.py
453     for opt in build_options.BUILD_OPTIONS:
454         enable_option = "--" + opt.config_option()
455         disable_option = enable_option.replace("--enable", "--disable")
456         enable_description = opt.description
457         if not enable_description.lower().startswith("enable"):
458             enable_description = "Enable " + enable_description
459         disable_description = "Disable " + enable_description[len("Enable "):]
460         g.add_option(enable_option,
461                      action='store_true',
462                      default=False,
463                      help=enable_description)
464         g.add_option(disable_option,
465                      action='store_true',
466                      default=False,
467                      help=disable_description)
468     
469     
470 def _collect_autoconfig_files(cfg):
471     for m in sys.modules.values():
472         paths = []
473         if hasattr(m, '__file__') and m.__file__ is not None:
474             paths.append(m.__file__)
475         elif hasattr(m, '__path__'):
476             for p in m.__path__:
477                 if p is not None:
478                     paths.append(p)
480         for p in paths:
481             if p in cfg.files or not os.path.isfile(p):
482                 continue
484             with open(p, 'rb') as f:
485                 cfg.hash = Utils.h_list((cfg.hash, f.read()))
486                 cfg.files.append(p)
488 def configure(cfg):
489         # we need to enable debug mode when building for gconv, and force it to sitl
490     if cfg.options.board is None:
491         cfg.options.board = 'sitl'
493     boards_names = boards.get_boards_names()
494     if not cfg.options.board in boards_names:
495         for b in boards_names:
496             if b.upper() == cfg.options.board.upper():
497                 cfg.options.board = b
498                 break
499         
500     cfg.env.BOARD = cfg.options.board
501     cfg.env.DEBUG = cfg.options.debug
502     cfg.env.DEBUG_SYMBOLS = cfg.options.debug_symbols
503     cfg.env.COVERAGE = cfg.options.coverage
504     cfg.env.AUTOCONFIG = cfg.options.autoconfig
506     _set_build_context_variant(cfg.env.BOARD)
507     cfg.setenv(cfg.env.BOARD)
509     if cfg.options.signed_fw:
510         cfg.env.AP_SIGNED_FIRMWARE = True
511         cfg.options.enable_check_firmware = True
513     cfg.env.BOARD = cfg.options.board
514     cfg.env.DEBUG = cfg.options.debug
515     cfg.env.VS_LAUNCH = cfg.options.vs_launch
516     cfg.env.DEBUG_SYMBOLS = cfg.options.debug_symbols
517     cfg.env.COVERAGE = cfg.options.coverage
518     cfg.env.FORCE32BIT = cfg.options.force_32bit
519     cfg.env.ENABLE_ASSERTS = cfg.options.enable_asserts
520     cfg.env.BOOTLOADER = cfg.options.bootloader
521     cfg.env.ENABLE_MALLOC_GUARD = cfg.options.enable_malloc_guard
522     cfg.env.ENABLE_STATS = cfg.options.enable_stats
523     cfg.env.SAVE_TEMPS = cfg.options.save_temps
525     extra_hwdef = cfg.options.extra_hwdef
526     if extra_hwdef is not None and not os.path.exists(extra_hwdef):
527         raise FileNotFoundError(f"extra-hwdef file NOT found: '{cfg.options.extra_hwdef}'")
528     cfg.env.HWDEF_EXTRA = cfg.options.extra_hwdef
529     if cfg.env.HWDEF_EXTRA:
530         cfg.env.HWDEF_EXTRA = os.path.abspath(cfg.env.HWDEF_EXTRA)
532     cfg.env.OPTIONS = cfg.options.__dict__
534     # Allow to differentiate our build from the make build
535     cfg.define('WAF_BUILD', 1)
537     cfg.msg('Autoconfiguration', 'enabled' if cfg.options.autoconfig else 'disabled')
539     if cfg.options.static:
540         cfg.msg('Using static linking', 'yes', color='YELLOW')
541         cfg.env.STATIC_LINKING = True
543     if cfg.options.num_aux_imus > 0:
544         cfg.define('INS_AUX_INSTANCES', cfg.options.num_aux_imus)
546     if cfg.options.board_start_time != 0:
547         cfg.define('AP_BOARD_START_TIME', cfg.options.board_start_time)
548         # also in env for hrt.c
549         cfg.env.AP_BOARD_START_TIME = cfg.options.board_start_time
551     # require python 3.8.x or later
552     cfg.load('python')
553     cfg.check_python_version(minver=(3,6,9))
555     cfg.load('ap_library')
557     cfg.msg('Setting board to', cfg.options.board)
558     cfg.get_board().configure(cfg)
560     cfg.load('waf_unit_test')
561     cfg.load('mavgen')
562     cfg.load('dronecangen')
564     cfg.env.SUBMODULE_UPDATE = cfg.options.submodule_update
566     cfg.start_msg('Source is git repository')
567     if cfg.srcnode.find_node('.git'):
568         cfg.end_msg('yes')
569     else:
570         cfg.end_msg('no')
571         cfg.env.SUBMODULE_UPDATE = False
573     cfg.msg('Update submodules', 'yes' if cfg.env.SUBMODULE_UPDATE else 'no')
574     cfg.load('git_submodule')
576     if cfg.options.enable_benchmarks:
577         cfg.load('gbenchmark')
578     cfg.load('gtest')
580     if cfg.env.BOARD == "sitl":
581         cfg.start_msg('Littlefs')
583         if cfg.options.sitl_littlefs:
584             cfg.end_msg('enabled')
585         else:
586             cfg.end_msg('disabled', color='YELLOW')
588     cfg.load('littlefs')
589     cfg.load('static_linking')
590     cfg.load('build_summary')
592     cfg.start_msg('Benchmarks')
593     if cfg.env.HAS_GBENCHMARK:
594         cfg.end_msg('enabled')
595     else:
596         cfg.end_msg('disabled', color='YELLOW')
598     cfg.start_msg('Unit tests')
599     if cfg.env.HAS_GTEST:
600         cfg.end_msg('enabled')
601     else:
602         cfg.end_msg('disabled', color='YELLOW')
604     cfg.start_msg('Scripting')
605     if cfg.options.disable_scripting:
606         cfg.end_msg('disabled', color='YELLOW')
607     elif cfg.options.enable_scripting:
608         cfg.end_msg('enabled')
609     else:
610         cfg.end_msg('maybe')
611     cfg.recurse('libraries/AP_Scripting')
613     cfg.recurse('libraries/AP_GPS')
614     cfg.recurse('libraries/AP_HAL_SITL')
615     cfg.recurse('libraries/SITL')
617     cfg.recurse('libraries/AP_Networking')
619     cfg.start_msg('Scripting runtime checks')
620     if cfg.options.scripting_checks:
621         cfg.end_msg('enabled')
622     else:
623         cfg.end_msg('disabled', color='YELLOW')
625     cfg.start_msg('Debug build')
626     if cfg.env.DEBUG:
627         cfg.end_msg('enabled')
628     else:
629         cfg.end_msg('disabled', color='YELLOW')
631     if cfg.env.DEBUG:
632         cfg.start_msg('VS Code launch')
633         if cfg.env.VS_LAUNCH:
634             cfg.end_msg('enabled')
635         else:
636             cfg.end_msg('disabled', color='YELLOW')
638     cfg.start_msg('Coverage build')
639     if cfg.env.COVERAGE:
640         cfg.end_msg('enabled')
641     else:
642         cfg.end_msg('disabled', color='YELLOW')
644     cfg.start_msg('Force 32-bit build')
645     if cfg.env.FORCE32BIT:
646         cfg.end_msg('enabled')
647     else:
648         cfg.end_msg('disabled', color='YELLOW')
650     cfg.env.append_value('GIT_SUBMODULES', 'mavlink')
652     cfg.env.prepend_value('INCLUDES', [
653         cfg.srcnode.abspath() + '/libraries/',
654     ])
656     cfg.find_program('rsync', mandatory=False)
657     if cfg.options.rsync_dest:
658         cfg.msg('Setting rsync destination to', cfg.options.rsync_dest)
659         cfg.env.RSYNC_DEST = cfg.options.rsync_dest
661     if cfg.options.enable_header_checks:
662         cfg.msg('Enabling header checks', cfg.options.enable_header_checks)
663         cfg.env.ENABLE_HEADER_CHECKS = True
664     else:
665         cfg.env.ENABLE_HEADER_CHECKS = False
667     # Always use system extensions
668     cfg.define('_GNU_SOURCE', 1)
670     if cfg.options.Werror:
671         # print(cfg.options.Werror)
672         if cfg.options.disable_Werror:
673             cfg.options.Werror = False
675     cfg.write_config_header(os.path.join(cfg.variant, 'ap_config.h'), guard='_AP_CONFIG_H_')
677     # add in generated flags
678     cfg.env.CXXFLAGS += ['-include', 'ap_config.h']
680     cfg.remove_target_list()
681     _collect_autoconfig_files(cfg)
683     if cfg.env.DEBUG and cfg.env.VS_LAUNCH:
684         import vscode_helper
685         vscode_helper.init_launch_json_if_not_exist(cfg)
686         vscode_helper.update_openocd_cfg(cfg)
688 def collect_dirs_to_recurse(bld, globs, **kw):
689     dirs = []
690     globs = Utils.to_list(globs)
692     if bld.bldnode.is_child_of(bld.srcnode):
693         kw['excl'] = Utils.to_list(kw.get('excl', []))
694         kw['excl'].append(bld.bldnode.path_from(bld.srcnode))
696     for g in globs:
697         for d in bld.srcnode.ant_glob(g + '/wscript', **kw):
698             dirs.append(d.parent.relpath())
699     return dirs
701 def list_boards(ctx):
702     print(*boards.get_boards_names())
704 def list_ap_periph_boards(ctx):
705     print(*boards.get_ap_periph_boards())
707 @conf
708 def ap_periph_boards(ctx):
709     return boards.get_ap_periph_boards()
711 vehicles = ['antennatracker', 'blimp', 'copter', 'heli', 'plane', 'rover', 'sub']
713 def generate_tasklist(ctx, do_print=True):
714     boardlist = boards.get_boards_names()
715     ap_periph_targets = boards.get_ap_periph_boards()
716     tasks = []
717     with open(os.path.join(Context.top_dir, "tasklist.json"), "w") as tlist:
718         for board in boardlist:
719             task = {}
720             task['configure'] = board
721             if board in ap_periph_targets:
722                 if 'sitl' not in board:
723                     # we only support AP_Periph and bootloader builds
724                     task['targets'] = ['AP_Periph', 'bootloader']
725                 else:
726                     task['targets'] = ['AP_Periph']
727             elif 'iofirmware' in board:
728                 task['targets'] = ['iofirmware', 'bootloader']
729             else:
730                 if boards.is_board_based(board, boards.sitl):
731                     task['targets'] = vehicles + ['replay']
732                 elif boards.is_board_based(board, boards.linux):
733                     task['targets'] = vehicles
734                 else:
735                     task['targets'] = vehicles + ['bootloader']
736                     task['buildOptions'] = '--upload'
737             tasks.append(task)
738         tlist.write(json.dumps(tasks))
739         if do_print:
740             print(json.dumps(tasks))
742 def board(ctx):
743     env = ConfigSet.ConfigSet()
744     try:
745         p = os.path.join(Context.out_dir, Build.CACHE_DIR, Build.CACHE_SUFFIX)
746         env.load(p)
747     except:
748         print('No board currently configured')
749         return
751     print('Board configured to: {}'.format(env.BOARD))
753 def _build_cmd_tweaks(bld):
754     if bld.cmd == 'check-all':
755         bld.options.all_tests = True
756         bld.cmd = 'check'
758     if bld.cmd == 'check':
759         if not bld.env.HAS_GTEST:
760             bld.fatal('check: gtest library is required')
761         bld.options.clear_failed_tests = True
763 def _build_dynamic_sources(bld):
764     if not bld.env.BOOTLOADER:
765         bld(
766             features='mavgen',
767             source='modules/mavlink/message_definitions/v1.0/all.xml',
768             output_dir='libraries/GCS_MAVLink/include/mavlink/v2.0/',
769             name='mavlink',
770             # this below is not ideal, mavgen tool should set this, but that's not
771             # currently possible
772             export_includes=[
773             bld.bldnode.make_node('libraries').abspath(),
774             bld.bldnode.make_node('libraries/GCS_MAVLink').abspath(),
775             ],
776             )
778     if (bld.get_board().with_can or bld.env.HAL_NUM_CAN_IFACES) and not bld.env.AP_PERIPH:
779         bld(
780             features='dronecangen',
781             source=bld.srcnode.ant_glob('modules/DroneCAN/DSDL/[a-z]* libraries/AP_DroneCAN/dsdl/[a-z]*', dir=True, src=False),
782             output_dir='modules/DroneCAN/libcanard/dsdlc_generated/',
783             name='dronecan',
784             export_includes=[
785                 bld.bldnode.make_node('modules/DroneCAN/libcanard/dsdlc_generated/include').abspath(),
786                 bld.srcnode.find_dir('modules/DroneCAN/libcanard/').abspath(),
787                 bld.srcnode.find_dir('libraries/AP_DroneCAN/canard/').abspath(),
788                 ]
789             )
790     elif bld.env.AP_PERIPH:
791         bld(
792             features='dronecangen',
793             source=bld.srcnode.ant_glob('modules/DroneCAN/DSDL/* libraries/AP_DroneCAN/dsdl/*', dir=True, src=False),
794             output_dir='modules/DroneCAN/libcanard/dsdlc_generated/',
795             name='dronecan',
796             export_includes=[
797                 bld.bldnode.make_node('modules/DroneCAN/libcanard/dsdlc_generated/include').abspath(),
798                 bld.srcnode.find_dir('modules/DroneCAN/libcanard/').abspath(),
799             ]
800         )
802     if bld.env.ENABLE_DDS:
803         bld.recurse("libraries/AP_DDS")
805     def write_version_header(tsk):
806         bld = tsk.generator.bld
807         return bld.write_version_header(tsk.outputs[0].abspath())
809     bld(
810         name='ap_version',
811         target='ap_version.h',
812         vars=['AP_VERSION_ITEMS'],
813         rule=write_version_header,
814     )
816     bld.env.prepend_value('INCLUDES', [
817         bld.bldnode.abspath(),
818     ])
820 def _build_common_taskgens(bld):
821     # NOTE: Static library with vehicle set to UNKNOWN, shared by all
822     # the tools and examples. This is the first step until the
823     # dependency on the vehicles is reduced. Later we may consider
824     # split into smaller pieces with well defined boundaries.
825     bld.ap_stlib(
826         name='ap',
827         ap_vehicle='UNKNOWN',
828         ap_libraries=bld.ap_get_all_libraries(),
829     )
831     if bld.env.HAS_GTEST:
832         bld.libgtest(cxxflags=['-include', 'ap_config.h'])
834     if bld.env.HAS_GBENCHMARK:
835         bld.libbenchmark()
837 def _build_recursion(bld):
838     common_dirs_patterns = [
839         # TODO: Currently each vehicle also generate its own copy of the
840         # libraries. Fix this, or at least reduce the amount of
841         # vehicle-dependent libraries.
842         '*',
843         'Tools/*',
844         'libraries/*/examples/*',
845         'libraries/*/tests',
846         'libraries/*/utility/tests',
847         'libraries/*/benchmarks',
848     ]
850     common_dirs_excl = [
851         'modules',
852         'libraries/AP_HAL_*',
853     ]
855     hal_dirs_patterns = [
856         'libraries/%s/tests',
857         'libraries/%s/*/tests',
858         'libraries/%s/*/benchmarks',
859         'libraries/%s/examples/*',
860     ]
862     dirs_to_recurse = collect_dirs_to_recurse(
863         bld,
864         common_dirs_patterns,
865         excl=common_dirs_excl,
866     )
867     if bld.env.IOMCU_FW is not None:
868         if bld.env.IOMCU_FW:
869             dirs_to_recurse.append('libraries/AP_IOMCU/iofirmware')
871     if bld.env.PERIPH_FW is not None:
872         if bld.env.PERIPH_FW:
873             dirs_to_recurse.append('Tools/AP_Periph')
875     dirs_to_recurse.append('libraries/AP_Scripting')
877     if bld.env.ENABLE_ONVIF:
878         dirs_to_recurse.append('libraries/AP_ONVIF')
880     for p in hal_dirs_patterns:
881         dirs_to_recurse += collect_dirs_to_recurse(
882             bld,
883             [p % l for l in bld.env.AP_LIBRARIES],
884         )
886     # NOTE: we need to sort to ensure the repeated sources get the
887     # same index, and random ordering of the filesystem doesn't cause
888     # recompilation.
889     dirs_to_recurse.sort()
891     for d in dirs_to_recurse:
892         bld.recurse(d)
894 def _build_post_funs(bld):
895     if bld.cmd == 'check':
896         bld.add_post_fun(ardupilotwaf.test_summary)
897     else:
898         bld.build_summary_post_fun()
900     if bld.env.SUBMODULE_UPDATE:
901         bld.git_submodule_post_fun()
903 def _load_pre_build(bld):
904     '''allow for a pre_build() function in build modules'''
905     if bld.cmd == 'clean':
906         return
907     brd = bld.get_board()
908     if getattr(brd, 'pre_build', None):
909         brd.pre_build(bld)    
911 def build(bld):
912     config_hash = Utils.h_file(bld.bldnode.make_node('ap_config.h').abspath())
913     bld.env.CCDEPS = config_hash
914     bld.env.CXXDEPS = config_hash
916     bld.post_mode = Build.POST_LAZY
918     bld.load('ardupilotwaf')
920     bld.env.AP_LIBRARIES_OBJECTS_KW.update(
921         use=['mavlink'],
922         cxxflags=['-include', 'ap_config.h'],
923     )
925     _load_pre_build(bld)
927     if bld.get_board().with_can:
928         bld.env.AP_LIBRARIES_OBJECTS_KW['use'] += ['dronecan']
930     if bld.get_board().with_littlefs:
931         bld.env.AP_LIBRARIES_OBJECTS_KW['use'] += ['littlefs']
932         bld.littlefs()
934     _build_cmd_tweaks(bld)
936     if bld.env.SUBMODULE_UPDATE:
937         bld.add_group('git_submodules')
938         for name in bld.env.GIT_SUBMODULES:
939             bld.git_submodule(name)
941     bld.add_group('dynamic_sources')
942     _build_dynamic_sources(bld)
944     bld.add_group('build')
945     bld.get_board().build(bld)
946     _build_common_taskgens(bld)
948     _build_recursion(bld)
950     _build_post_funs(bld)
952     if bld.env.DEBUG and bld.env.VS_LAUNCH:
953         import vscode_helper
954         vscode_helper.update_settings(bld)
956 ardupilotwaf.build_command('check',
957     program_group_list='all',
958     doc='builds all programs and run tests',
960 ardupilotwaf.build_command('check-all',
961     program_group_list='all',
962     doc='shortcut for `waf check --alltests`',
965 for name in (vehicles + ['bootloader','iofirmware','AP_Periph','replay']):
966     ardupilotwaf.build_command(name,
967         program_group_list=name,
968         doc='builds %s programs' % name,
969     )
971 for program_group in ('all', 'bin', 'tool', 'examples', 'tests', 'benchmarks'):
972     ardupilotwaf.build_command(program_group,
973         program_group_list=program_group,
974         doc='builds all programs of %s group' % program_group,
975     )
977 class LocalInstallContext(Build.InstallContext):
978     """runs install using BLD/install as destdir, where BLD is the build variant directory"""
979     cmd = 'localinstall'
981     def __init__(self, **kw):
982         super(LocalInstallContext, self).__init__(**kw)
983         self.local_destdir = os.path.join(self.variant_dir, 'install')
985     def execute(self):
986         old_destdir = self.options.destdir
987         self.options.destdir = self.local_destdir
988         r = super(LocalInstallContext, self).execute()
989         self.options.destdir = old_destdir
990         return r
992 class RsyncContext(LocalInstallContext):
993     """runs localinstall and then rsyncs BLD/install with the target system"""
994     cmd = 'rsync'
996     def __init__(self, **kw):
997         super(RsyncContext, self).__init__(**kw)
998         self.add_pre_fun(RsyncContext.create_rsync_taskgen)
1000     def create_rsync_taskgen(self):
1001         if 'RSYNC' not in self.env:
1002             self.fatal('rsync program seems not to be installed, can\'t continue')
1004         self.add_group()
1006         tg = self(
1007             name='rsync',
1008             rule='${RSYNC} -a ${RSYNC_SRC}/ ${RSYNC_DEST}',
1009             always=True,
1010         )
1012         tg.env.RSYNC_SRC = self.local_destdir
1013         if self.options.rsync_dest:
1014             self.env.RSYNC_DEST = self.options.rsync_dest
1016         if 'RSYNC_DEST' not in tg.env:
1017             self.fatal('Destination for rsync not defined. Either pass --rsync-dest here or during configuration.')
1019         tg.post()