Skip to content

Commit

Permalink
Create documentation for Starlark code with stardoc
Browse files Browse the repository at this point in the history
We want a single source of truth and less work by maintaining
the docstring as well as the README.
  • Loading branch information
martis42 committed Aug 4, 2024
1 parent d323e15 commit 59616b2
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 18 deletions.
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
define: &generated_doc_files "^docs/(cc_info_mapping|dwyu_aspect).md"

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
Expand All @@ -11,15 +13,19 @@ repos:
- id: check-json
# Code style
- id: end-of-file-fixer
exclude: *generated_doc_files
- id: trailing-whitespace
# Python code quality
- id: debug-statements

- repo: https://github.com/executablebooks/mdformat
rev: 0.7.17
hooks:
- id: mdformat
exclude: *generated_doc_files
additional_dependencies:
- mdformat-gfm

- repo: https://github.com/keith/pre-commit-buildifier
rev: 7.1.2
hooks:
Expand All @@ -30,6 +36,7 @@ repos:
"--diff_command='diff'",
"--warnings=-module-docstring,-function-docstring,-function-docstring-header,-print"
]

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.5.5
Expand Down
2 changes: 2 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use_repo(non_module_dependencies, "dwyu_pcpp")

# Keep in sync with third_party/dependencies.bzl
bazel_dep(name = "bazel_skylib", version = "1.7.1", dev_dependency = True)
bazel_dep(name = "aspect_bazel_lib", version = "2.7.9", dev_dependency = True)
bazel_dep(name = "stardoc", version = "0.7.0", dev_dependency = True)

