diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml index 55c56ed..04023f7 100644 --- a/.bcr/presubmit.yml +++ b/.bcr/presubmit.yml @@ -1,7 +1,7 @@ bcr_test_module: module_path: "examples" matrix: - platform: ["fedora40", "ubuntu2204", "windows"] + platform: ["fedora40", "ubuntu2204", "windows", "macos"] bazel: [7.x] tasks: run_tests: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 313f386..a28cb65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: tests: strategy: matrix: - os: [ubuntu-latest, windows-latest] # No macOS for now + os: [ubuntu-latest, windows-latest, macos-latest] subdir: [base, kwargs, doxyfile, latex, nested, custom, awesome] runs-on: ${{ matrix.os }} @@ -50,3 +50,40 @@ jobs: with: files: "examples/bazel-bin/${{ matrix.subdir }}/html/index.html" fail: true + + tests-multiple-installations: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + subdir: [base, kwargs, doxyfile, latex, nested, custom, awesome] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Install doxygen + uses: ssciwr/doxygen-install@v1 + - name: Enable use of windows doxygen by decommenting the module extension line + uses: richardrigutins/replace-in-files@v2 + with: + search-text: '# doxygen_extension.version(version = "1.11.0", sha256 = "478fc9897d00ca181835d248a4d3e5c83c26a32d1c7571f4321ddb0f2e97459f", platform = "windows")' + replacement-text: doxygen_extension.version(version = "1.11.0", sha256 = "478fc9897d00ca181835d248a4d3e5c83c26a32d1c7571f4321ddb0f2e97459f", platform = "windows") + files: examples/MODULE.bazel + - name: Enable use of mac doxygen by decommenting the module extension line + uses: richardrigutins/replace-in-files@v2 + with: + search-text: '# doxygen_extension.version(version = "1.12.0", sha256 = "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001", platform = "mac")' + replacement-text: doxygen_extension.version(version = "1.12.0", sha256 = "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001", platform = "mac") + files: examples/MODULE.bazel + - name: Enable use linux doxygen by decommenting the module extension line + uses: richardrigutins/replace-in-files@v2 + with: + search-text: '# doxygen_extension.version(version = "1.10.0", sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", platform = "linux")' + replacement-text: doxygen_extension.version(version = "1.10.0", sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", platform = "linux") + files: examples/MODULE.bazel + - name: Build ${{ matrix.subdir }} + run: bazel build //${{ matrix.subdir }}:doxygen + working-directory: examples + - name: Check output + uses: andstor/file-existence-action@v3 + with: + files: "examples/bazel-bin/${{ matrix.subdir }}/html/index.html" + fail: true diff --git a/BUILD.bazel b/BUILD.bazel index 6971a21..0f95292 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,8 +1,3 @@ """rules_doxygen BUILD file""" -exports_files([ - "Doxyfile.template", - "doxygen.BUILD.bazel", - "doxygen.bzl", - "extensions.bzl", -]) +exports_files(["extensions.bzl"]) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ad1b78..23a8c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Default doxygen version is now `1.12.0` +## [1.3.0] + +### Added + +- Support hermetic build for `macos` platform (thanks to @kaycebasques) +- Support for platform-specific configurations in the extension rule + +### Changed + +- Update dependencies (stardoc 0.6.2 -> 0.7.1, platforms 0.0.5 -> 0.0.10) +- Refactor of internal repository and extension rules +- Updated documentation + ## [NEXT.VERSION] [1.0.0]: https://github.com/TendTo/rules_doxygen/tree/1.0.0 @@ -73,4 +86,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [1.1.2]: https://github.com/TendTo/rules_doxygen/compare/1.1.1...1.1.2 [1.1.3]: https://github.com/TendTo/rules_doxygen/compare/1.1.2...1.1.3 [1.2.0]: https://github.com/TendTo/rules_doxygen/compare/1.1.3...1.2.0 -[NEXT.VERSION]: https://github.com/TendTo/rules_doxygen/compare/1.2.0...HEAD +[1.3.0]: https://github.com/TendTo/rules_doxygen/compare/1.2.0...1.3.0 +[NEXT.VERSION]: https://github.com/TendTo/rules_doxygen/compare/1.3.0...HEAD diff --git a/MODULE.bazel b/MODULE.bazel index da26679..a49350f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,5 +1,5 @@ """rules_doxygen module""" -module(name = "rules_doxygen", version = "1.2.0", compatibility_level = 1) +module(name = "rules_doxygen", version = "1.3.0", compatibility_level = 1) -bazel_dep(name = "platforms", version = "0.0.5") -bazel_dep(name = "stardoc", version = "0.6.2", dev_dependency = True) +bazel_dep(name = "platforms", version = "0.0.10") +bazel_dep(name = "stardoc", version = "0.7.1", dev_dependency = True) diff --git a/README.md b/README.md index 98e5474..f9a334b 100644 --- a/README.md +++ b/README.md @@ -9,18 +9,22 @@ This repository contains a [Starlark](https://github.com/bazelbuild/starlark) im Add the following to your _MODULE.bazel_: ```bzl -bazel_dep(name = "rules_doxygen", version = "1.2.0", dev_dependency = True) +# MODULE.bazel file + +bazel_dep(name = "rules_doxygen", version = "1.3.0", dev_dependency = True) ``` If you don't want to depend on the [Bazel package registry](https://bazel.build/external/bazelbuild/rules_pkg) or you want to use a not-yet-published version of this module, you can use an archive override by adding the following lines below the `bazel_dep` rule in your _MODULE.bazel_ file: ```bzl -bazel_dep(name = "rules_doxygen", version = "1.2.0", dev_dependency = True) +# MODULE.bazel file + +bazel_dep(name = "rules_doxygen", version = "1.3.0", dev_dependency = True) archive_override( module_name = "rules_doxygen", urls = "https://github.com/TendTo/rules_doxygen/archive/refs/heads/main.tar.gz", strip_prefix = "rules_doxygen-main", - # The SHA256 checksum of the archive file, based on the rules' version, for reproducibility + # The SHA256 checksum of the archive file, based on the rules' version # integrity = "sha256-0SCaZuAerluoDs6HXMb0Bj9FttZVieM4+Dpd9gnMM+o=", # Example ) ``` @@ -30,19 +34,16 @@ archive_override( To select a doxygen version to use, use the `doxygen_extension` module extension below the `bazel_dep` rule in your MODULE.bazel file. ```bzl -doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") -use_repo(doxygen_extension, "doxygen") -``` +# MODULE.bazel file -By default, version `1.12.0` of Doxygen is used. To select a different version, indicate it in the `version` module: +bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) -```bzl doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") -# Using the 1.10.0 version of Doxygen on Windows instead of the default 1.12.0 -doxygen_extension.version(version = "1.10.0", sha256 = "2135c1d5bdd6e067b3d0c40a4daac5d63d0fee1b3f4d6ef1e4f092db0d632d5b") use_repo(doxygen_extension, "doxygen") ``` +By default, version `1.12.0` of Doxygen is used. To select a different version, indicate it in the `version` module: + If you don't know the SHA256 of the Doxygen binary, just leave it empty. The build will fail with an error message containing the correct SHA256. @@ -52,7 +53,40 @@ Download from https://github.com/doxygen/doxygen/releases/download/Release_1_10_ If you set the version to `0.0.0`, the doxygen executable will be assumed to be available from the PATH. No download will be performed and bazel will use the installed version of doxygen. -Keep in mind that this will break the hermeticity of your build, as it will now depend on the environment. + +> [!Warning] +> Setting the version to `0.0.0` this will break the hermeticity of your build, as it will now depend on the environment. + +The module also supports multiple versions of doxygen for different platforms. +Each will only be downloaded if the given platform matches the current platform. + +> [!Tip] +> Not indicating the platform will make the configuration apply to all platforms. +> The build will fail when the downloaded file does not match the SHA256 checksum, i.e. when the platform changes. +> Unless you are using a system-wide doxygen installation, you should always specify the platform. + +```bzl +# MODULE.bazel file + +bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) + +doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") + +# Download doxygen version 1.10.0 on linux +doxygen_extension.version( + version = "1.10.0", + sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", + platform = "linux", +) +# Use the local doxygen installation on mac +doxygen_extension.version( + version = "0.0.0", + platform = "mac", +) +# Since no configuration has been provided, windows will fallback to the default version + +use_repo(doxygen_extension, "doxygen") +``` > [!Note] > See [the documentation](docs/extensions_doc.md) for more information. @@ -65,6 +99,7 @@ Only the sources are required, the rest of the parameters are optional. ```bzl # My BUILD.bazel file + doxygen( name = "doxygen", # Name of the rule, can be anything srcs = glob([ # List of sources to document. @@ -73,12 +108,13 @@ doxygen( ]) + ["README.md"], project_brief = "Example project for doxygen", # Brief description of the project project_name = "base", # Name of the project - configurations = [ # Additional configurations to add to the Doxyfile - "GENERATE_HTML = YES", # They are the same as the Doxyfile options, - "GENERATE_LATEX = NO", # and will override the default values + configurations = [ # Customizable configurations + "GENERATE_HTML = YES", # that override the default ones + "GENERATE_LATEX = NO", # from the Doxyfile "USE_MDFILE_AS_MAINPAGE = README.md", ] - tags = ["manual"] # Tags to add to the target. This way the target won't run unless explicitly called + tags = ["manual"] # Tags to add to the target. + # This way the target won't run unless explicitly called ) ``` @@ -100,6 +136,7 @@ For example, if the _BUILD.bazel_ file is in the root of the repository, and the ```bzl # BUILD.bazel file in the root of the repository + doxygen( name = "doxygen", srcs = glob([ @@ -135,5 +172,4 @@ tar -czvf doxygen.tar.gz bazel-bin//html ## TODO -- [ ] Add support for macos other than the system-wide doxygen installation (I can't be bothered :D) - [ ] Add more easy-to-use common configuration for the Doxyfile diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index ef22604..4fbf878 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -13,7 +13,7 @@ bzl_library( stardoc( name = "doxygen_doc", out = "doxygen_doc.md", - input = "@rules_doxygen//:doxygen.bzl", + input = "@rules_doxygen//doxygen:doxygen.bzl", ) stardoc( diff --git a/docs/doxygen_doc.md b/docs/doxygen_doc.md index bd24a90..1eb23d3 100755 --- a/docs/doxygen_doc.md +++ b/docs/doxygen_doc.md @@ -7,6 +7,8 @@ Doxygen rule for Bazel. ## doxygen
+load("@doxygen//:doxygen.bzl", "doxygen")
+
 doxygen(name, srcs, project_name, project_brief, project_number, project_logo, project_icon,
         use_mdfile_as_mainpage, extract_private, html_footer, html_header, filter_patterns,
         use_mathjax, html_extra_stylesheet, html_extra_files, html_colorstyle, aliases, have_dot,
diff --git a/docs/extensions_doc.md b/docs/extensions_doc.md
index 6ca2066..847be0e 100755
--- a/docs/extensions_doc.md
+++ b/docs/extensions_doc.md
@@ -2,25 +2,51 @@
 
 Repository rule for downloading the correct version of doxygen using module extensions.
 
-
+
 
-## local_repository_doxygen
+## doxygen_repository
 
 
-local_repository_doxygen(name, build, doxyfile_template, doxygen_bzl, executable, repo_mapping)
+load("@rules_doxygen//:extensions.bzl", "doxygen_repository")
+
+doxygen_repository(name, build, doxyfile_template, doxygen_bzl, platforms, repo_mapping, sha256s,
+                   versions)
 
Repository rule for doxygen. -Used to create a local repository for doxygen, containing the installed doxygen binary and all the necessary files to run the doxygen macro. -In order to use this rule, you must have doxygen installed on your system and the binary (named doxygen) must available in the PATH. -Keep in mind that this will break the hermeticity of your build, as it will now depend on the environment. +It can be provided with a configuration for each of the three platforms (windows, mac, linux) to download the correct version of doxygen only when the configuration matches the current platform. +Depending on the version, the behavior will change: +- If the version is set to `0.0.0`, the repository will use the installed version of doxygen, getting the binary from the PATH. +- If a version is specified, the repository will download the correct version of doxygen and make it available to the requesting module. + +> [!Warning] +> If version is set to `0.0.0`, the rules needs doxygen to be installed on your system and the binary (named doxygen) must available in the PATH. +> Keep in mind that this will break the hermeticity of your build, as it will now depend on the environment. + +You can further customize the repository by specifying the `doxygen_bzl`, `build`, and `doxyfile_template` attributes, but the default values should be enough for most use cases. ### Example ```starlark -local_repository_doxygen( +# Download the os specific version 1.12.0 of doxygen supporting all platforms +doxygen_repository( name = "doxygen", + versions = ["1.12.0", "1.12.0", "1.12.0"], + sha256s = [ + "07f1c92cbbb32816689c725539c0951f92c6371d3d7f66dfa3192cbe88dd3138", + "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001", + "3c42c3f3fb206732b503862d9c9c11978920a8214f223a3950bbf2520be5f647", + ] + platforms = ["windows", "mac", "linux"], +) + +# Use the system installed version of doxygen on linux and download version 1.11.0 for windows. No support for mac +doxygen_repository( + name = "doxygen", + version = ["0.0.0", "1.11.0"], + sha256s = ["", "478fc9897d00ca181835d248a4d3e5c83c26a32d1c7571f4321ddb0f2e97459f"], + platforms = ["linux", "windows"], ) ``` @@ -29,12 +55,14 @@ local_repository_doxygen( | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this repository. | Name | required | | -| build | The BUILD file of the repository | Label | optional | `"@rules_doxygen//:doxygen.BUILD.bazel"` | -| doxyfile_template | The Doxyfile template to use | Label | optional | `"@rules_doxygen//:Doxyfile.template"` | -| doxygen_bzl | The starlark file containing the doxygen macro | Label | optional | `"@rules_doxygen//:doxygen.bzl"` | -| executable | The doxygen executable to use. Must refer to an executable file. Defaults to the doxygen executable in the PATH. | Label | optional | `None` | -| repo_mapping | In `WORKSPACE` context only: a dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.

For example, an entry `"@foo": "@bar"` declares that, for any time this repository depends on `@foo` (such as a dependency on `@foo//some:target`, it should actually resolve that dependency within globally-declared `@bar` (`@bar//some:target`).

This attribute is _not_ supported in `MODULE.bazel` context (when invoking a repository rule inside a module extension's implementation function). | Dictionary: String -> String | optional | | +| name | A unique name for this repository. | Name | required | | +| build | The BUILD file of the repository | Label | optional | `"@rules_doxygen//doxygen:BUILD.bazel"` | +| doxyfile_template | The Doxyfile template to use | Label | optional | `"@rules_doxygen//doxygen:Doxyfile.template"` | +| doxygen_bzl | The starlark file containing the doxygen macro | Label | optional | `"@rules_doxygen//doxygen:doxygen.bzl"` | +| platforms | List of platforms to download the doxygen binary for. Available options are (windows, mac, linux). Must be the same length as `version` and `sha256s`. | List of strings | required | | +| repo_mapping | In `WORKSPACE` context only: a dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.

For example, an entry `"@foo": "@bar"` declares that, for any time this repository depends on `@foo` (such as a dependency on `@foo//some:target`, it should actually resolve that dependency within globally-declared `@bar` (`@bar//some:target`).

This attribute is _not_ supported in `MODULE.bazel` context (when invoking a repository rule inside a module extension's implementation function). | Dictionary: String -> String | optional | | +| sha256s | List of sha256 hashes of the doxygen archive. Must be the same length as `versions and `platforms`. | List of strings | required | | +| versions | List of versions of doxygen to use. If set to `0.0.0`, the doxygen executable will be assumed to be available from the PATH. Must be the same length as `sha256s` and `platforms`. | List of strings | required | | @@ -43,7 +71,7 @@ local_repository_doxygen(
 doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension")
-doxygen_extension.version(sha256, version)
+doxygen_extension.version(platform, sha256, version)
 
Module extension for declaring the doxygen version to use. @@ -63,17 +91,83 @@ Download from https://github.com/doxygen/doxygen/releases/download/Release_1_10_ If you set the version to `0.0.0`, the doxygen executable will be assumed to be available from the PATH. No download will be performed and bazel will use the installed version of doxygen. -Keep in mind that this will break the hermeticity of your build, as it will now depend on the environment. -### Example +> [!Warning] +> Setting the version to `0.0.0` this will break the hermeticity of your build, as it will now depend on the environment. + +The module also supports multiple versions of doxygen for different platforms. +Each will only be downloaded if the given platform matches the current platform. + +> [!Tip] +> Not indicating the platform will make the configuration apply to all platforms. +> The build will fail when the downloaded file does not match the SHA256 checksum, i.e. when the platform changes. +> Unless you are using a system-wide doxygen installation, you should always specify the platform. + +### Examples + +```starlark +# MODULE.bazel file + +bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) + +doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") + +# Using the 1.10.0 version of Doxygen instead of the default 1.12.0. +# Note that che checksum is correct only if the platform is windows. +# If the platform is different, the build will fail. +doxygen_extension.version( + version = "1.10.0", + sha256 = "2135c1d5bdd6e067b3d0c40a4daac5d63d0fee1b3f4d6ef1e4f092db0d632d5b", +) + +use_repo(doxygen_extension, "doxygen") +``` ```starlark +# MODULE.bazel file + +bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) + +doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") + +doxygen_extension.version( + version = "1.10.0", + sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", + platform = "linux", +) +doxygen_extension.version( + version = "1.12.0", + sha256 = "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001", + platform = "mac", +) +doxygen_extension.version( + version = "1.11.0", + sha256 = "478fc9897d00ca181835d248a4d3e5c83c26a32d1c7571f4321ddb0f2e97459f", + platform = "windows", +) + +use_repo(doxygen_extension, "doxygen") +``` + +```bzl +# MODULE.bazel file + bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") -# Using the 1.10.0 version of Doxygen on Windows instead of the default 1.12.0 -doxygen_extension.version(version = "1.10.0", sha256 = "2135c1d5bdd6e067b3d0c40a4daac5d63d0fee1b3f4d6ef1e4f092db0d632d5b") +# Download doxygen version 1.10.0 on linux +doxygen_extension.version( + version = "1.10.0", + sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", + platform = "linux", +) +# Use the local doxygen installation on mac +doxygen_extension.version( + version = "0.0.0", + platform = "mac", +) +# Since no configuration has been provided, windows will fallback to the default version use_repo(doxygen_extension, "doxygen") ``` @@ -89,6 +183,7 @@ use_repo(doxygen_extension, "doxygen") | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | +| platform | The target platform for the doxygen binary. Available options are (windows, mac, linux). If not specified, it will select the platform it is currently running on. | String | optional | `""` | | sha256 | The sha256 hash of the doxygen archive. If not specified, an all-zero hash will be used. | String | optional | `""` | | version | The version of doxygen to use. If set to `0.0.0`, the doxygen executable will be assumed to be available from the PATH | String | required | | diff --git a/doxygen.BUILD.bazel b/doxygen.BUILD.bazel deleted file mode 100644 index 695f370..0000000 --- a/doxygen.BUILD.bazel +++ /dev/null @@ -1,17 +0,0 @@ -"""Doxygen BUILD file""" - -filegroup( - name = "Doxyfile.template", - srcs = ["@rules_doxygen//:Doxyfile.template"], - visibility = ["//visibility:public"], -) - -filegroup( - name = "executable", - srcs = select({ - "@platforms//os:linux": ["bin/doxygen"], - "@platforms//os:macos": ["doxygen"], - "@platforms//os:windows": ["doxygen.exe"], - }, "Unsupported platform"), - visibility = ["//visibility:public"], -) diff --git a/doxygen/BUILD.bazel b/doxygen/BUILD.bazel new file mode 100644 index 0000000..b463064 --- /dev/null +++ b/doxygen/BUILD.bazel @@ -0,0 +1,19 @@ +"""Doxygen BUILD file""" + +exports_files([ + "Doxyfile.template", + "doxygen.bzl", +]) + +filegroup( + name = "executable", + srcs = select( + { + "@platforms//os:linux": ["linux/doxygen"], + "@platforms//os:macos": ["mac/doxygen"], + "@platforms//os:windows": ["windows/doxygen.exe"], + }, + "Unsupported platform", + ), + visibility = ["//visibility:public"], +) diff --git a/Doxyfile.template b/doxygen/Doxyfile.template similarity index 100% rename from Doxyfile.template rename to doxygen/Doxyfile.template diff --git a/doxygen.bzl b/doxygen/doxygen.bzl similarity index 99% rename from doxygen.bzl rename to doxygen/doxygen.bzl index b5329fd..733b37d 100644 --- a/doxygen.bzl +++ b/doxygen/doxygen.bzl @@ -183,7 +183,7 @@ def doxygen( hide_in_body_docs: Whether to hide in body docs. exclude_symbols: A list of symbols to exclude. example_path: The path to the examples. They must be added to the source files. - dot_executable: Label of the doxygen executable. Make sure it is also added to the `srcs` of the macro + dot_executable: Label of the doxygen executable. Make sure it is also added to the `srcs` of the macro configurations: A list of additional configuration parameters to pass to Doxygen. doxyfile_template: The template file to use to generate the Doxyfile. The following substitutions are available:
diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel index 9dbdfb3..33c4ad4 100644 --- a/examples/MODULE.bazel +++ b/examples/MODULE.bazel @@ -7,6 +7,13 @@ local_path_override( ) doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") -# Test doxygen_extension with a system installation of doxygen + +# doxygen_extension with a system installation of doxygen # doxygen_extension.version(version = "0.0.0") + +# Multiple versions of doxygen for different platforms +# doxygen_extension.version(version = "1.10.0", sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", platform = "linux") +# doxygen_extension.version(version = "1.12.0", sha256 = "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001", platform = "mac") +# doxygen_extension.version(version = "1.11.0", sha256 = "478fc9897d00ca181835d248a4d3e5c83c26a32d1c7571f4321ddb0f2e97459f", platform = "windows") + use_repo(doxygen_extension, "doxygen") diff --git a/extensions.bzl b/extensions.bzl index dec84a9..59b0ec6 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -1,8 +1,9 @@ """Repository rule for downloading the correct version of doxygen using module extensions.""" -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:cache.bzl", "get_default_canonical_id") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "get_auth") -def _local_repository_doxygen(ctx): +def _doxygen_repository(ctx): """ Repository rule for doxygen. @@ -13,60 +14,160 @@ def _local_repository_doxygen(ctx): """ # Copy the necessary files to the repository by reading them from the current repository + if len(ctx.attr.versions) != len(ctx.attr.sha256s) or len(ctx.attr.versions) != len(ctx.attr.platforms): + fail("The number of versions, sha256s and platforms must be the same") + for platform in ctx.attr.platforms: + if platform not in ("windows", "mac", "linux"): + fail("Unsupported platform: '%s'. Available options are (windows, mac, linux)" % platform) + ctx.file("WORKSPACE", "workspace(name = %s)\n" % repr(ctx.name)) ctx.file("doxygen.bzl", ctx.read(ctx.attr.doxygen_bzl)) ctx.file("BUILD.bazel", ctx.read(ctx.attr.build)) ctx.file("Doxyfile.template", ctx.read(ctx.attr.doxyfile_template)) - # Copy the doxygen executable to the repository - doxygen_content = ctx.read(ctx.attr.executable or ctx.which("doxygen")) - if ctx.os.name.startswith("windows"): - ctx.file("doxygen.exe", doxygen_content, legacy_utf8 = False) - elif ctx.os.name.startswith("mac"): - ctx.file("doxygen", doxygen_content, legacy_utf8 = False) - elif ctx.os.name == "linux": - ctx.file("bin/doxygen", doxygen_content, legacy_utf8 = False) - else: - fail("Unsuppported OS: %s" % ctx.os.name) - -local_repository_doxygen = repository_rule( - implementation = _local_repository_doxygen, + for doxygen_version, sha256, platform in zip(ctx.attr.versions, ctx.attr.sha256s, ctx.attr.platforms): + # If the version is set to 0.0.0 use the installed version of doxygen from the PATH + # No download will be performed + # This happens only if the platform matches the current platform + if doxygen_version == "0.0.0": + if platform == "windows" and ctx.os.name.startswith("windows"): + ctx.file("windows/doxygen.exe", ctx.read(ctx.which("doxygen")), legacy_utf8 = False) + elif platform == "mac" and ctx.os.name.startswith("mac"): + ctx.file("mac/doxygen", ctx.read(ctx.which("doxygen")), legacy_utf8 = False) + elif platform == "linux" and ctx.os.name == "linux": + ctx.file("linux/doxygen", ctx.read(ctx.which("doxygen")), legacy_utf8 = False) + continue + + url = "https://github.com/doxygen/doxygen/releases/download/Release_%s/doxygen-%s.%s" + doxygen_version_dash = doxygen_version.replace(".", "_") + download_output = "doxygen-dir" + + if platform == "windows" and ctx.os.name.startswith("windows"): + # For windows, download the zip file and extract the executable and dll + url = url % (doxygen_version_dash, doxygen_version, "windows.x64.bin.zip") + ctx.download_and_extract( + url = url, + output = download_output, + sha256 = sha256, + type = "zip", + canonical_id = get_default_canonical_id(ctx, [url]), + auth = get_auth(ctx, [url]), + ) + + # Copy the doxygen executable (and dll) to the repository + ctx.file("windows/doxygen.exe", ctx.read("doxygen-dir/doxygen.exe"), legacy_utf8 = False) + ctx.file("windows/libclang.dll", ctx.read("doxygen-dir/libclang.dll"), legacy_utf8 = False) + + elif platform == "mac" and ctx.os.name.startswith("mac"): + # For mac, download the dmg file, mount it and copy the executable + url = url % (doxygen_version_dash, doxygen_version, "dmg") + download_output = "doxygen.dmg" + ctx.download( + url = url, + output = download_output, + sha256 = sha256, + canonical_id = get_default_canonical_id(ctx, [url]), + auth = get_auth(ctx, [url]), + ) + + # Mount the dmg file + ctx.execute(["hdiutil", "attach", "-nobrowse", "-readonly", "-mountpoint", "doxygen-mount", download_output]) + + # Copy the doxygen executable to the repository + ctx.file("mac/doxygen", ctx.read("doxygen-mount/Doxygen.app/Contents/Resources/doxygen"), legacy_utf8 = False) + + # Unmount the dmg file + ctx.execute(["hdiutil", "detach", "doxygen-mount"]) + + elif platform == "linux" and ctx.os.name == "linux": + # For linux, download the tar.gz file and extract the executable + url = url % (doxygen_version_dash, doxygen_version, "linux.bin.tar.gz") + ctx.download_and_extract( + url = url, + output = download_output, + sha256 = sha256, + type = "tar.gz", + canonical_id = get_default_canonical_id(ctx, [url]), + auth = get_auth(ctx, [url]), + stripPrefix = "doxygen-%s" % doxygen_version, + ) + + # Copy the doxygen executable to the repository + ctx.file("linux/doxygen", ctx.read("doxygen-dir/bin/doxygen"), legacy_utf8 = False) + + # Delete temporary files + ctx.delete(download_output) + +doxygen_repository = repository_rule( + implementation = _doxygen_repository, doc = """ Repository rule for doxygen. -Used to create a local repository for doxygen, containing the installed doxygen binary and all the necessary files to run the doxygen macro. -In order to use this rule, you must have doxygen installed on your system and the binary (named doxygen) must available in the PATH. -Keep in mind that this will break the hermeticity of your build, as it will now depend on the environment. +It can be provided with a configuration for each of the three platforms (windows, mac, linux) to download the correct version of doxygen only when the configuration matches the current platform. +Depending on the version, the behavior will change: +- If the version is set to `0.0.0`, the repository will use the installed version of doxygen, getting the binary from the PATH. +- If a version is specified, the repository will download the correct version of doxygen and make it available to the requesting module. + +> [!Warning] +> If version is set to `0.0.0`, the rules needs doxygen to be installed on your system and the binary (named doxygen) must available in the PATH. +> Keep in mind that this will break the hermeticity of your build, as it will now depend on the environment. + +You can further customize the repository by specifying the `doxygen_bzl`, `build`, and `doxyfile_template` attributes, but the default values should be enough for most use cases. ### Example ```starlark -local_repository_doxygen( +# Download the os specific version 1.12.0 of doxygen supporting all platforms +doxygen_repository( name = "doxygen", + versions = ["1.12.0", "1.12.0", "1.12.0"], + sha256s = [ + "07f1c92cbbb32816689c725539c0951f92c6371d3d7f66dfa3192cbe88dd3138", + "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001", + "3c42c3f3fb206732b503862d9c9c11978920a8214f223a3950bbf2520be5f647", + ] + platforms = ["windows", "mac", "linux"], +) + +# Use the system installed version of doxygen on linux and download version 1.11.0 for windows. No support for mac +doxygen_repository( + name = "doxygen", + version = ["0.0.0", "1.11.0"], + sha256s = ["", "478fc9897d00ca181835d248a4d3e5c83c26a32d1c7571f4321ddb0f2e97459f"], + platforms = ["linux", "windows"], ) ``` """, attrs = { + "versions": attr.string_list( + doc = "List of versions of doxygen to use. If set to `0.0.0`, the doxygen executable will be assumed to be available from the PATH. Must be the same length as `sha256s` and `platforms`.", + mandatory = True, + allow_empty = False, + ), + "sha256s": attr.string_list( + doc = "List of sha256 hashes of the doxygen archive. Must be the same length as `versions and `platforms`.", + mandatory = True, + allow_empty = False, + ), + "platforms": attr.string_list( + doc = "List of platforms to download the doxygen binary for. Available options are (windows, mac, linux). Must be the same length as `version` and `sha256s`.", + mandatory = True, + allow_empty = False, + ), "doxygen_bzl": attr.label( doc = "The starlark file containing the doxygen macro", allow_single_file = True, - default = Label("@rules_doxygen//:doxygen.bzl"), + default = Label("@rules_doxygen//doxygen:doxygen.bzl"), ), "build": attr.label( doc = "The BUILD file of the repository", allow_single_file = True, - default = Label("@rules_doxygen//:doxygen.BUILD.bazel"), + default = Label("@rules_doxygen//doxygen:BUILD.bazel"), ), "doxyfile_template": attr.label( doc = "The Doxyfile template to use", allow_single_file = True, - default = Label("@rules_doxygen//:Doxyfile.template"), - ), - "executable": attr.label( - executable = True, - cfg = "exec", - allow_single_file = True, - doc = "The doxygen executable to use. Must refer to an executable file. Defaults to the doxygen executable in the PATH.", + default = Label("@rules_doxygen//doxygen:Doxyfile.template"), ), }, ) @@ -80,57 +181,45 @@ def _doxygen_extension_impl(ctx): ctx: a [module context](https://bazel.build/rules/lib/builtins/module_ctx) object containing the module's attributes """ for mod in ctx.modules: - if len(mod.tags.version) > 1: - fail("Only one version of doxygen can be specified") - doxygen_version = "1.12.0" - strip_prefix = "" - if ctx.os.name.startswith("windows"): - doxygen_sha256 = "07f1c92cbbb32816689c725539c0951f92c6371d3d7f66dfa3192cbe88dd3138" - elif ctx.os.name.startswith("mac"): - doxygen_sha256 = "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001" - elif ctx.os.name == "linux": - doxygen_sha256 = "3c42c3f3fb206732b503862d9c9c11978920a8214f223a3950bbf2520be5f647" - else: - fail("Unsuppported OS: %s" % ctx.os.name) + platforms = [] + versions = [] + sha256s = [] - for attr in mod.tags.version: - doxygen_version = attr.version if attr.version != "" else fail("Version must be specified") - doxygen_sha256 = attr.sha256 if attr.sha256 != "" else "0" * 64 + default_configurations = { + "windows": struct(version = "1.12.0", sha256 = "07f1c92cbbb32816689c725539c0951f92c6371d3d7f66dfa3192cbe88dd3138"), + "mac": struct(version = "1.12.0", sha256 = "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001"), + "linux": struct(version = "1.12.0", sha256 = "3c42c3f3fb206732b503862d9c9c11978920a8214f223a3950bbf2520be5f647"), + } - if doxygen_version == "0.0.0": - local_repository_doxygen( - name = "doxygen", - ) - return - - doxygen_version_dash = doxygen_version.replace(".", "_") + # Otherwise, add all the configurations (version and sha256) for each platform + for attr in mod.tags.version: + platform = attr.platform if attr.platform != "" else "windows" if ctx.os.name.startswith("windows") else "mac" if ctx.os.name.startswith("mac") else "linux" + if platform not in default_configurations: + fail("Unsupported platform: '%s'. Available options are (windows, mac, linux)" % platform) + if platform in platforms: + fail("Doxygen version/sha256 for platform '%s' was already specified: (version = '%s', sha256 = '%s')" % (platform, versions[platforms.index(platform)], sha256s[platforms.index(platform)])) + platforms.append(platform) + versions.append(attr.version if attr.version != "" else fail("Version must be specified")) + sha256s.append(attr.sha256 if attr.sha256 != "" else "0" * 64) - url = "https://github.com/doxygen/doxygen/releases/download/Release_%s/doxygen-%s.%s" - if ctx.os.name.startswith("windows"): - url = url % (doxygen_version_dash, doxygen_version, "windows.x64.bin.zip") - elif ctx.os.name.startswith("mac"): # TODO: support macos for hermetic build - url = url % (doxygen_version_dash, doxygen_version, "dmg") - fail("Unsuppported OS: %s" % ctx.os.name) - elif ctx.os.name == "linux": - url = url % (doxygen_version_dash, doxygen_version, "linux.bin.tar.gz") - strip_prefix = "doxygen-%s" % doxygen_version - else: - fail("Unsuppported OS: %s" % ctx.os.name) + # If no version is specified for a platform, use the default + for platform in default_configurations: + if platform not in platforms: + platforms.append(platform) + versions.append(default_configurations[platform].version) + sha256s.append(default_configurations[platform].sha256) - doxygen_bzl_content = ctx.read(Label("@rules_doxygen//:doxygen.bzl")) - http_archive( + doxygen_repository( name = "doxygen", - build_file = "@rules_doxygen//:doxygen.BUILD.bazel", - url = url, - sha256 = doxygen_sha256, - patch_cmds = ["cat > 'doxygen.bzl' <<- EOF\n%s\nEOF" % doxygen_bzl_content], - patch_cmds_win = ["Set-Content -Path 'doxygen.bzl' -Value '%s'" % doxygen_bzl_content], - strip_prefix = strip_prefix, + versions = versions, + sha256s = sha256s, + platforms = platforms, ) _doxygen_version = tag_class(attrs = { "version": attr.string(doc = "The version of doxygen to use. If set to `0.0.0`, the doxygen executable will be assumed to be available from the PATH", mandatory = True), "sha256": attr.string(doc = "The sha256 hash of the doxygen archive. If not specified, an all-zero hash will be used."), + "platform": attr.string(doc = "The target platform for the doxygen binary. Available options are (windows, mac, linux). If not specified, it will select the platform it is currently running on."), }) doxygen_extension = module_extension( @@ -154,17 +243,83 @@ Download from https://github.com/doxygen/doxygen/releases/download/Release_1_10_ If you set the version to `0.0.0`, the doxygen executable will be assumed to be available from the PATH. No download will be performed and bazel will use the installed version of doxygen. -Keep in mind that this will break the hermeticity of your build, as it will now depend on the environment. -### Example +> [!Warning] +> Setting the version to `0.0.0` this will break the hermeticity of your build, as it will now depend on the environment. + +The module also supports multiple versions of doxygen for different platforms. +Each will only be downloaded if the given platform matches the current platform. + +> [!Tip] +> Not indicating the platform will make the configuration apply to all platforms. +> The build will fail when the downloaded file does not match the SHA256 checksum, i.e. when the platform changes. +> Unless you are using a system-wide doxygen installation, you should always specify the platform. + +### Examples ```starlark +# MODULE.bazel file + bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") -# Using the 1.10.0 version of Doxygen on Windows instead of the default 1.12.0 -doxygen_extension.version(version = "1.10.0", sha256 = "2135c1d5bdd6e067b3d0c40a4daac5d63d0fee1b3f4d6ef1e4f092db0d632d5b") +# Using the 1.10.0 version of Doxygen instead of the default 1.12.0. +# Note that che checksum is correct only if the platform is windows. +# If the platform is different, the build will fail. +doxygen_extension.version( + version = "1.10.0", + sha256 = "2135c1d5bdd6e067b3d0c40a4daac5d63d0fee1b3f4d6ef1e4f092db0d632d5b", +) + +use_repo(doxygen_extension, "doxygen") +``` + +```starlark +# MODULE.bazel file + +bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) + +doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") + +doxygen_extension.version( + version = "1.10.0", + sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", + platform = "linux", +) +doxygen_extension.version( + version = "1.12.0", + sha256 = "6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001", + platform = "mac", +) +doxygen_extension.version( + version = "1.11.0", + sha256 = "478fc9897d00ca181835d248a4d3e5c83c26a32d1c7571f4321ddb0f2e97459f", + platform = "windows", +) + +use_repo(doxygen_extension, "doxygen") +``` + +```bzl +# MODULE.bazel file + +bazel_dep(name = "rules_doxygen", version = "...", dev_dependency = True) + +doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension") + +# Download doxygen version 1.10.0 on linux +doxygen_extension.version( + version = "1.10.0", + sha256 = "dcfc9aa4cc05aef1f0407817612ad9e9201d9bf2ce67cecf95a024bba7d39747", + platform = "linux", +) +# Use the local doxygen installation on mac +doxygen_extension.version( + version = "0.0.0", + platform = "mac", +) +# Since no configuration has been provided, windows will fallback to the default version use_repo(doxygen_extension, "doxygen") ```