| #!/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", |
| ) |