python = use_extension(
"@rules_python//python/extensions:python.bzl",
Expand Down
13 changes: 13 additions & 0 deletions docs/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@aspect_bazel_lib//lib:docs.bzl", "stardoc_with_diff_test", "update_docs")

stardoc_with_diff_test(
name = "cc_info_mapping",
bzl_library_target = "//src/cc_info_mapping:cc_info_mapping",
)

stardoc_with_diff_test(
name = "dwyu_aspect",
bzl_library_target = "//src/aspect:factory",
)

update_docs()
51 changes: 51 additions & 0 deletions docs/cc_info_mapping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!-- Generated with Stardoc: http://skydoc.bazel.build -->

Sometimes users don't want to follow the DWYU rules for all targets or have to work with external dependencies not following the DWYU principles.
While one can completely exclude targets from the DWYU analysis (e.g. via tags), one might not want to disable DWYU completely, but define custom rules for specific dependencies.
One can do so by defining exceptions where includes can be provided by selected transitive dependencies instead of direct dependencies.
In other words, one can virtually change which header files are treated as being available from direct dependencies.

One example use case for this are unit tests based on gtest.
Following strictly the DWYU principles each test using a gtest header should depend both on the gtest library and the gtest main:
```starlark
cc_test(
name = "my_test",
srcs = ["my_test.cc"],
deps = [
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
```
This can be considered superfluous noise without a significant benefit.
The mapping feature described here allows defining that `@com_google_googletest//:gtest_main` offers the header files from `@com_google_googletest//:gtest`.
Then a test can specify only the dependency to `@com_google_googletest//:gtest_main` without DWYU raising an error while analysing the test.

<a id="dwyu_make_cc_info_mapping"></a>

## dwyu_make_cc_info_mapping

<pre>
load("@depend_on_what_you_use//src/cc_info_mapping:cc_info_mapping.bzl", "dwyu_make_cc_info_mapping")

dwyu_make_cc_info_mapping(<a href="#dwyu_make_cc_info_mapping-name">name</a>, <a href="#dwyu_make_cc_info_mapping-mapping">mapping</a>)
</pre>

Map include paths available from one or several targets to another target.

Create a mapping allowing treating targets as if they themselves would offer header files, which in fact are coming from their dependencies.
This enables the DWYU analysis to skip over some usage of headers provided by transitive dependencies without raising an error.


This is demonstrated in the [target_mapping example](/examples/target_mapping).


**PARAMETERS**


| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="dwyu_make_cc_info_mapping-name"></a>name | Unique name for this target. Will be the prefix for all private intermediate targets. | none |
| <a id="dwyu_make_cc_info_mapping-mapping"></a>mapping | Dictionary containing various targets and how they should be mapped. Possible mappings are:<br> - An explicit list of targets which are mapped to the main target. Be careful only to choose targets which are dependencies of the main target! <br> - The `MAP_DIRECT_DEPS` token which tells the rule to map all direct dependencies to the main target. <br> - The `MAP_TRANSITIVE_DEPS` token which tells the rule to map recursively all transitive dependencies to the main target. | none |


35 changes: 35 additions & 0 deletions docs/dwyu_aspect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- Generated with Stardoc: http://skydoc.bazel.build -->



<a id="dwyu_aspect_factory"></a>

## dwyu_aspect_factory

<pre>
load("@depend_on_what_you_use//src/aspect:factory.bzl", "dwyu_aspect_factory")

dwyu_aspect_factory(<a href="#dwyu_aspect_factory-ignored_includes">ignored_includes</a>, <a href="#dwyu_aspect_factory-recursive">recursive</a>, <a href="#dwyu_aspect_factory-skip_external_targets">skip_external_targets</a>, <a href="#dwyu_aspect_factory-skipped_tags">skipped_tags</a>,
<a href="#dwyu_aspect_factory-target_mapping">target_mapping</a>, <a href="#dwyu_aspect_factory-use_implementation_deps">use_implementation_deps</a>, <a href="#dwyu_aspect_factory-verbose">verbose</a>)
</pre>

Create a "Depend on What You Use" (DWYU) aspect.

**PARAMETERS**


| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="dwyu_aspect_factory-ignored_includes"></a>ignored_includes | Configuration file specifying which include statements should be skipped during analysis. When nothing is specified, the standard library headers are ignored by default. | `None` |
| <a id="dwyu_aspect_factory-recursive"></a>recursive | If true, execute the aspect on all transitive dependencies. If false, analyze only the target the aspect is being executed on. | `False` |
| <a id="dwyu_aspect_factory-skip_external_targets"></a>skip_external_targets | If a target is from an external workspace DWYU skips analyzing it. | `False` |
| <a id="dwyu_aspect_factory-skipped_tags"></a>skipped_tags | Do not execute the aspect on targets with at least one of those tags. By default skips the analysis for targets tagged with 'no-dwyu'. | `None` |
| <a id="dwyu_aspect_factory-target_mapping"></a>target_mapping | A target providing a map of target labels to alternative CcInfo provider objects for those targets. Typically created with the dwyu_make_cc_info_mapping rule. | `None` |
| <a id="dwyu_aspect_factory-use_implementation_deps"></a>use_implementation_deps | If true, ensure cc_library dependencies which are used only in private files are listed in implementation_deps. Only available if flag '--experimental_cc_implementation_deps' is provided. | `False` |
| <a id="dwyu_aspect_factory-verbose"></a>verbose | If true, print debugging information about what DWYU does internally. | `False` |

**RETURNS**

Configured DWYU aspect


19 changes: 19 additions & 0 deletions src/aspect/BUILD
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@rules_python//python:defs.bzl", "py_binary")

py_binary(
name = "process_target",
srcs = ["process_target.py"],
visibility = ["//visibility:public"],
)

bzl_library(
name = "factory",
srcs = [
"dwyu.bzl",
"factory.bzl",
"@bazel_tools//tools/build_defs/cc:action_names.bzl",
],
visibility = ["//visibility:public"],
deps = [
"//src/cc_info_mapping",
],
)

exports_files(
["factory.bzl"],
visibility = ["//docs:__pkg__"],
)
2 changes: 1 addition & 1 deletion src/aspect/dwyu.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "CPP_COMPILE_ACTION_NAME")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("@depend_on_what_you_use//src/cc_info_mapping:cc_info_mapping.bzl", "DwyuCcInfoRemappingsInfo")
load("@depend_on_what_you_use//src/cc_info_mapping:providers.bzl", "DwyuCcInfoRemappingsInfo")
load("@rules_cc//cc:defs.bzl", "CcInfo", "cc_common")

def _is_external(ctx):
Expand Down
3 changes: 2 additions & 1 deletion src/aspect/factory.bzl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@depend_on_what_you_use//src/cc_info_mapping:cc_info_mapping.bzl", "DwyuCcInfoRemappingsInfo")
load("@depend_on_what_you_use//src/cc_info_mapping:providers.bzl", "DwyuCcInfoRemappingsInfo")
load(":dwyu.bzl", "dwyu_aspect_impl")

