This is a basic example of how to use the doxygen rule with make variable substitutions. The advantage of using make variable substitutions instead of directly working over the values passed to the doxygen rule is that you can access informations from other rules and toolchains and use them in the documentation. Move to the parent directory and run the following command:
# Version: _empty_ , Description: "no stamp" bazel build //substitutions:doxygen # or # Version: _empty_ , Description: "stamp fallback" bazel build //substitutions:doxygen --stamp # or # Version: 1.0.0 , Description: "MyBuildDescription" bazel build //substitutions:doxygen --stamp --//substitutions:build_description="MyBuildDescription" --embed_label=1.0.0
[!NOTE]
If--stamp
is not passed, the version will be undetermined, usually an empty string or the last stamped value.
We are reading variables from three sources:
BUILD.bazel
file (e.g. NAME
).--substitutions:build_description=MyBuildDescription
).stamp
information stored in the bazel-out/stable-status.txt
file.For the first two kind of substitution we need to define a simple rule that will apply the make variable substitutions. Let's say we want to pass a description to the doxygen rule from a command line flag, but only if the build is stamped. So, first we use skylib
to define a string flag.
# BUILD.bazel load("@bazel_skylib//rules:common_settings.bzl", "string_flag") string_flag( name = "build_description", build_setting_default = "stamp fallback", )
[!TIP]
You can define an alias for the flag to make it easier to use in the command line. Create a.bazelrc
file in the root of your workspace with the following content:build --flag_alias=build_description=//substitutions:build_descriptionNow you can use
--build_description=MyBuildDescription
instead of--//substitutions:build_description=MyBuildDescription
.
Then we create a substitution rule.
# make_var_substitution.bzl load("@aspect_bazel_lib//lib:stamping.bzl", "STAMP_ATTRS", "maybe_stamp") load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") def _make_var_substitution_impl(ctx): vars = dict(ctx.attr.variables) stamp = maybe_stamp(ctx) if stamp: # If the build is stamped, use the value from --//substitutions:build_description as the build version. vars["BUILD_DESCRIPTION"] = ctx.attr._build_description[BuildSettingInfo].value else: # Otherwise use the hardcoded value. vars["BUILD_DESCRIPTION"] = "no stamp" # Add the path of the label files to the variables. for key, value in ctx.attr.locations.items(): vars[key] = '"%s"' % '" "'.join([file.path for file in (value[DefaultInfo].files.to_list())]) return [platform_common.TemplateVariableInfo(vars)] make_var_substitution = rule( implementation = _make_var_substitution_impl, attrs = dict({ "locations": attr.string_keyed_label_dict(), "variables": attr.string_dict(), "_build_description": attr.label(default = "//substitutions:build_description"), }, **STAMP_ATTRS), )
[!IMPORTANT]
Thestring_keyed_label_dict
attribute is not available in bazel 7.0.0. As an alternative, you can use two lists, one for the keys (strings) and one for the values (labels).
Finally, the substitution rule can be used as a toolchain in the doxygen rule.
All configurations using the make variable syntax will be replaced with the values defined in the make_var_substitution rule.
To retrieve the stamp information from the bazel-out/stable-status.txt
file, we have to define a genrule that reads the file and extracts the BUILD_EMBED_LABEL
. That information will be used to modify our custom Doxyfile.template
file we will provide to the doxygen rule.
# BUILD.bazel # Use a shell script to read the version from the stable-status.txt file # It will replace the pattern {{PROJECT_NUMBER}} in the Doxyfile.template file genrule( name = "doxyfile_template", srcs = ["Doxyfile.template"], outs = ["NewDoxyfile"], cmd = "sed s/{{PROJECT_NUMBER}}/$(grep -oP '(?<=BUILD_EMBED_LABEL ).+' bazel-out/stable-status.txt)/ $(SRCS) > $@", cmd_ps = "Get-content $(SRCS) | ForEach-Object { $$_ -replace '{{PROJECT_NUMBER}}', (Select-String -Pattern '(?<=BUILD_EMBED_LABEL +)(.+)' bazel-out/stable-status.txt -AllMatches | Select-Object -Expand Matches | Select-Object -Expand Value) } > $@", stamp = -1, # Only update if --stamp is passed )
It is also possible to use files produced by other rules as input files for the doxygen rule. For example, we can use a genrule
to create an header.html
file that will be used as the header for the doxygen documentation.
# BUILD.bazel genrule( name = "header", srcs = ["header.html"], outs = ["header.html"], cmd = "echo '<h1>My Header</h1>' > $@", )
We need to include the genrule in the locations
attribute of a make_var_substitution
rule, as well as including it in the srcs
attribute of the doxygen rule and specifying the location substitution in the doxygen
rule.
# BUILD.bazel load("@doxygen//:doxygen.bzl", "doxygen") load("//substitutions:make_var_substitution.bzl", "make_var_substitution") # Use a shell script to create a header file genrule( name = "header", srcs = ["header.html"], outs = ["header.html"], cmd = "echo '<h1>My Header</h1>' > $@", ) # Use a shell script to read the version from the stable-status.txt file # It will replace the pattern {{PROJECT_NUMBER}} in the Doxyfile.template file genrule( name = "doxyfile_template", srcs = ["Doxyfile.template"], outs = ["NewDoxyfile"], cmd = "sed s/{{PROJECT_NUMBER}}/$(grep -oP '(?<=BUILD_EMBED_LABEL ).+' bazel-out/stable-status.txt)/ $(SRCS) > $@", cmd_ps = "Get-content $(SRCS) | ForEach-Object { $$_ -replace '{{PROJECT_NUMBER}}', (Select-String -Pattern '(?<=BUILD_EMBED_LABEL +)(.+)' bazel-out/stable-status.txt -AllMatches | Select-Object -Expand Matches | Select-Object -Expand Value) } > $@", stamp = -1, # Only update if --stamp is passed ) # Use the make_var_substitution rule to define some other custom substitutions make_var_substitution( name = "make_var_substitution", variables = { "NAME": "substitutions", }, locations = { "HEADER": ":header", }, ) doxygen( name = "doxygen", srcs = glob([ "*.h", "*.cpp", ]) + [":header"], # We need to indicate all the rules this doxygen rule depends on project_brief = "$(BUILD_DESCRIPTION)", # => "no stamp" or "//substitutions:build_description" if the build is stamped project_name = "$(NAME)", # => "substitutions" doxyfile_template = ":doxyfile_template", html_header = "$(HEADER)", # => "header.html" toolchains = [":make_var_substitution"], )