Giter Site home page Giter Site logo

r2r-dev / depend_on_what_you_use Goto Github PK

View Code? Open in Web Editor NEW

This project forked from martis42/depend_on_what_you_use

0.0 1.0 0.0 195 KB

Bazel tool for making sure your C++ dependencies match your include statements

License: MIT License

Shell 0.22% C++ 3.30% Python 75.52% C 2.90% Starlark 18.06%

depend_on_what_you_use's Introduction

Depend on what you use (DWYU)

DWYU is a Bazel aspect for C++ projects making sure the headers your Bazel targets are using are aligned with their dependency lists.

DWYUs enforces the design principle:
A cc_* target X shall depend directly on the targets providing the header files which are included in the source code of X.

The main features are:

  • Finding include statements which are not available through a direct dependency, aka preventing to rely on transitive dependencies for includes.
  • Finding unused dependencies.
  • Given one uses the latest experimental Bazel features, making sure one distinguishes properly between public and private dependencies for cc_library. For more details see features chapter Implementation_deps.

More information about the idea behind DWYU and the implementation of the project is available in the docs.

Getting started

Get a release

Choose a release from the release page and follow the instructions.

Get a specific commit

Put the following into your WORKSPACE file to use a specific DWYU commit:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

dwyu_version = "<git_commit_hash>"
http_archive(
    name = "depend_on_what_you_use",
    sha256 = "<archive_checksum>",  # optional
    strip_prefix = "depend_on_what_you_use-{}".format(dwyu_version),
    url = "https://github.com/martis42/depend_on_what_you_use/archive/{}.tar.gz".format(dwyu_version),
)

load("@depend_on_what_you_use//:dependencies.bzl", dwyu_dependencies = "public_dependencies")
dwyu_dependencies()

Use DWYU

Configure the aspect

Configure an aspect with the desired behavior. The features which can be configured through the the aspect factory attributes are documented at Features. Put the following inside a aspect.bzl file (file name is exemplary):

load("@depend_on_what_you_use//:defs.bzl", "dwyu_aspect_factory")

# Provide no arguments for the default behavior
# Or set a custom value for the various attributes
your_dwyu_aspect = dwyu_aspect_factory()

Use the aspect

Invoke the aspect through the command line on a target:
bazel build <target_pattern> --aspects=//:aspect.bzl%your_dwyu_aspect --output_groups=cc_dwyu_output

If no problem is found, the command will exit with INFO: Build completed successfully.
If a problem is detected, the build command will fail with an error and a description of the problem will be printed in the terminal. For example:

================================================================================
DWYU analyzing: '<analyzed_target>'

Result: Failure

Unused dependencies in 'deps' (none of their headers are referenced):
  Dependency='//some/target/with_an_unused:dependency'
===============================================================================

Create a rule invoking the aspect.