def dwyu_aspect_factory(
Expand Down Expand Up @@ -26,6 +26,7 @@ def dwyu_aspect_factory(
listed in implementation_deps. Only available if flag
'--experimental_cc_implementation_deps' is provided.
verbose: If true, print debugging information about what DWYU does internally.
Returns:
Configured DWYU aspect
"""
Expand Down
21 changes: 21 additions & 0 deletions src/cc_info_mapping/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

bzl_library(
name = "cc_info_mapping",
srcs = [
"cc_info_mapping.bzl",
"providers.bzl",
"@bazel_tools//tools/cpp:toolchain_utils.bzl",
"@rules_cc//cc:bzl_srcs",
],
visibility = ["//visibility:public"],
deps = [
"//src/cc_info_mapping/private:bzl_srcs",
"//src/utils",
],
)

exports_files(
["cc_info_mapping.bzl"],
visibility = ["//docs:__pkg__"],
)
51 changes: 35 additions & 16 deletions src/cc_info_mapping/cc_info_mapping.bzl
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
"""
Sometimes users don't want to follow the DWYU rules for all targets or have to work with external dependencies not following the DWYU principles.
While one can completely exclude targets from the DWYU analysis (e.g. via tags), one might not want to disable DWYU completely, but define custom rules for specific dependencies.
One can do so by defining exceptions where includes can be provided by selected transitive dependencies instead of direct dependencies.
In other words, one can virtually change which header files are treated as being available from direct dependencies.
One example use case for this are unit tests based on gtest.
Following strictly the DWYU principles each test using a gtest header should depend both on the gtest library and the gtest main:
```starlark
cc_test(
name = "my_test",
srcs = ["my_test.cc"],
deps = [
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
```
This can be considered superfluous noise without a significant benefit.
The mapping feature described here allows defining that `@com_google_googletest//:gtest_main` offers the header files from `@com_google_googletest//:gtest`.
Then a test can specify only the dependency to `@com_google_googletest//:gtest_main` without DWYU raising an error while analysing the test.
"""

load("@depend_on_what_you_use//src/cc_info_mapping/private:direct_deps.bzl", "mapping_to_direct_deps")
load("@depend_on_what_you_use//src/cc_info_mapping/private:explicit.bzl", "explicit_mapping")
load("@depend_on_what_you_use//src/cc_info_mapping/private:providers.bzl", "DwyuCcInfoRemapInfo")
load("@depend_on_what_you_use//src/cc_info_mapping/private:transitive_deps.bzl", "mapping_to_transitive_deps")
load("@depend_on_what_you_use//src/utils:utils.bzl", "label_to_name")
load(":providers.bzl", "DwyuCcInfoRemappingsInfo")

MAP_DIRECT_DEPS = "__DWYU_MAP_DIRECT_DEPS__"
MAP_TRANSITIVE_DEPS = "__DWYU_MAP_TRANSITIVE_DEPS__"

DwyuCcInfoRemappingsInfo = provider(
"Dictionary of targets labels wnd which CcInfo provider DWYU should use for analysing them",
fields = {
"mapping": "Dictionary with structure {'target label': CcInfo provider which should be used by DWYU}",
},
)

def _make_remapping_info_impl(ctx):
return DwyuCcInfoRemappingsInfo(mapping = {
remap[DwyuCcInfoRemapInfo].target: remap[DwyuCcInfoRemapInfo].cc_info
Expand All @@ -30,18 +47,20 @@ _make_remapping_info = rule(

def dwyu_make_cc_info_mapping(name, mapping):
"""
Create a mapping which allows treating targets as if they themselves would offer header files, which in fact are
coming from their dependencies. This enables the DWYU analysis to skip over some usage of headers provided by
transitive dependencies without raising an error.
Map include paths available from one or several targets to another target.
Create a mapping allowing treating targets as if they themselves would offer header files, which in fact are coming from their dependencies.
This enables the DWYU analysis to skip over some usage of headers provided by transitive dependencies without raising an error.
Using this rule and the various mapping techniques is demonstrated in the [target_mapping example](/examples/target_mapping).
Args:
name: Unique name for this target. Will be the prefix for all private intermediate targets.
mapping: Dictionary containing various targets and how they should be mapped. Possible mappings are:
- An explicit list of targets which are mapped to the main target. Be careful only to choose targets
which are dependencies of the main target!
- The MAP_DIRECT_DEPS token which tells the rule to map all direct dependencies to the main target.
- The MAP_TRANSITIVE_DEPS token which tells the rule to map recursively all transitive dependencies to
the main target.
mapping: Dictionary containing various targets and how they should be mapped. Possible mappings are:<br>
- An explicit list of targets which are mapped to the main target.
Be careful only to choose targets which are dependencies of the main target! <br>
- The `MAP_DIRECT_DEPS` token which tells the rule to map all direct dependencies to the main target. <br>
- The `MAP_TRANSITIVE_DEPS` token which tells the rule to map recursively all transitive dependencies to the main target.
"""
mappings = []
for target, map_to in mapping.items():
Expand Down
12 changes: 12 additions & 0 deletions src/cc_info_mapping/private/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

bzl_library(
name = "bzl_srcs",
srcs = [
"direct_deps.bzl",
"explicit.bzl",
"providers.bzl",
"transitive_deps.bzl",
],
visibility = ["//src/cc_info_mapping:__pkg__"],
)
6 changes: 6 additions & 0 deletions src/cc_info_mapping/providers.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DwyuCcInfoRemappingsInfo = provider(
"Mapping of targets to CcInfo providers which DWYU should use for analyis instead of the targets original CcInfo.",
fields = {
"mapping": "Dictionary with structure {'target label': CcInfo}",
},
)
9 changes: 9 additions & 0 deletions src/utils/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

bzl_library(
name = "utils",
srcs = [
"utils.bzl",
],
visibility = ["//src:__subpackages__"],
)

0 comments on commit 59616b2

Please sign in to comment.