| #!/usr/bin/env python3 | |
| # Copyright lowRISC contributors. | |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| import logging | |
| from pathlib import ( | |
| Path, | |
| PurePath, | |
| ) | |
| from pprint import pformat | |
| from typing import List | |
| from common import ( | |
| BAZEL, | |
| DEVICE_LIBS_QUERY, | |
| LLD_HOST, | |
| BazelTestType, | |
| CoverageParams, | |
| run, | |
| ) | |
| def handle_libs(device_libs_all: List[str]) -> List[str]: | |
| """Filter device libraries that are not compatible with the host. | |
| Args: | |
| device_libs_all: A list of device libraries. | |
| Returns: | |
| `device_libs_all` with incompatible libraries filtered out. | |
| """ | |
| device_libs_incompat = run( | |
| BAZEL, | |
| "cquery", | |
| DEVICE_LIBS_QUERY, | |
| "--output=starlark", | |
| ("--starlark:expr=target.label" | |
| " if 'IncompatiblePlatformProvider' in providers(target)" | |
| " else ''"), | |
| ) | |
| logging.info(f"incompatible libraries: {pformat(device_libs_incompat)}") | |
| return sorted(list(set(device_libs_all) - set(device_libs_incompat))) | |
| def handle_objs(merged_library: Path, obj_files: List[str]): | |
| """Create a shared library from the given object files. | |
| This function also filters the object files of mocks. | |
| Args: | |
| merged_library: Path where to save the merged library. | |
| obj_files: A list of object files. | |
| """ | |
| # Note that we exclude mock_*.o since they contain duplicate definitions that we | |
| # are not interested in. | |
| logging.info(f"object files with coverage data: {pformat(obj_files)}") | |
| run( | |
| LLD_HOST, | |
| "--shared", | |
| "-o", | |
| str(merged_library), | |
| *[o for o in obj_files if not PurePath(o).name.startswith("mock_")], | |
| ) | |
| def handle_test_targets(test_targets: List[str]) -> List[str]: | |
| """Add some base library tests to the given list of tests. | |
| Args: | |
| test_targets: A list of test targets. | |
| Returns: | |
| The given list of targets along with some base library tests. | |
| """ | |
| res = test_targets + [ | |
| "//sw/device/lib/base:hardened_memory_unittest", | |
| "//sw/device/lib/base:math_unittest", | |
| "//sw/device/lib/base:math_builtins_unittest", | |
| "//sw/device/lib/base:memory_unittest", | |
| ] | |
| logging.info(f"test targets: {pformat(res)}") | |
| return res | |
| def handle_test_log_dirs(test_log_dirs: List[Path]) -> List[Path]: | |
| """Get coverage profiles. | |
| This function returns the paths of individual coverage profiles for the given list of | |
| test log directories. | |
| Args: | |
| test_log_dirs: A list of test log directories. | |
| Returns: | |
| Paths of individual coverage profiles. | |
| """ | |
| return [d / "coverage.dat" for d in test_log_dirs] | |
| PARAMS = CoverageParams( | |
| bazel_test_type=BazelTestType.CC_TEST, | |
| config="ot_coverage_off_target", | |
| libs_fn=handle_libs, | |
| objs_fn=handle_objs, | |
| test_targets_fn=handle_test_targets, | |
| test_log_dirs_fn=handle_test_log_dirs, | |
| report_title="OpenTitan Unit Test Coverage", | |
| ) |