| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- # Copyright (c) 2021 Project CHIP Authors
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- import os
- from enum import Enum, auto
- from platform import uname
- from .gn import GnBuilder
- class HostCryptoLibrary(Enum):
- """Defines what cryptographic backend applications should use."""
- OPENSSL = auto()
- MBEDTLS = auto()
- BORINGSSL = auto()
- @property
- def gn_argument(self):
- if self == HostCryptoLibrary.OPENSSL:
- return 'chip_crypto="openssl"'
- elif self == HostCryptoLibrary.MBEDTLS:
- return 'chip_crypto="mbedtls"'
- elif self == HostCryptoLibrary.BORINGSSL:
- return 'chip_crypto="boringssl"'
- class HostFuzzingType(Enum):
- """Defines fuzz target options available for host targets."""
- NONE = auto()
- LIB_FUZZER = auto()
- OSS_FUZZ = auto()
- class HostApp(Enum):
- ALL_CLUSTERS = auto()
- ALL_CLUSTERS_MINIMAL = auto()
- CHIP_TOOL = auto()
- CHIP_TOOL_DARWIN = auto()
- THERMOSTAT = auto()
- RPC_CONSOLE = auto()
- MIN_MDNS = auto()
- ADDRESS_RESOLVE = auto()
- TV_APP = auto()
- TV_CASTING_APP = auto()
- LIGHT = auto()
- LOCK = auto()
- TESTS = auto()
- SHELL = auto()
- CERT_TOOL = auto()
- OTA_PROVIDER = auto()
- OTA_REQUESTOR = auto()
- SIMULATED_APP1 = auto()
- SIMULATED_APP2 = auto()
- PYTHON_BINDINGS = auto()
- EFR32_TEST_RUNNER = auto()
- TV_CASTING = auto()
- BRIDGE = auto()
- JAVA_MATTER_CONTROLLER = auto()
- CONTACT_SENSOR = auto()
- DISHWASHER = auto()
- REFRIGERATOR = auto()
- RVC = auto()
- def ExamplePath(self):
- if self == HostApp.ALL_CLUSTERS:
- return 'all-clusters-app/linux'
- elif self == HostApp.ALL_CLUSTERS_MINIMAL:
- return 'all-clusters-minimal-app/linux'
- elif self == HostApp.CHIP_TOOL:
- return 'chip-tool'
- elif self == HostApp.CHIP_TOOL_DARWIN:
- return 'darwin-framework-tool'
- elif self == HostApp.THERMOSTAT:
- return 'thermostat/linux'
- elif self == HostApp.RPC_CONSOLE:
- return 'common/pigweed/rpc_console'
- elif self == HostApp.MIN_MDNS:
- return 'minimal-mdns'
- elif self == HostApp.TV_APP:
- return 'tv-app/linux'
- elif self == HostApp.TV_CASTING_APP:
- return 'tv-casting-app/linux'
- elif self == HostApp.LIGHT:
- return 'lighting-app/linux'
- elif self == HostApp.LOCK:
- return 'lock-app/linux'
- elif self == HostApp.SHELL:
- return 'shell/standalone'
- elif self == HostApp.OTA_PROVIDER:
- return 'ota-provider-app/linux'
- elif self in [HostApp.SIMULATED_APP1, HostApp.SIMULATED_APP2]:
- return 'placeholder/linux/'
- elif self == HostApp.OTA_REQUESTOR:
- return 'ota-requestor-app/linux'
- elif self in [HostApp.ADDRESS_RESOLVE, HostApp.TESTS, HostApp.PYTHON_BINDINGS, HostApp.CERT_TOOL]:
- return '../'
- elif self == HostApp.EFR32_TEST_RUNNER:
- return '../src/test_driver/efr32'
- elif self == HostApp.TV_CASTING:
- return 'tv-casting-app/linux'
- elif self == HostApp.BRIDGE:
- return 'bridge-app/linux'
- elif self == HostApp.JAVA_MATTER_CONTROLLER:
- return 'java-matter-controller'
- elif self == HostApp.CONTACT_SENSOR:
- return 'contact-sensor-app/linux'
- elif self == HostApp.DISHWASHER:
- return 'dishwasher-app/linux'
- elif self == HostApp.REFRIGERATOR:
- return 'refrigerator-app/linux'
- elif self == HostApp.RVC:
- return 'rvc-app/linux'
- else:
- raise Exception('Unknown app type: %r' % self)
- def OutputNames(self):
- if self == HostApp.ALL_CLUSTERS:
- yield 'chip-all-clusters-app'
- yield 'chip-all-clusters-app.map'
- elif self == HostApp.ALL_CLUSTERS_MINIMAL:
- yield 'chip-all-clusters-minimal-app'
- yield 'chip-all-clusters-minimal-app.map'
- elif self == HostApp.CHIP_TOOL:
- yield 'chip-tool'
- yield 'chip-tool.map'
- elif self == HostApp.CHIP_TOOL_DARWIN:
- yield 'darwin-framework-tool'
- yield 'darwin-framework-tool.map'
- elif self == HostApp.THERMOSTAT:
- yield 'thermostat-app'
- yield 'thermostat-app.map'
- elif self == HostApp.RPC_CONSOLE:
- yield 'chip_rpc_console_wheels'
- elif self == HostApp.MIN_MDNS:
- yield 'mdns-advertiser'
- yield 'mdns-advertiser.map'
- yield 'minimal-mdns-client'
- yield 'minimal-mdns-client.map'
- yield 'minimal-mdns-server'
- yield 'minimal-mdns-server.map'
- elif self == HostApp.ADDRESS_RESOLVE:
- yield 'address-resolve-tool'
- yield 'address-resolve-tool.map'
- elif self == HostApp.TV_APP:
- yield 'chip-tv-app'
- yield 'chip-tv-app.map'
- elif self == HostApp.TV_CASTING_APP:
- yield 'chip-tv-casting-app'
- yield 'chip-tv-casting-app.map'
- elif self == HostApp.LIGHT:
- yield 'chip-lighting-app'
- yield 'chip-lighting-app.map'
- elif self == HostApp.LOCK:
- yield 'chip-lock-app'
- yield 'chip-lock-app.map'
- elif self == HostApp.TESTS:
- pass
- elif self == HostApp.SHELL:
- yield 'chip-shell'
- yield 'chip-shell.map'
- elif self == HostApp.CERT_TOOL:
- yield 'chip-cert'
- yield 'chip-cert.map'
- elif self == HostApp.SIMULATED_APP1:
- yield 'chip-app1'
- yield 'chip-app1.map'
- elif self == HostApp.SIMULATED_APP2:
- yield 'chip-app2'
- yield 'chip-app2.map'
- elif self == HostApp.OTA_PROVIDER:
- yield 'chip-ota-provider-app'
- yield 'chip-ota-provider-app.map'
- elif self == HostApp.OTA_REQUESTOR:
- yield 'chip-ota-requestor-app'
- yield 'chip-ota-requestor-app.map'
- elif self == HostApp.PYTHON_BINDINGS:
- yield 'controller/python' # Directory containing WHL files
- elif self == HostApp.EFR32_TEST_RUNNER:
- yield 'chip_nl_test_runner_wheels'
- elif self == HostApp.TV_CASTING:
- yield 'chip-tv-casting-app'
- yield 'chip-tv-casting-app.map'
- elif self == HostApp.BRIDGE:
- yield 'chip-bridge-app'
- yield 'chip-bridge-app.map'
- elif self == HostApp.JAVA_MATTER_CONTROLLER:
- yield 'java-matter-controller'
- yield 'java-matter-controller.map'
- elif self == HostApp.CONTACT_SENSOR:
- yield 'contact-sensor-app'
- yield 'contact-sensor-app.map'
- elif self == HostApp.DISHWASHER:
- yield 'dishwasher-app'
- yield 'dishwasher-app.map'
- elif self == HostApp.REFRIGERATOR:
- yield 'refrigerator-app'
- yield 'refrigerator-app.map'
- elif self == HostApp.RVC:
- yield 'rvc-app'
- yield 'rvc-app.map'
- else:
- raise Exception('Unknown app type: %r' % self)
- class HostBoard(Enum):
- NATIVE = auto()
- # cross-compile support
- ARM64 = auto()
- # for test support
- FAKE = auto()
- def BoardName(self):
- if self == HostBoard.NATIVE:
- uname_result = uname()
- arch = uname_result.machine
- # standardize some common platforms
- if arch == 'x86_64':
- arch = 'x64'
- elif arch == 'i386' or arch == 'i686':
- arch = 'x86'
- elif arch in ('aarch64', 'aarch64_be', 'armv8b', 'armv8l'):
- arch = 'arm64'
- return arch
- elif self == HostBoard.ARM64:
- return 'arm64'
- elif self == HostBoard.FAKE:
- return 'fake'
- else:
- raise Exception('Unknown host board type: %r' % self)
- def PlatformName(self):
- if self == HostBoard.NATIVE:
- return uname().system.lower()
- elif self == HostBoard.FAKE:
- return 'fake'
- else:
- # Cross compilation assumes linux currently
- return 'linux'
- class HostBuilder(GnBuilder):
- def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE,
- enable_ipv4=True, enable_ble=True, enable_wifi=True,
- enable_thread=True, use_tsan=False, use_asan=False, use_ubsan=False,
- separate_event_loop=True, fuzzing_type: HostFuzzingType = HostFuzzingType.NONE, use_clang=False,
- interactive_mode=True, extra_tests=False, use_platform_mdns=False, enable_rpcs=False,
- use_coverage=False, use_dmalloc=False, minmdns_address_policy=None,
- minmdns_high_verbosity=False, imgui_ui=False, crypto_library: HostCryptoLibrary = None):
- super(HostBuilder, self).__init__(
- root=os.path.join(root, 'examples', app.ExamplePath()),
- runner=runner)
- self.app = app
- self.board = board
- self.extra_gn_options = []
- self.build_env = {}
- if enable_rpcs:
- self.extra_gn_options.append('import("//with_pw_rpc.gni")')
- if not enable_ipv4:
- self.extra_gn_options.append('chip_inet_config_enable_ipv4=false')
- if not enable_ble:
- self.extra_gn_options.append('chip_config_network_layer_ble=false')
- if not enable_wifi:
- self.extra_gn_options.append('chip_enable_wifi=false')
- if not enable_thread:
- self.extra_gn_options.append('chip_enable_openthread=false')
- if use_tsan:
- self.extra_gn_options.append('is_tsan=true')
- if use_asan:
- self.extra_gn_options.append('is_asan=true')
- if use_ubsan:
- self.extra_gn_options.append('is_ubsan=true')
- if use_dmalloc:
- self.extra_gn_options.append('chip_config_memory_debug_checks=true')
- self.extra_gn_options.append('chip_config_memory_debug_dmalloc=true')
- # this is from `dmalloc -b -l DMALLOC_LOG -i 1 high`
- self.build_env['DMALLOC_OPTIONS'] = 'debug=0x4f4ed03,inter=1,log=DMALLOC_LOG'
- # glib interop with dmalloc
- self.build_env['G_SLICE'] = 'always-malloc'
- if not separate_event_loop:
- self.extra_gn_options.append('config_use_separate_eventloop=false')
- if not interactive_mode:
- self.extra_gn_options.append('config_use_interactive_mode=false')
- if fuzzing_type == HostFuzzingType.LIB_FUZZER:
- self.extra_gn_options.append('is_libfuzzer=true')
- elif fuzzing_type == HostFuzzingType.OSS_FUZZ:
- self.extra_gn_options.append('oss_fuzz=true')
- if imgui_ui:
- self.extra_gn_options.append('chip_examples_enable_imgui_ui=true')
- self.use_coverage = use_coverage
- if use_coverage:
- self.extra_gn_options.append('use_coverage=true')
- if use_clang:
- self.extra_gn_options.append('is_clang=true')
- if self.board == HostBoard.FAKE:
- # Fake uses "//build/toolchain/fake:fake_x64_gcc"
- # so setting clang is not correct
- raise Exception('Fake host board is always gcc (not clang)')
- if minmdns_address_policy:
- if use_platform_mdns:
- raise Exception('Address policy applies to minmdns only')
- self.extra_gn_options.append('chip_minmdns_default_policy="%s"' % minmdns_address_policy)
- if use_platform_mdns:
- self.extra_gn_options.append('chip_mdns="platform"')
- if extra_tests:
- # Flag for testing purpose
- self.extra_gn_options.append(
- 'chip_im_force_fabric_quota_check=true')
- if minmdns_high_verbosity:
- self.extra_gn_options.append('chip_minmdns_high_verbosity=true')
- if app == HostApp.TESTS:
- self.extra_gn_options.append('chip_build_tests=true')
- self.build_command = 'check'
- if app == HostApp.EFR32_TEST_RUNNER:
- self.build_command = 'runner'
- # board will NOT be used, but is required to be able to properly
- # include things added by the test_runner efr32 build
- self.extra_gn_options.append('silabs_board="BRD4161A"')
- # Crypto library has per-platform defaults (like openssl for linux/mac
- # and mbedtls for android/freertos/zephyr/mbed/...)
- if crypto_library:
- self.extra_gn_options.append(crypto_library.gn_argument)
- if self.board == HostBoard.ARM64:
- if not use_clang:
- raise Exception("Cross compile only supported using clang")
- if app == HostApp.CERT_TOOL:
- # Certification only built for openssl
- if self.board == HostBoard.ARM64 and crypto_library == HostCryptoLibrary.MBEDTLS:
- raise Exception("MbedTLS not supported for cross compiling cert tool")
- self.build_command = 'src/tools/chip-cert'
- elif app == HostApp.ADDRESS_RESOLVE:
- self.build_command = 'src/lib/address_resolve:address-resolve-tool'
- elif app == HostApp.PYTHON_BINDINGS:
- self.extra_gn_options.append('enable_rtti=false')
- self.extra_gn_options.append('chip_project_config_include_dirs=["//config/python"]')
- self.build_command = 'chip-repl'
- if self.app == HostApp.SIMULATED_APP1:
- self.extra_gn_options.append('chip_tests_zap_config="app1"')
- if self.app == HostApp.SIMULATED_APP2:
- self.extra_gn_options.append('chip_tests_zap_config="app2"')
- if self.app == HostApp.TESTS and fuzzing_type != HostFuzzingType.NONE:
- self.build_command = 'fuzz_tests'
- def GnBuildArgs(self):
- if self.board == HostBoard.NATIVE:
- return self.extra_gn_options
- elif self.board == HostBoard.ARM64:
- self.extra_gn_options.extend(
- [
- 'target_cpu="arm64"',
- 'sysroot="%s"' % self.SysRootPath('SYSROOT_AARCH64')
- ]
- )
- return self.extra_gn_options
- elif self.board == HostBoard.FAKE:
- self.extra_gn_options.extend(
- [
- 'custom_toolchain="//build/toolchain/fake:fake_x64_gcc"',
- 'chip_link_tests=true',
- 'chip_device_platform="fake"',
- 'chip_fake_platform=true',
- ]
- )
- return self.extra_gn_options
- else:
- raise Exception('Unknown host board type: %r' % self)
- def createJavaExecutable(self, java_program):
- self._Execute(
- [
- "chmod",
- "+x",
- "%s/bin/%s" % (self.output_dir, java_program),
- ],
- title="Make Java program executable",
- )
- def GnBuildEnv(self):
- if self.board == HostBoard.ARM64:
- self.build_env['PKG_CONFIG_PATH'] = os.path.join(
- self.SysRootPath('SYSROOT_AARCH64'), 'lib/aarch64-linux-gnu/pkgconfig')
- return self.build_env
- def SysRootPath(self, name):
- if name not in os.environ:
- raise Exception('Missing environment variable "%s"' % name)
- return os.environ[name]
- def generate(self):
- super(HostBuilder, self).generate()
- if 'JAVA_PATH' in os.environ:
- self._Execute(
- ["third_party/java_deps/set_up_java_deps.sh"],
- title="Setting up Java deps",
- )
- exampleName = self.app.ExamplePath()
- if exampleName == "java-matter-controller":
- self._Execute(
- [
- "cp",
- os.path.join(self.root, "Manifest.txt"),
- self.output_dir,
- ],
- title="Copying Manifest.txt to " + self.output_dir,
- )
- if self.app == HostApp.TESTS and self.use_coverage:
- self.coverage_dir = os.path.join(self.output_dir, 'coverage')
- self._Execute(['mkdir', '-p', self.coverage_dir], title="Create coverage output location")
- def PreBuildCommand(self):
- if self.app == HostApp.TESTS and self.use_coverage:
- self._Execute(['ninja', '-C', self.output_dir, 'default'], title="Build-only")
- self._Execute(['find', os.path.join(self.output_dir, 'obj/src/'), '-depth',
- '-name', 'tests', '-exec', 'rm -rf {} \\;'], title="Cleanup unit tests")
- self._Execute(['lcov', '--initial', '--capture', '--directory', os.path.join(self.output_dir, 'obj'),
- '--exclude', os.path.join(self.chip_dir, 'zzz_generated/*'),
- '--exclude', os.path.join(self.chip_dir, 'third_party/*'),
- '--exclude', '/usr/include/*',
- '--output-file', os.path.join(self.coverage_dir, 'lcov_base.info')], title="Initial coverage baseline")
- def PostBuildCommand(self):
- if self.app == HostApp.TESTS and self.use_coverage:
- self._Execute(['lcov', '--capture', '--directory', os.path.join(self.output_dir, 'obj'),
- '--exclude', os.path.join(self.chip_dir, 'zzz_generated/*'),
- '--exclude', os.path.join(self.chip_dir, 'third_party/*'),
- '--exclude', '/usr/include/*',
- '--output-file', os.path.join(self.coverage_dir, 'lcov_test.info')], title="Update coverage")
- self._Execute(['lcov', '--add-tracefile', os.path.join(self.coverage_dir, 'lcov_base.info'),
- '--add-tracefile', os.path.join(self.coverage_dir, 'lcov_test.info'),
- '--output-file', os.path.join(self.coverage_dir, 'lcov_final.info')
- ], title="Final coverage info")
- self._Execute(['genhtml', os.path.join(self.coverage_dir, 'lcov_final.info'), '--output-directory',
- os.path.join(self.coverage_dir, 'html')], title="HTML coverage")
- if self.app == HostApp.JAVA_MATTER_CONTROLLER:
- self.createJavaExecutable("java-matter-controller")
- def build_outputs(self):
- outputs = {}
- for name in self.app.OutputNames():
- path = os.path.join(self.output_dir, name)
- if os.path.isdir(path):
- for root, dirs, files in os.walk(path):
- for file in files:
- outputs.update({
- file: os.path.join(root, file)
- })
- else:
- outputs.update({
- name: os.path.join(self.output_dir, name)
- })
- return outputs
|