Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/Tools/autotest/test_build_options.py
Views: 1798
#!/usr/bin/env python312"""3Contains functions used to test the ArduPilot build_options.py structures45To extract feature sizes:67cat >> /tmp/extra-hwdef.dat <<EOF8undef AP_BARO_MS56XX_ENABLED9define AP_BARO_MS56XX_ENABLED 110EOF1112nice time ./Tools/autotest/test_build_options.py --board=CubeOrange --extra-hwdef=/tmp/extra-hwdef.dat --no-run-with-defaults --no-disable-all --no-enable-in-turn | tee /tmp/tbo-out # noqa13grep 'sabling.*saves' /tmp/tbo-out1415- note that a lot of the time explicitly disabling features will make the binary larger as the ROMFS includes the generated hwdef.h which will have the extra define in it # noqa1617AP_FLAKE8_CLEAN18"""1920from __future__ import print_function2122import fnmatch23import optparse24import os25import pathlib26import re27import sys2829from pysim import util3031sys.path.insert(1, os.path.join(os.path.dirname(__file__), '..', 'scripts'))32import extract_features # noqa333435class TestBuildOptionsResult(object):36'''object to return results from a comparison'''3738def __init__(self, feature, vehicle, bytes_delta):39self.feature = feature40self.vehicle = vehicle41self.bytes_delta = bytes_delta424344class TestBuildOptions(object):45def __init__(self,46match_glob=None,47do_step_disable_all=True,48do_step_disable_none=False,49do_step_disable_defaults=True,50do_step_disable_in_turn=True,51do_step_enable_in_turn=True,52build_targets=None,53board="CubeOrange", # DevEBoxH7v2 also works54extra_hwdef=None,55emit_disable_all_defines=None,56resume=False,57):58self.extra_hwdef = extra_hwdef59self.sizes_nothing_disabled = None60self.match_glob = match_glob61self.do_step_disable_all = do_step_disable_all62self.do_step_disable_none = do_step_disable_none63self.do_step_run_with_defaults = do_step_disable_defaults64self.do_step_disable_in_turn = do_step_disable_in_turn65self.do_step_enable_in_turn = do_step_enable_in_turn66self.build_targets = build_targets67if self.build_targets is None:68self.build_targets = self.all_targets()69self._board = board70self.emit_disable_all_defines = emit_disable_all_defines71self.resume = resume72self.results = {}7374self.enable_in_turn_results = {}75self.sizes_everything_disabled = None7677def must_have_defines_for_board(self, board):78'''return a set of defines which must always be enabled'''79must_have_defines = {80"CubeOrange": frozenset([81'AP_BARO_MS56XX_ENABLED',82'AP_COMPASS_LSM303D_ENABLED',83'AP_COMPASS_AK8963_ENABLED',84'AP_COMPASS_AK09916_ENABLED',85'AP_COMPASS_ICM20948_ENABLED',86]),87"CubeBlack": frozenset([88'AP_BARO_MS56XX_ENABLED',89'AP_COMPASS_LSM303D_ENABLED',90'AP_COMPASS_AK8963_ENABLED',91'AP_COMPASS_AK09916_ENABLED',92'AP_COMPASS_ICM20948_ENABLED',93]),94"Pixhawk6X-GenericVehicle": frozenset([95"AP_BARO_BMP388_ENABLED",96"AP_BARO_ICP201XX_ENABLED",97]),98}99return must_have_defines.get(board, frozenset([]))100101def must_have_defines(self):102return self.must_have_defines_for_board(self._board)103104@staticmethod105def all_targets():106return ['copter', 'plane', 'rover', 'antennatracker', 'sub', 'blimp']107108def progress(self, message):109print("###### %s" % message, file=sys.stderr)110111# swiped from app.py:112def get_build_options_from_ardupilot_tree(self):113'''return a list of build options'''114import importlib.util115spec = importlib.util.spec_from_file_location(116"build_options.py",117os.path.join(os.path.dirname(os.path.realpath(__file__)),118'..', 'scripts', 'build_options.py'))119mod = importlib.util.module_from_spec(spec)120spec.loader.exec_module(mod)121return mod.BUILD_OPTIONS122123def write_defines_to_file(self, defines, filepath):124self.write_defines_to_Path(defines, pathlib.Path(filepath))125126def write_defines_to_Path(self, defines, Path):127lines = []128lines.extend(["undef %s\n" % (a, ) for (a, b) in defines.items()])129lines.extend(["define %s %s\n" % (a, b) for (a, b) in defines.items()])130content = "".join(lines)131Path.write_text(content)132133def get_disable_defines(self, feature, options):134'''returns a hash of (name, value) defines to turn feature off -135recursively gets dependencies'''136ret = {137feature.define: 0,138}139added_one = True140while added_one:141added_one = False142for option in options:143if option.define in ret:144continue145if option.dependency is None:146continue147for dep in option.dependency.split(','):148f = self.get_option_by_label(dep, options)149if f.define not in ret:150continue151152# print("%s requires %s" % (option.define, f.define), file=sys.stderr)153added_one = True154ret[option.define] = 0155break156return ret157158def update_get_enable_defines_for_feature(self, ret, feature, options):159'''recursive function to turn on required feature and what it depends160on'''161ret[feature.define] = 1162if feature.dependency is None:163return164for depname in feature.dependency.split(','):165dep = None166for f in options:167if f.label == depname:168dep = f169if dep is None:170raise ValueError("Invalid dep (%s) for feature (%s)" %171(depname, feature.label))172self.update_get_enable_defines_for_feature(ret, dep, options)173174def get_enable_defines(self, feature, options):175'''returns a hash of (name, value) defines to turn all features *but* feature (and whatever it depends on) on'''176ret = self.get_disable_all_defines()177self.update_get_enable_defines_for_feature(ret, feature, options)178for define in self.must_have_defines_for_board(self._board):179ret[define] = 1180return ret181182def test_disable_feature(self, feature, options):183defines = self.get_disable_defines(feature, options)184185if len(defines.keys()) > 1:186self.progress("Disabling %s disables (%s)" % (187feature.define,188",".join(defines.keys())))189190self.test_compile_with_defines(defines)191192self.assert_feature_not_in_code(defines, feature)193194def assert_feature_not_in_code(self, defines, feature):195# if the feature is truly disabled then extract_features.py196# should say so:197for target in self.build_targets:198path = self.target_to_elf_path(target)199extracter = extract_features.ExtractFeatures(path)200(compiled_in_feature_defines, not_compiled_in_feature_defines) = extracter.extract()201for define in defines:202# the following defines are known not to work on some203# or all vehicles:204feature_define_whitelist = set([205'AP_RANGEFINDER_ENABLED', # only at vehicle level ATM206'HAL_PERIPH_SUPPORT_LONG_CAN_PRINTF', # no symbol207])208if define in compiled_in_feature_defines:209error = f"feature gated by {define} still compiled into ({target}); extract_features.py bug?"210if define in feature_define_whitelist:211print("warn: " + error)212else:213raise ValueError(error)214215def test_enable_feature(self, feature, options):216defines = self.get_enable_defines(feature, options)217218enabled = list(filter(lambda x : bool(defines[x]), defines.keys()))219220if len(enabled) > 1:221self.progress("Enabling %s enables (%s)" % (222feature.define,223",".join(enabled)))224225self.test_compile_with_defines(defines)226227self.assert_feature_in_code(defines, feature)228229def define_is_whitelisted_for_feature_in_code(self, target, define):230'''returns true if we can not expect the define to be extracted from231the binary'''232# the following defines are known not to work on some233# or all vehicles:234feature_define_whitelist = set([235'AP_RANGEFINDER_ENABLED', # only at vehicle level ATM236'HAL_PERIPH_SUPPORT_LONG_CAN_PRINTF', # no symbol237'AP_DRONECAN_VOLZ_FEEDBACK_ENABLED', # broken, no subscriber238# Baro drivers either come in because you have239# external-probing enabled or you have them specified in240# your hwdef. If you're not probing and its not in your241# hwdef then the code will be elided as unreachable242'AP_BARO_ICM20789_ENABLED',243'AP_BARO_ICP101XX_ENABLED',244'AP_BARO_ICP201XX_ENABLED',245'AP_BARO_BMP085_ENABLED',246'AP_BARO_BMP280_ENABLED',247'AP_BARO_BMP388_ENABLED',248'AP_BARO_BMP581_ENABLED',249'AP_BARO_DPS280_ENABLED',250'AP_BARO_FBM320_ENABLED',251'AP_BARO_KELLERLD_ENABLED',252'AP_BARO_LPS2XH_ENABLED',253'AP_BARO_MS56XX_ENABLED',254'AP_BARO_SPL06_ENABLED',255'AP_CAMERA_SEND_FOV_STATUS_ENABLED', # elided unless AP_CAMERA_SEND_FOV_STATUS_ENABLED256'AP_COMPASS_LSM9DS1_ENABLED', # must be in hwdef, not probed257'AP_COMPASS_MAG3110_ENABLED', # must be in hwdef, not probed258'AP_COMPASS_MMC5XX3_ENABLED', # must be in hwdef, not probed259'AP_MAVLINK_AUTOPILOT_VERSION_REQUEST_ENABLED', # completely elided260'AP_MAVLINK_MSG_RELAY_STATUS_ENABLED', # no symbol available261'AP_MAVLINK_MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES_ENABLED', # no symbol available262'HAL_MSP_SENSORS_ENABLED', # no symbol available263'AP_OSD_LINK_STATS_EXTENSIONS_ENABLED', # FIXME: need a new define/feature264'HAL_OSD_SIDEBAR_ENABLE', # FIXME: need a new define/feature265'HAL_PLUSCODE_ENABLE', # FIXME: need a new define/feature266'AP_SERIALMANAGER_REGISTER_ENABLED', # completely elided without a caller267'AP_OPTICALFLOW_ONBOARD_ENABLED', # only instantiated on Linux268'HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL', # entirely elided if no user269'AP_PLANE_BLACKBOX_LOGGING', # entirely elided if no user270'AP_COMPASS_AK8963_ENABLED', # probed on a board-by-board basis, not on CubeOrange for example271'AP_COMPASS_LSM303D_ENABLED', # probed on a board-by-board basis, not on CubeOrange for example272])273if target.lower() != "copter":274feature_define_whitelist.add('MODE_ZIGZAG_ENABLED')275feature_define_whitelist.add('MODE_SYSTEMID_ENABLED')276feature_define_whitelist.add('MODE_SPORT_ENABLED')277feature_define_whitelist.add('MODE_FOLLOW_ENABLED')278feature_define_whitelist.add('MODE_TURTLE_ENABLED')279feature_define_whitelist.add('MODE_GUIDED_NOGPS_ENABLED')280feature_define_whitelist.add('MODE_FLOWHOLD_ENABLED')281feature_define_whitelist.add('MODE_FLIP_ENABLED')282feature_define_whitelist.add('MODE_BRAKE_ENABLED')283feature_define_whitelist.add('AP_TEMPCALIBRATION_ENABLED')284feature_define_whitelist.add('AC_PAYLOAD_PLACE_ENABLED')285feature_define_whitelist.add('AP_AVOIDANCE_ENABLED')286feature_define_whitelist.add('AP_WINCH_ENABLED')287feature_define_whitelist.add('AP_WINCH_DAIWA_ENABLED')288feature_define_whitelist.add('AP_WINCH_PWM_ENABLED')289feature_define_whitelist.add(r'AP_MOTORS_FRAME_.*_ENABLED')290feature_define_whitelist.add('AP_COPTER_ADVANCED_FAILSAFE_ENABLED')291feature_define_whitelist.add('AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED')292293if target.lower() != "plane":294# only on Plane:295feature_define_whitelist.add('AP_ICENGINE_ENABLED')296feature_define_whitelist.add('AP_PLANE_OFFBOARD_GUIDED_SLEW_ENABLED')297feature_define_whitelist.add('AP_MAVLINK_MAV_CMD_SET_HAGL_ENABLED')298feature_define_whitelist.add('AP_ADVANCEDFAILSAFE_ENABLED')299feature_define_whitelist.add('AP_TUNING_ENABLED')300feature_define_whitelist.add('HAL_LANDING_DEEPSTALL_ENABLED')301feature_define_whitelist.add('HAL_SOARING_ENABLED')302feature_define_whitelist.add('AP_PLANE_BLACKBOX_LOGGING')303feature_define_whitelist.add('QAUTOTUNE_ENABLED')304feature_define_whitelist.add('AP_PLANE_OFFBOARD_GUIDED_SLEW_ENABLED')305feature_define_whitelist.add('HAL_QUADPLANE_ENABLED')306feature_define_whitelist.add('AP_BATTERY_WATT_MAX_ENABLED')307feature_define_whitelist.add('MODE_AUTOLAND_ENABLED')308feature_define_whitelist.add('AP_PLANE_GLIDER_PULLUP_ENABLED')309feature_define_whitelist.add('AP_QUICKTUNE_ENABLED')310311if target.lower() not in ["plane", "copter"]:312feature_define_whitelist.add('HAL_ADSB_ENABLED')313feature_define_whitelist.add('AP_LANDINGGEAR_ENABLED')314# only Plane and Copter instantiate Parachute315feature_define_whitelist.add('HAL_PARACHUTE_ENABLED')316# only Plane and Copter have AP_Motors:317318if target.lower() not in ["rover", "copter"]:319# only Plane and Copter instantiate Beacon320feature_define_whitelist.add('AP_BEACON_ENABLED')321322if target.lower() != "rover":323# only on Rover:324feature_define_whitelist.add('HAL_TORQEEDO_ENABLED')325feature_define_whitelist.add('AP_ROVER_ADVANCED_FAILSAFE_ENABLED')326if target.lower() != "sub":327# only on Sub:328feature_define_whitelist.add('AP_BARO_KELLERLD_ENABLED')329if target.lower() not in frozenset(["rover", "sub"]):330# only Rover and Sub get nmea airspeed331feature_define_whitelist.add('AP_AIRSPEED_NMEA_ENABLED')332if target.lower() not in frozenset(["copter", "rover"]):333feature_define_whitelist.add('HAL_SPRAYER_ENABLED')334feature_define_whitelist.add('HAL_PROXIMITY_ENABLED')335feature_define_whitelist.add('AP_PROXIMITY_.*_ENABLED')336feature_define_whitelist.add('AP_OAPATHPLANNER_ENABLED')337338if target.lower() in ["blimp", "antennatracker"]:339# no airspeed on blimp/tracker340feature_define_whitelist.add(r'AP_AIRSPEED_.*_ENABLED')341feature_define_whitelist.add(r'HAL_MOUNT_ENABLED')342feature_define_whitelist.add(r'AP_MOUNT_.*_ENABLED')343feature_define_whitelist.add(r'HAL_MOUNT_.*_ENABLED')344feature_define_whitelist.add(r'HAL_SOLO_GIMBAL_ENABLED')345feature_define_whitelist.add(r'AP_OPTICALFLOW_ENABLED')346feature_define_whitelist.add(r'AP_OPTICALFLOW_.*_ENABLED')347feature_define_whitelist.add(r'HAL_MSP_OPTICALFLOW_ENABLED')348# missing calls to fence.check():349feature_define_whitelist.add(r'AP_FENCE_ENABLED')350# RPM not instantiated on Blimp or Rover:351feature_define_whitelist.add(r'AP_RPM_ENABLED')352feature_define_whitelist.add(r'AP_RPM_.*_ENABLED')353# rangefinder init is not called:354feature_define_whitelist.add(r'HAL_MSP_RANGEFINDER_ENABLED')355# these guys don't instantiate anything which uses sd-card storage:356feature_define_whitelist.add(r'AP_SDCARD_STORAGE_ENABLED')357feature_define_whitelist.add(r'AP_RANGEFINDER_ENABLED')358feature_define_whitelist.add(r'AP_RANGEFINDER_.*_ENABLED')359360if target.lower() in ["blimp", "antennatracker", "sub"]:361# no OSD on Sub/blimp/tracker362feature_define_whitelist.add(r'OSD_ENABLED')363feature_define_whitelist.add(r'OSD_PARAM_ENABLED')364# AP_OSD is not instantiated, , so no MSP backend:365feature_define_whitelist.add(r'HAL_WITH_MSP_DISPLAYPORT')366# camera instantiated in specific vehicles:367feature_define_whitelist.add(r'AP_CAMERA_ENABLED')368feature_define_whitelist.add(r'AP_CAMERA_.*_ENABLED')369# button update is not called in these vehicles370feature_define_whitelist.add(r'HAL_BUTTON_ENABLED')371# precland not instantiated on these vehicles372feature_define_whitelist.add(r'AC_PRECLAND_ENABLED')373feature_define_whitelist.add(r'AC_PRECLAND_.*_ENABLED')374# RSSI is not initialised - probably should be for some375feature_define_whitelist.add(r'AP_RSSI_ENABLED')376377if target.lower() in ["antennatracker", "sub"]:378# missing the init call to the relay library:379feature_define_whitelist.add(r'AP_RELAY_ENABLED')380feature_define_whitelist.add(r'AP_RC_CHANNEL_AUX_FUNCTION_STRINGS_ENABLED')381382for some_re in feature_define_whitelist:383if re.match(some_re, define):384return True385386def assert_feature_in_code(self, defines, feature):387# if the feature is truly disabled then extract_features.py388# should say so:389for target in self.build_targets:390path = self.target_to_elf_path(target)391extracter = extract_features.ExtractFeatures(path)392(compiled_in_feature_defines, not_compiled_in_feature_defines) = extracter.extract()393for define in defines:394if not defines[define]:395continue396if define in compiled_in_feature_defines:397continue398error = f"feature gated by {define} not compiled into ({target}); extract_features.py bug?"399if self.define_is_whitelisted_for_feature_in_code(target, define):400print("warn: " + error)401continue402raise ValueError(error)403404def board(self):405'''returns board to build for'''406return self._board407408def test_compile_with_defines(self, defines):409extra_hwdef_filepath = "/tmp/extra.hwdef"410self.write_defines_to_file(defines, extra_hwdef_filepath)411if self.extra_hwdef is not None:412content = open(self.extra_hwdef, "r").read()413with open(extra_hwdef_filepath, "a") as f:414f.write(content)415util.waf_configure(416self.board(),417extra_hwdef=extra_hwdef_filepath,418)419for t in self.build_targets:420try:421util.run_cmd([util.relwaf(), t])422except Exception:423print("Failed to build (%s) with things disabled" %424(t,))425raise426427def target_to_path(self, target, extension=None):428'''given a build target (e.g. copter), return expected path to .bin429file for that target'''430target_to_binpath = {431"copter": "arducopter",432"plane": "arduplane",433"rover": "ardurover",434"antennatracker": "antennatracker",435"sub": "ardusub",436"blimp": "blimp",437}438filename = target_to_binpath[target]439if extension is not None:440filename += "." + extension441return os.path.join("build", self.board(), "bin", filename)442443def target_to_bin_path(self, target):444'''given a build target (e.g. copter), return expected path to .bin445file for that target'''446return self.target_to_path(target, 'bin')447448def target_to_elf_path(self, target):449'''given a build target (e.g. copter), return expected path to .elf450file for that target'''451return self.target_to_path(target)452453def find_build_sizes(self):454'''returns a hash with size of all build targets'''455ret = {}456for target in self.build_targets:457path = self.target_to_bin_path(target)458ret[target] = os.path.getsize(path)459return ret460461def csv_for_results(self, results):462'''return a string with csv for results'''463features = sorted(results.keys())464all_vehicles = set()465for feature in features:466all_vehicles.update(list(results[feature].keys()))467sorted_all_vehicles = sorted(list(all_vehicles))468ret = ""469ret += ",".join(["Feature"] + sorted_all_vehicles) + "\n"470for feature in features:471line = [feature]472feature_results = results[feature]473for vehicle in sorted_all_vehicles:474bytes_delta = ""475if vehicle in feature_results:476result = feature_results[vehicle]477bytes_delta = result.bytes_delta478line.append(str(bytes_delta))479ret += ",".join(line) + "\n"480return ret481482def disable_in_turn_check_sizes(self, feature, sizes_nothing_disabled):483if not self.do_step_disable_none:484self.progress("disable-none skipped, size comparison not available")485return486current_sizes = self.find_build_sizes()487for (build, new_size) in current_sizes.items():488old_size = sizes_nothing_disabled[build]489self.progress("Disabling %s(%s) on %s saves %u bytes" %490(feature.label, feature.define, build, old_size - new_size))491if feature.define not in self.results:492self.results[feature.define] = {}493self.results[feature.define][build] = TestBuildOptionsResult(feature.define, build, old_size - new_size)494with open("/tmp/some.csv", "w") as f:495f.write(self.csv_for_results(self.results))496497def run_disable_in_turn(self):498progress_file = pathlib.Path("/tmp/run-disable-in-turn-progress")499resume_number = self.resume_number_from_progress_Path(progress_file)500options = self.get_build_options_from_ardupilot_tree()501count = 1502for feature in sorted(options, key=lambda x : x.define):503if resume_number is not None:504if count < resume_number:505count += 1506continue507if self.match_glob is not None:508if not fnmatch.fnmatch(feature.define, self.match_glob):509continue510with open(progress_file, "w") as f:511f.write(f"{count}/{len(options)} {feature.define}\n")512# if feature.define < "WINCH_ENABLED":513# count += 1514# continue515if feature.define in self.must_have_defines_for_board(self._board):516self.progress("Feature %s(%s) (%u/%u) is a MUST-HAVE" %517(feature.label, feature.define, count, len(options)))518count += 1519continue520self.progress("Disabling feature %s(%s) (%u/%u)" %521(feature.label, feature.define, count, len(options)))522self.test_disable_feature(feature, options)523count += 1524self.disable_in_turn_check_sizes(feature, self.sizes_nothing_disabled)525526def enable_in_turn_check_sizes(self, feature, sizes_everything_disabled):527if not self.do_step_disable_all:528self.progress("disable-none skipped, size comparison not available")529return530current_sizes = self.find_build_sizes()531for (build, new_size) in current_sizes.items():532old_size = sizes_everything_disabled[build]533self.progress("Enabling %s(%s) on %s costs %u bytes" %534(feature.label, feature.define, build, old_size - new_size))535if feature.define not in self.enable_in_turn_results:536self.enable_in_turn_results[feature.define] = {}537self.enable_in_turn_results[feature.define][build] = TestBuildOptionsResult(feature.define, build, old_size - new_size) # noqa538with open("/tmp/enable-in-turn.csv", "w") as f:539f.write(self.csv_for_results(self.enable_in_turn_results))540541def resume_number_from_progress_Path(self, progress_file):542if not self.resume:543return None544try:545content = progress_file.read_text().rstrip()546m = re.match(r"(\d+)/\d+ \w+", content)547if m is None:548raise ValueError(f"{progress_file} not matched")549return int(m.group(1))550except FileNotFoundError:551pass552return None553554def run_enable_in_turn(self):555progress_file = pathlib.Path("/tmp/run-enable-in-turn-progress")556resume_number = self.resume_number_from_progress_Path(progress_file)557options = self.get_build_options_from_ardupilot_tree()558count = 1559for feature in options:560if resume_number is not None:561if count < resume_number:562count += 1563continue564if self.match_glob is not None:565if not fnmatch.fnmatch(feature.define, self.match_glob):566continue567self.progress("Enabling feature %s(%s) (%u/%u)" %568(feature.label, feature.define, count, len(options)))569with open(progress_file, "w") as f:570f.write(f"{count}/{len(options)} {feature.define}\n")571self.test_enable_feature(feature, options)572count += 1573self.enable_in_turn_check_sizes(feature, self.sizes_everything_disabled)574575def get_option_by_label(self, label, options):576for x in options:577if x.label == label:578return x579raise ValueError("No such option (%s)" % label)580581def get_disable_all_defines(self):582'''returns a hash of defines which turns all features off'''583options = self.get_build_options_from_ardupilot_tree()584defines = {}585for feature in options:586if self.match_glob is not None:587if not fnmatch.fnmatch(feature.define, self.match_glob):588continue589defines[feature.define] = 0590for define in self.must_have_defines_for_board(self._board):591defines[define] = 1592593return defines594595def run_disable_all(self):596defines = self.get_disable_all_defines()597self.test_compile_with_defines(defines)598self.sizes_everything_disabled = self.find_build_sizes()599600def run_disable_none(self):601self.test_compile_with_defines({})602self.sizes_nothing_disabled = self.find_build_sizes()603604def run_with_defaults(self):605options = self.get_build_options_from_ardupilot_tree()606defines = {}607for feature in options:608defines[feature.define] = feature.default609self.test_compile_with_defines(defines)610611def check_deps_consistency(self):612# self.progress("Checking deps consistency")613options = self.get_build_options_from_ardupilot_tree()614for feature in options:615self.get_disable_defines(feature, options)616617def check_duplicate_labels(self):618'''check that we do not have multiple features with same labels'''619options = self.get_build_options_from_ardupilot_tree()620seen_labels = {}621for feature in options:622if seen_labels.get(feature.label, None) is not None:623raise ValueError("Duplicate entries found for label '%s'" % feature.label)624seen_labels[feature.label] = True625626def do_emit_disable_all_defines(self):627defines = tbo.get_disable_all_defines()628for f in self.must_have_defines():629defines[f] = 1630tbo.write_defines_to_Path(defines, pathlib.Path("/dev/stdout"))631sys.exit(0)632633def run(self):634self.check_deps_consistency()635self.check_duplicate_labels()636637if self.emit_disable_all_defines:638self.do_emit_disable_all_defines()639sys.exit(0)640641if self.do_step_run_with_defaults:642self.progress("Running run-with-defaults step")643self.run_with_defaults()644if self.do_step_disable_all:645self.progress("Running disable-all step")646self.run_disable_all()647if self.do_step_disable_none:648self.progress("Running disable-none step")649self.run_disable_none()650if self.do_step_disable_in_turn:651self.progress("Running disable-in-turn step")652self.run_disable_in_turn()653if self.do_step_enable_in_turn:654self.progress("Running enable-in-turn step")655self.run_enable_in_turn()656657658if __name__ == '__main__':659660parser = optparse.OptionParser()661parser.add_option("--define-match-glob",662type='string',663default=None,664help='feature define must match this glob to be tested')665parser.add_option("--no-run-with-defaults",666action='store_true',667help='Do not run the run-with-defaults step')668parser.add_option("--no-disable-all",669action='store_true',670help='Do not run the disable-all step')671parser.add_option("--no-disable-none",672action='store_true',673help='Do not run the disable-none step')674parser.add_option("--no-disable-in-turn",675action='store_true',676help='Do not run the disable-in-turn step')677parser.add_option("--no-enable-in-turn",678action='store_true',679help='Do not run the enable-in-turn step')680parser.add_option("--build-targets",681type='choice',682choices=TestBuildOptions.all_targets(),683action='append',684help='vehicle targets to build')685parser.add_option("--extra-hwdef",686type='string',687default=None,688help="file containing extra hwdef information")689parser.add_option("--board",690type='string',691default="CubeOrange",692help='board to build for')693parser.add_option("--emit-disable-all-defines",694action='store_true',695help='emit defines used for disabling all features then exit')696parser.add_option("--resume",697action='store_true',698help='resume from previous progress file')699700opts, args = parser.parse_args()701702tbo = TestBuildOptions(703match_glob=opts.define_match_glob,704do_step_disable_all=not opts.no_disable_all,705do_step_disable_none=not opts.no_disable_none,706do_step_disable_defaults=not opts.no_run_with_defaults,707do_step_disable_in_turn=not opts.no_disable_in_turn,708do_step_enable_in_turn=not opts.no_enable_in_turn,709build_targets=opts.build_targets,710board=opts.board,711extra_hwdef=opts.extra_hwdef,712emit_disable_all_defines=opts.emit_disable_all_defines,713resume=opts.resume,714)715716tbo.run()717718719