AP_GPS: add checking of instance number before update with incoming data
[ardupilot.git] / wscript
blob0517655459219c4c09877e21ca675c74af8ad54f
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/')
14 import ardupilotwaf
15 import boards
16 import shutil
18 from waflib import Build, ConfigSet, Configure, Context, Utils
19 from waflib.Configure import conf
21 # Ref: https://stackoverflow.com/questions/40590192/getting-an-error-attributeerror-module-object-has-no-attribute-run-while
22 try:
23     from subprocess import CompletedProcess
24 except ImportError:
25     # Python 2
26     class CompletedProcess:
28         def __init__(self, args, returncode, stdout=None, stderr=None):
29             self.args = args
30             self.returncode = returncode
31             self.stdout = stdout
32             self.stderr = stderr
34         def check_returncode(self):
35             if self.returncode != 0:
36                 err = subprocess.CalledProcessError(self.returncode, self.args, output=self.stdout)
37                 raise err
38             return self.returncode
40     def sp_run(*popenargs, **kwargs):
41         input = kwargs.pop("input", None)
42         check = kwargs.pop("handle", False)
43         kwargs.pop("capture_output", True)
44         if input is not None:
45             if 'stdin' in kwargs:
46                 raise ValueError('stdin and input arguments may not both be used.')
47             kwargs['stdin'] = subprocess.PIPE
48         process = subprocess.Popen(*popenargs, **kwargs)
49         try:
50             outs, errs = process.communicate(input)
51         except:
52             process.kill()
53             process.wait()
54             raise
55         returncode = process.poll()
56         if check and returncode:
57             raise subprocess.CalledProcessError(returncode, popenargs, output=outs)
58         return CompletedProcess(popenargs, returncode, stdout=outs, stderr=errs)
60     subprocess.run = sp_run
61     # ^ This monkey patch allows it work on Python 2 or 3 the same way
64 # TODO: implement a command 'waf help' that shows the basic tasks a
65 # developer might want to do: e.g. how to configure a board, compile a
66 # vehicle, compile all the examples, add a new example. Should fit in
67 # less than a terminal screen, ideally commands should be copy
68 # pastable. Add the 'export waf="$PWD/waf"' trick to be copy-pastable
69 # as well.
71 # TODO: replace defines with the use of the generated ap_config.h file
72 # this makes recompilation at least when defines change. which might
73 # be sufficient.
75 # Default installation prefix for Linux boards
76 default_prefix = '/usr/'
78 # Override Build execute and Configure post_recurse methods for autoconfigure purposes
79 Build.BuildContext.execute = ardupilotwaf.ap_autoconfigure(Build.BuildContext.execute)
80 Configure.ConfigurationContext.post_recurse = ardupilotwaf.ap_configure_post_recurse()
83 def _set_build_context_variant(board):
84     for c in Context.classes:
85         if not issubclass(c, Build.BuildContext):
86             continue
87         c.variant = board
89 # Remove all submodules and then sync
90 @conf
91 def submodule_force_clean(ctx):
92     whitelist = {
93                             'COLCON_IGNORE',
94                             'esp_idf',
95                           }
97     # Get all items in the modules folder
98     module_list = os.scandir('modules')
100     # Delete all directories except those in the whitelist
101     for module in module_list:
102         if (module.is_dir()) and (module.name not in whitelist):
103             shutil.rmtree(module)
105     submodulesync(ctx)
107 # run Tools/gittools/submodule-sync.sh to sync submodules
108 @conf
109 def submodulesync(ctx):
110     subprocess.call(['Tools/gittools/submodule-sync.sh'])
112 def init(ctx):
113     # Generate Task List, so that VS Code extension can keep track
114     # of changes to possible build targets
115     generate_tasklist(ctx, False)
116     env = ConfigSet.ConfigSet()
117     try:
118         p = os.path.join(Context.out_dir, Build.CACHE_DIR, Build.CACHE_SUFFIX)
119         env.load(p)
120     except EnvironmentError:
121         return
123     Configure.autoconfig = 'clobber' if env.AUTOCONFIG else False
125     board = ctx.options.board or env.BOARD
127     if not board:
128         return
130     # define the variant build commands according to the board
131     _set_build_context_variant(board)
133 def options(opt):
134     opt.load('compiler_cxx compiler_c waf_unit_test python')
135     opt.load('ardupilotwaf')
136     opt.load('build_summary')
138     g = opt.ap_groups['configure']
140     boards_names = boards.get_boards_names()
141     removed_names = boards.get_removed_boards()
142     g.add_option('--board',
143         action='store',
144         default=None,
145         help='Target board to build, choices are %s.' % ', '.join(boards_names))
147     g.add_option('--debug',
148         action='store_true',
149         default=False,
150         help='Configure as debug variant.')
152     g.add_option('--debug-symbols', '-g',
153         action='store_true',
154         default=False,
155         help='Add debug symbolds to build.')
156     
157     g.add_option('--disable-watchdog',
158         action='store_true',
159         default=False,
160         help='Build with watchdog disabled.')
162     g.add_option('--coverage',
163                  action='store_true',
164                  default=False,
165                  help='Configure coverage flags.')
167     g.add_option('--Werror',
168         action='store_true',
169         default=None,
170         help='build with -Werror.')
172     g.add_option('--disable-Werror',
173         action='store_true',
174         default=None,
175         help='Disable -Werror.')
176     
177     g.add_option('--toolchain',
178         action='store',
179         default=None,
180         help='Override default toolchain used for the board. Use "native" for using the host toolchain.')
182     g.add_option('--disable-gccdeps',
183         action='store_true',
184         default=False,
185         help='Disable the use of GCC dependencies output method and use waf default method.')
187     g.add_option('--enable-asserts',
188         action='store_true',
189         default=False,
190         help='enable OS level asserts.')
192     g.add_option('--save-temps',
193         action='store_true',
194         default=False,
195         help='save compiler temporary files.')
196     
197     g.add_option('--enable-malloc-guard',
198         action='store_true',
199         default=False,
200         help='enable malloc guard regions.')
202     g.add_option('--enable-stats',
203         action='store_true',
204         default=False,
205         help='enable OS level thread statistics.')
207     g.add_option('--enable-ppp',
208         action='store_true',
209         default=False,
210         help='enable PPP networking.')
211     
212     g.add_option('--bootloader',
213         action='store_true',
214         default=False,
215         help='Configure for building a bootloader.')
217     g.add_option('--signed-fw',
218         action='store_true',
219         default=False,
220         help='Configure for signed firmware support.')
222     g.add_option('--private-key',
223                  action='store',
224                  default=None,
225             help='path to private key for signing firmware.')
226     
227     g.add_option('--no-autoconfig',
228         dest='autoconfig',
229         action='store_false',
230         default=True,
231         help='''Disable autoconfiguration feature. By default, the build system
232 triggers a reconfiguration whenever it thinks it's necessary - this
233 option disables that.
234 ''')
236     g.add_option('--no-submodule-update',
237         dest='submodule_update',
238         action='store_false',
239         default=True,
240         help='''Don't update git submodules. Useful for building with
241 submodules at specific revisions.
242 ''')
244     g.add_option('--enable-header-checks', action='store_true',
245         default=False,
246         help="Enable checking of headers")
248     g.add_option('--default-parameters',
249         default=None,
250         help='set default parameters to embed in the firmware')
252     g.add_option('--enable-math-check-indexes',
253                  action='store_true',
254                  default=False,
255                  help="Enable checking of math indexes")
257     g.add_option('--disable-scripting', action='store_true',
258                  default=False,
259                  help="Disable onboard scripting engine")
261     g.add_option('--enable-scripting', action='store_true',
262                  default=False,
263                  help="Enable onboard scripting engine")
265     g.add_option('--no-gcs', action='store_true',
266                  default=False,
267                  help="Disable GCS code")
268     
269     g.add_option('--scripting-checks', action='store_true',
270                  default=True,
271                  help="Enable runtime scripting sanity checks")
273     g.add_option('--enable-onvif', action='store_true',
274                  default=False,
275                  help="Enables and sets up ONVIF camera control")
277     g.add_option('--scripting-docs', action='store_true',
278                  default=False,
279                  help="enable generation of scripting documentation")
281     g.add_option('--enable-opendroneid', action='store_true',
282                  default=False,
283                  help="Enables OpenDroneID")
285     g.add_option('--enable-check-firmware', action='store_true',
286                  default=False,
287                  help="Enables firmware ID checking on boot")
289     g.add_option('--enable-custom-controller', action='store_true',
290                  default=False,
291                  help="Enables custom controller")
293     g.add_option('--enable-gps-logging', action='store_true',
294                  default=False,
295                  help="Enables GPS logging")
296     
297     g.add_option('--enable-dds', action='store_true',
298                  help="Enable the dds client to connect with ROS2/DDS.")
300     g.add_option('--disable-networking', action='store_true',
301                  help="Disable the networking API code")
303     g.add_option('--enable-networking-tests', action='store_true',
304                  help="Enable the networking test code. Automatically enables networking.")
305     
306     g.add_option('--enable-dronecan-tests', action='store_true',
307                  default=False,
308                  help="Enables DroneCAN tests in sitl")
309     g = opt.ap_groups['linux']
311     linux_options = ('--prefix', '--destdir', '--bindir', '--libdir')
312     for k in linux_options:
313         option = opt.parser.get_option(k)
314         if option:
315             opt.parser.remove_option(k)
316             g.add_option(option)
318     g.add_option('--apstatedir',
319         action='store',
320         default='',
321         help='''Where to save data like parameters, log and terrain.
322 This is the --localstatedir + ArduPilots subdirectory [default:
323 board-dependent, usually /var/lib/ardupilot]''')
325     g.add_option('--rsync-dest',
326         dest='rsync_dest',
327         action='store',
328         default='',
329         help='''Destination for the rsync Waf command. It can be passed during
330 configuration in order to save typing.
331 ''')
333     g.add_option('--enable-benchmarks',
334         action='store_true',
335         default=False,
336         help='Enable benchmarks.')
338     g.add_option('--enable-lttng', action='store_true',
339         default=False,
340         help="Enable lttng integration")
342     g.add_option('--disable-libiio', action='store_true',
343         default=False,
344         help="Don't use libiio even if supported by board and dependencies available")
346     g.add_option('--disable-tests', action='store_true',
347         default=False,
348         help="Disable compilation and test execution")
350     g.add_option('--enable-sfml', action='store_true',
351                  default=False,
352                  help="Enable SFML graphics library")
354     g.add_option('--enable-sfml-joystick', action='store_true',
355                  default=False,
356                  help="Enable SFML joystick input library")
358     g.add_option('--enable-sfml-audio', action='store_true',
359                  default=False,
360                  help="Enable SFML audio library")
362     g.add_option('--osd', action='store_true',
363                  default=False,
364                  help="Enable OSD support")
366     g.add_option('--osd-fonts', action='store_true',
367                  default=False,
368                  help="Enable OSD support with fonts")
369     
370     g.add_option('--sitl-osd', action='store_true',
371                  default=False,
372                  help="Enable SITL OSD")
374     g.add_option('--sitl-rgbled', action='store_true',
375                  default=False,
376                  help="Enable SITL RGBLed")
378     g.add_option('--force-32bit', action='store_true',
379                  default=False,
380                  help="Force 32bit build")
382     g.add_option('--build-dates', action='store_true',
383                  default=False,
384                  help="Include build date in binaries.  Appears in AUTOPILOT_VERSION.os_sw_version")
386     g.add_option('--sitl-flash-storage',
387         action='store_true',
388         default=False,
389         help='Use flash storage emulation.')
391     g.add_option('--enable-ekf2',
392         action='store_true',
393         default=False,
394         help='Configure with EKF2.')
396     g.add_option('--disable-ekf3',
397         action='store_true',
398         default=False,
399         help='Configure without EKF3.')
401     g.add_option('--ekf-double',
402         action='store_true',
403         default=False,
404         help='Configure EKF as double precision.')
406     g.add_option('--ekf-single',
407         action='store_true',
408         default=False,
409         help='Configure EKF as single precision.')
410     
411     g.add_option('--static',
412         action='store_true',
413         default=False,
414         help='Force a static build')
416     g.add_option('--postype-single',
417         action='store_true',
418         default=False,
419         help='force single precision postype_t')
421     g.add_option('--consistent-builds',
422         action='store_true',
423         default=False,
424         help='force consistent build outputs for things like __LINE__')
426     g.add_option('--extra-hwdef',
427             action='store',
428             default=None,
429             help='Extra hwdef.dat file for custom build.')
431     g.add_option('--assert-cc-version',
432                  default=None,
433                  help='fail configure if not using the specified gcc version')
435     g.add_option('--num-aux-imus',
436                  type='int',
437                  default=0,
438                  help='number of auxiliary IMUs')
440     g.add_option('--board-start-time',
441                  type='int',
442                  default=0,
443                  help='zero time on boot in microseconds')
444     
445 def _collect_autoconfig_files(cfg):
446     for m in sys.modules.values():
447         paths = []
448         if hasattr(m, '__file__') and m.__file__ is not None:
449             paths.append(m.__file__)
450         elif hasattr(m, '__path__'):
451             for p in m.__path__:
452                 if p is not None:
453                     paths.append(p)
455         for p in paths:
456             if p in cfg.files or not os.path.isfile(p):
457                 continue
459             with open(p, 'rb') as f:
460                 cfg.hash = Utils.h_list((cfg.hash, f.read()))
461                 cfg.files.append(p)
463 def configure(cfg):
464         # we need to enable debug mode when building for gconv, and force it to sitl
465     if cfg.options.board is None:
466         cfg.options.board = 'sitl'
468     boards_names = boards.get_boards_names()
469     if not cfg.options.board in boards_names:
470         for b in boards_names:
471             if b.upper() == cfg.options.board.upper():
472                 cfg.options.board = b
473                 break
474         
475     cfg.env.BOARD = cfg.options.board
476     cfg.env.DEBUG = cfg.options.debug
477     cfg.env.DEBUG_SYMBOLS = cfg.options.debug_symbols
478     cfg.env.COVERAGE = cfg.options.coverage
479     cfg.env.AUTOCONFIG = cfg.options.autoconfig
481     _set_build_context_variant(cfg.env.BOARD)
482     cfg.setenv(cfg.env.BOARD)
484     if cfg.options.signed_fw:
485         cfg.env.AP_SIGNED_FIRMWARE = True
486         cfg.options.enable_check_firmware = True
488     cfg.env.BOARD = cfg.options.board
489     cfg.env.DEBUG = cfg.options.debug
490     cfg.env.DEBUG_SYMBOLS = cfg.options.debug_symbols
491     cfg.env.COVERAGE = cfg.options.coverage
492     cfg.env.FORCE32BIT = cfg.options.force_32bit
493     cfg.env.ENABLE_ASSERTS = cfg.options.enable_asserts
494     cfg.env.BOOTLOADER = cfg.options.bootloader
495     cfg.env.ENABLE_MALLOC_GUARD = cfg.options.enable_malloc_guard
496     cfg.env.ENABLE_STATS = cfg.options.enable_stats
497     cfg.env.SAVE_TEMPS = cfg.options.save_temps
499     cfg.env.HWDEF_EXTRA = cfg.options.extra_hwdef
500     if cfg.env.HWDEF_EXTRA:
501         cfg.env.HWDEF_EXTRA = os.path.abspath(cfg.env.HWDEF_EXTRA)
503     cfg.env.OPTIONS = cfg.options.__dict__
505     # Allow to differentiate our build from the make build
506     cfg.define('WAF_BUILD', 1)
508     cfg.msg('Autoconfiguration', 'enabled' if cfg.options.autoconfig else 'disabled')
510     if cfg.options.static:
511         cfg.msg('Using static linking', 'yes', color='YELLOW')
512         cfg.env.STATIC_LINKING = True
514     if cfg.options.num_aux_imus > 0:
515         cfg.define('INS_AUX_INSTANCES', cfg.options.num_aux_imus)
517     if cfg.options.board_start_time != 0:
518         cfg.define('AP_BOARD_START_TIME', cfg.options.board_start_time)
519         # also in env for hrt.c
520         cfg.env.AP_BOARD_START_TIME = cfg.options.board_start_time
522     # require python 3.8.x or later
523     cfg.load('python')
524     cfg.check_python_version(minver=(3,6,9))
526     cfg.load('ap_library')
528     cfg.msg('Setting board to', cfg.options.board)
529     cfg.get_board().configure(cfg)
531     cfg.load('waf_unit_test')
532     cfg.load('mavgen')
533     cfg.load('dronecangen')
535     cfg.env.SUBMODULE_UPDATE = cfg.options.submodule_update
537     cfg.start_msg('Source is git repository')
538     if cfg.srcnode.find_node('.git'):
539         cfg.end_msg('yes')
540     else:
541         cfg.end_msg('no')
542         cfg.env.SUBMODULE_UPDATE = False
544     cfg.msg('Update submodules', 'yes' if cfg.env.SUBMODULE_UPDATE else 'no')
545     cfg.load('git_submodule')
547     if cfg.options.enable_benchmarks:
548         cfg.load('gbenchmark')
549     cfg.load('gtest')
550     cfg.load('static_linking')
551     cfg.load('build_summary')
553     cfg.start_msg('Benchmarks')
554     if cfg.env.HAS_GBENCHMARK:
555         cfg.end_msg('enabled')
556     else:
557         cfg.end_msg('disabled', color='YELLOW')
559     cfg.start_msg('Unit tests')
560     if cfg.env.HAS_GTEST:
561         cfg.end_msg('enabled')
562     else:
563         cfg.end_msg('disabled', color='YELLOW')
565     cfg.start_msg('Scripting')
566     if cfg.options.disable_scripting:
567         cfg.end_msg('disabled', color='YELLOW')
568     elif cfg.options.enable_scripting:
569         cfg.end_msg('enabled')
570     else:
571         cfg.end_msg('maybe')
572     cfg.recurse('libraries/AP_Scripting')
574     cfg.recurse('libraries/AP_GPS')
575     cfg.recurse('libraries/AP_HAL_SITL')
576     cfg.recurse('libraries/SITL')
578     cfg.recurse('libraries/AP_Networking')
580     cfg.start_msg('Scripting runtime checks')
581     if cfg.options.scripting_checks:
582         cfg.end_msg('enabled')
583     else:
584         cfg.end_msg('disabled', color='YELLOW')
586     cfg.start_msg('Debug build')
587     if cfg.env.DEBUG:
588         cfg.end_msg('enabled')
589     else:
590         cfg.end_msg('disabled', color='YELLOW')
592     cfg.start_msg('Coverage build')
593     if cfg.env.COVERAGE:
594         cfg.end_msg('enabled')
595     else:
596         cfg.end_msg('disabled', color='YELLOW')
598     cfg.start_msg('Force 32-bit build')
599     if cfg.env.FORCE32BIT:
600         cfg.end_msg('enabled')
601     else:
602         cfg.end_msg('disabled', color='YELLOW')
604     cfg.env.append_value('GIT_SUBMODULES', 'mavlink')
606     cfg.env.prepend_value('INCLUDES', [
607         cfg.srcnode.abspath() + '/libraries/',
608     ])
610     cfg.find_program('rsync', mandatory=False)
611     if cfg.options.rsync_dest:
612         cfg.msg('Setting rsync destination to', cfg.options.rsync_dest)
613         cfg.env.RSYNC_DEST = cfg.options.rsync_dest
615     if cfg.options.enable_header_checks:
616         cfg.msg('Enabling header checks', cfg.options.enable_header_checks)
617         cfg.env.ENABLE_HEADER_CHECKS = True
618     else:
619         cfg.env.ENABLE_HEADER_CHECKS = False
621     # Always use system extensions
622     cfg.define('_GNU_SOURCE', 1)
624     if cfg.options.Werror:
625         # print(cfg.options.Werror)
626         if cfg.options.disable_Werror:
627             cfg.options.Werror = False
629     cfg.write_config_header(os.path.join(cfg.variant, 'ap_config.h'), guard='_AP_CONFIG_H_')
631     # add in generated flags
632     cfg.env.CXXFLAGS += ['-include', 'ap_config.h']
634     _collect_autoconfig_files(cfg)
636 def collect_dirs_to_recurse(bld, globs, **kw):
637     dirs = []
638     globs = Utils.to_list(globs)
640     if bld.bldnode.is_child_of(bld.srcnode):
641         kw['excl'] = Utils.to_list(kw.get('excl', []))
642         kw['excl'].append(bld.bldnode.path_from(bld.srcnode))
644     for g in globs:
645         for d in bld.srcnode.ant_glob(g + '/wscript', **kw):
646             dirs.append(d.parent.relpath())
647     return dirs
649 def list_boards(ctx):
650     print(*boards.get_boards_names())
652 def list_ap_periph_boards(ctx):
653     print(*boards.get_ap_periph_boards())
655 @conf
656 def ap_periph_boards(ctx):
657     return boards.get_ap_periph_boards()
659 vehicles = ['antennatracker', 'blimp', 'copter', 'heli', 'plane', 'rover', 'sub']
661 def generate_tasklist(ctx, do_print=True):
662     boardlist = boards.get_boards_names()
663     ap_periph_targets = boards.get_ap_periph_boards()
664     tasks = []
665     with open(os.path.join(Context.top_dir, "tasklist.json"), "w") as tlist:
666         for board in boardlist:
667             task = {}
668             task['configure'] = board
669             if board in ap_periph_targets:
670                 if 'sitl' not in board:
671                     # we only support AP_Periph and bootloader builds
672                     task['targets'] = ['AP_Periph', 'bootloader']
673                 else:
674                     task['targets'] = ['AP_Periph']
675             elif 'iofirmware' in board:
676                 task['targets'] = ['iofirmware', 'bootloader']
677             else:
678                 if boards.is_board_based(board, boards.sitl):
679                     task['targets'] = vehicles + ['replay']
680                 elif boards.is_board_based(board, boards.linux):
681                     task['targets'] = vehicles
682                 else:
683                     task['targets'] = vehicles + ['bootloader']
684                     task['buildOptions'] = '--upload'
685             tasks.append(task)
686         tlist.write(json.dumps(tasks))
687         if do_print:
688             print(json.dumps(tasks))
690 def board(ctx):
691     env = ConfigSet.ConfigSet()
692     try:
693         p = os.path.join(Context.out_dir, Build.CACHE_DIR, Build.CACHE_SUFFIX)
694         env.load(p)
695     except:
696         print('No board currently configured')
697         return
699     print('Board configured to: {}'.format(env.BOARD))
701 def _build_cmd_tweaks(bld):
702     if bld.cmd == 'check-all':
703         bld.options.all_tests = True
704         bld.cmd = 'check'
706     if bld.cmd == 'check':
707         if not bld.env.HAS_GTEST:
708             bld.fatal('check: gtest library is required')
709         bld.options.clear_failed_tests = True
711 def _build_dynamic_sources(bld):
712     if not bld.env.BOOTLOADER:
713         bld(
714             features='mavgen',
715             source='modules/mavlink/message_definitions/v1.0/all.xml',
716             output_dir='libraries/GCS_MAVLink/include/mavlink/v2.0/',
717             name='mavlink',
718             # this below is not ideal, mavgen tool should set this, but that's not
719             # currently possible
720             export_includes=[
721             bld.bldnode.make_node('libraries').abspath(),
722             bld.bldnode.make_node('libraries/GCS_MAVLink').abspath(),
723             ],
724             )
726     if (bld.get_board().with_can or bld.env.HAL_NUM_CAN_IFACES) and not bld.env.AP_PERIPH:
727         bld(
728             features='dronecangen',
729             source=bld.srcnode.ant_glob('modules/DroneCAN/DSDL/[a-z]* libraries/AP_DroneCAN/dsdl/[a-z]*', dir=True, src=False),
730             output_dir='modules/DroneCAN/libcanard/dsdlc_generated/',
731             name='dronecan',
732             export_includes=[
733                 bld.bldnode.make_node('modules/DroneCAN/libcanard/dsdlc_generated/include').abspath(),
734                 bld.srcnode.find_dir('modules/DroneCAN/libcanard/').abspath(),
735                 bld.srcnode.find_dir('libraries/AP_DroneCAN/canard/').abspath(),
736                 ]
737             )
738     elif bld.env.AP_PERIPH:
739         bld(
740             features='dronecangen',
741             source=bld.srcnode.ant_glob('modules/DroneCAN/DSDL/* libraries/AP_DroneCAN/dsdl/*', dir=True, src=False),
742             output_dir='modules/DroneCAN/libcanard/dsdlc_generated/',
743             name='dronecan',
744             export_includes=[
745                 bld.bldnode.make_node('modules/DroneCAN/libcanard/dsdlc_generated/include').abspath(),
746                 bld.srcnode.find_dir('modules/DroneCAN/libcanard/').abspath(),
747             ]
748         )
750     if bld.env.ENABLE_DDS:
751         bld.recurse("libraries/AP_DDS")
753     def write_version_header(tsk):
754         bld = tsk.generator.bld
755         return bld.write_version_header(tsk.outputs[0].abspath())
757     bld(
758         name='ap_version',
759         target='ap_version.h',
760         vars=['AP_VERSION_ITEMS'],
761         rule=write_version_header,
762     )
764     bld.env.prepend_value('INCLUDES', [
765         bld.bldnode.abspath(),
766     ])
768 def _build_common_taskgens(bld):
769     # NOTE: Static library with vehicle set to UNKNOWN, shared by all
770     # the tools and examples. This is the first step until the
771     # dependency on the vehicles is reduced. Later we may consider
772     # split into smaller pieces with well defined boundaries.
773     bld.ap_stlib(
774         name='ap',
775         ap_vehicle='UNKNOWN',
776         ap_libraries=bld.ap_get_all_libraries(),
777     )
779     if bld.env.HAS_GTEST:
780         bld.libgtest(cxxflags=['-include', 'ap_config.h'])
782     if bld.env.HAS_GBENCHMARK:
783         bld.libbenchmark()
785 def _build_recursion(bld):
786     common_dirs_patterns = [
787         # TODO: Currently each vehicle also generate its own copy of the
788         # libraries. Fix this, or at least reduce the amount of
789         # vehicle-dependent libraries.
790         '*',
791         'Tools/*',
792         'libraries/*/examples/*',
793         'libraries/*/tests',
794         'libraries/*/utility/tests',
795         'libraries/*/benchmarks',
796     ]
798     common_dirs_excl = [
799         'modules',
800         'libraries/AP_HAL_*',
801     ]
803     hal_dirs_patterns = [
804         'libraries/%s/tests',
805         'libraries/%s/*/tests',
806         'libraries/%s/*/benchmarks',
807         'libraries/%s/examples/*',
808     ]
810     dirs_to_recurse = collect_dirs_to_recurse(
811         bld,
812         common_dirs_patterns,
813         excl=common_dirs_excl,
814     )
815     if bld.env.IOMCU_FW is not None:
816         if bld.env.IOMCU_FW:
817             dirs_to_recurse.append('libraries/AP_IOMCU/iofirmware')
819     if bld.env.PERIPH_FW is not None:
820         if bld.env.PERIPH_FW:
821             dirs_to_recurse.append('Tools/AP_Periph')
823     dirs_to_recurse.append('libraries/AP_Scripting')
825     if bld.env.ENABLE_ONVIF:
826         dirs_to_recurse.append('libraries/AP_ONVIF')
828     for p in hal_dirs_patterns:
829         dirs_to_recurse += collect_dirs_to_recurse(
830             bld,
831             [p % l for l in bld.env.AP_LIBRARIES],
832         )
834     # NOTE: we need to sort to ensure the repeated sources get the
835     # same index, and random ordering of the filesystem doesn't cause
836     # recompilation.
837     dirs_to_recurse.sort()
839     for d in dirs_to_recurse:
840         bld.recurse(d)
842 def _build_post_funs(bld):
843     if bld.cmd == 'check':
844         bld.add_post_fun(ardupilotwaf.test_summary)
845     else:
846         bld.build_summary_post_fun()
848     if bld.env.SUBMODULE_UPDATE:
849         bld.git_submodule_post_fun()
851 def _load_pre_build(bld):
852     '''allow for a pre_build() function in build modules'''
853     if bld.cmd == 'clean':
854         return
855     brd = bld.get_board()
856     if getattr(brd, 'pre_build', None):
857         brd.pre_build(bld)    
859 def build(bld):
860     config_hash = Utils.h_file(bld.bldnode.make_node('ap_config.h').abspath())
861     bld.env.CCDEPS = config_hash
862     bld.env.CXXDEPS = config_hash
864     bld.post_mode = Build.POST_LAZY
866     bld.load('ardupilotwaf')
868     bld.env.AP_LIBRARIES_OBJECTS_KW.update(
869         use=['mavlink'],
870         cxxflags=['-include', 'ap_config.h'],
871     )
873     _load_pre_build(bld)
875     if bld.get_board().with_can:
876         bld.env.AP_LIBRARIES_OBJECTS_KW['use'] += ['dronecan']
878     _build_cmd_tweaks(bld)
880     if bld.env.SUBMODULE_UPDATE:
881         bld.add_group('git_submodules')
882         for name in bld.env.GIT_SUBMODULES:
883             bld.git_submodule(name)
885     bld.add_group('dynamic_sources')
886     _build_dynamic_sources(bld)
888     bld.add_group('build')
889     bld.get_board().build(bld)
890     _build_common_taskgens(bld)
892     _build_recursion(bld)
894     _build_post_funs(bld)
896 ardupilotwaf.build_command('check',
897     program_group_list='all',
898     doc='builds all programs and run tests',
900 ardupilotwaf.build_command('check-all',
901     program_group_list='all',
902     doc='shortcut for `waf check --alltests`',
905 for name in (vehicles + ['bootloader','iofirmware','AP_Periph','replay']):
906     ardupilotwaf.build_command(name,
907         program_group_list=name,
908         doc='builds %s programs' % name,
909     )
911 for program_group in ('all', 'bin', 'tool', 'examples', 'tests', 'benchmarks'):
912     ardupilotwaf.build_command(program_group,
913         program_group_list=program_group,
914         doc='builds all programs of %s group' % program_group,
915     )
917 class LocalInstallContext(Build.InstallContext):
918     """runs install using BLD/install as destdir, where BLD is the build variant directory"""
919     cmd = 'localinstall'
921     def __init__(self, **kw):
922         super(LocalInstallContext, self).__init__(**kw)
923         self.local_destdir = os.path.join(self.variant_dir, 'install')
925     def execute(self):
926         old_destdir = self.options.destdir
927         self.options.destdir = self.local_destdir
928         r = super(LocalInstallContext, self).execute()
929         self.options.destdir = old_destdir
930         return r
932 class RsyncContext(LocalInstallContext):
933     """runs localinstall and then rsyncs BLD/install with the target system"""
934     cmd = 'rsync'
936     def __init__(self, **kw):
937         super(RsyncContext, self).__init__(**kw)
938         self.add_pre_fun(RsyncContext.create_rsync_taskgen)
940     def create_rsync_taskgen(self):
941         if 'RSYNC' not in self.env:
942             self.fatal('rsync program seems not to be installed, can\'t continue')
944         self.add_group()
946         tg = self(
947             name='rsync',
948             rule='${RSYNC} -a ${RSYNC_SRC}/ ${RSYNC_DEST}',
949             always=True,
950         )
952         tg.env.RSYNC_SRC = self.local_destdir
953         if self.options.rsync_dest:
954             self.env.RSYNC_DEST = self.options.rsync_dest
956         if 'RSYNC_DEST' not in tg.env:
957             self.fatal('Destination for rsync not defined. Either pass --rsync-dest here or during configuration.')
959         tg.post()