You can invoke the aspect from within a rule. This can be useful to make the execution part of a bazel build (e.g. bazel build //...) without having to manually execute the longish aspect build command.

The Bazel documentation for invoking an aspect from within a rule can be found here. A concrete example for doing so for the DWYU aspect can be found in a rule in the recursion test cases.

Features

Custom header ignore list

By default DWYU ignores all header from the standard library when comparing include statements to the dependencies. This list of headers can be seen in std_header.py.

You can exclude a custom set of header files by providing a config file in json format to the aspect:

your_aspect = dwyu_aspect_factory(config = "//<your_config_file>.json")

The config file can contain these fields which should be lists of strings. All fields are optional:

Field Description
ignore_include_paths List of include paths which are ignored by the analysis. Setting this disables ignoring the standard library include paths.
extra_ignore_include_paths List of include paths which are ignored by the analysis. If ignore_include_paths is specified as well, both list are combined. If ignore_include_paths is not set, the default list of standard library headers is extended.
ignore_include_patterns List of patterns for include paths which are ignored by the analysis. Patterns have to be compatible to Python regex syntax. The match function is used to process the patterns,

Examples and the correct format can be seen at the custom config test cases.

Recursion

By default DWYU analyzes only the target it is being applied to.

You can also activate recursive analysis. Meaning the aspect analyzes recursively all dependencies of the target it is being applied to:

your_aspect = dwyu_aspect_factory(recursive = True)

This can be used to create a rule invoking DWYU on a target and all its dependencies as part of a normal build command. Also it can be a convenience to analyze specific fraction of your stack without utilizing bazel (c)query.

Examples for this can be seen at the recursion test cases.

Implementation_deps

Starting with version 5.0.0 Bazel offers experimental feature implementation_deps to distinguish between public (aka interface) and private (aka implementation) dependencies for cc_library. Headers from the private dependencies are not made available to users of the library to trim down dependency trees.

DWYU analyzes the usage of headers from the dependencies and can raise an error if a dependency is used only in private files, but not put into the private dependency attribute. Meaning, it can find dependencies which should be move from deps to implementation_deps.

Activate this behavior via:

your_aspect = dwyu_aspect_factory(use_implementation_deps = True)

Examples for this can be seen at the implementation_deps test cases.

Known limitations

  • If includes are added through a macro, this is invisible to DWYU.
  • Defines are ignored. No matter if they are defined directly inside the header under inspection, headers from the dependencies or injected through the defines = [...] attribute of the cc_ rules.
  • Include statements utilizing .. are not recognized if they are used on virtual or system include paths.

Applying automatic fixes

DWYU offers a tool to automatically fix detected problems.

The workflow is the following:

  1. Execute DWYU on your workspace. DWYU will create report files containing information about discovered problems for each analyzed target in the Bazel output directory.
  2. Execute bazel run @depend_on_what_you_use//:apply_fixes. The tool discovers the report files generated in the previous step and gathers the problems for which a fix is available. Then buildozer is utilized to adapt the BUILDS files in your workspace.

If the apply_fixes tool is not able to discover the report files, this can be caused by the bazel-bin convenience symlink at the workspace root not existing or not pointing to the output directory which was used by to generate the report files. The apply_fixes tool offers options to control how the output directory is discovered.
Execute bazel run @depend_on_what_you_use//:apply_fixes -- --help to discover the whole CLI interface of the tool.

There are limitations on what can be automatically fixed due to constrraints of buildozer. For more details see the doc string of the apply fixes main function.

Preconditions

The code has to be compilable
DWYU is not performing a compilation itself. It works by statically analyzing the source code and build tree. However, non compiling code can contain errors which infringe the assumptions DWYU is based on. For example, including header files which do not exist at the expected path.

Include paths have to be unambiguous
In other words, there shall not be multiple header files in the dependency tree of a target matching an include statement. Even if analysing the code works initially, it might break at any time if the ordering of paths in the analysis changes.

Supported Platforms

Platform Constraints
Operating system No constraints. However, Ubuntu 20.04 is currently the only OS used for development and testing.
Python Minimum version is 3.6. Tests are currently running based on Python 3.8.
Bazel Minimum version is 4.0.0. Multiple versions are tested.
Buildozer No known limitations. Tests have been performed with 5.0.1.

Alternatives to DWYU

If you are mostly interested in making sure no headers from transitive dependencies are used by your C++ targets, you might want to look into the layering_check feature. It causes the compilation to fail on using headers from transitive dependencies.
At the time of writing this, I could not find detailed documentation about this feature. It was introduced in this PR and is mentioned in the unix_cc_toolchain_config.bzl.
As far as I can tell this feature is only available with the clang compiler and while using modules.

Versioning

This project uses semantic versioning. Please be aware that the project is still in an early phase and until version 1.0.0 has been reached all releases can contain breaking changes.

Contributing

See Contributing.

License

Copyright © 2022-present, Martin Medler.
This project licensed under the MIT license.

depend_on_what_you_use's People

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.