Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,9 @@ label_flag(
build_setting_default = ":.clang-tidy",
visibility = ["//visibility:public"],
)

# Doxygen configuration file
exports_files(
["doxyfile"],
visibility = ["//build/doxygen:__pkg__"],
)
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ archive_override(
)

include("//build/deps:deps.MODULE.bazel")
include("//build/deps:doxygen.MODULE.bazel")
include("//build/deps:nodejs.MODULE.bazel")
include("//build/deps:python.MODULE.bazel")
include("//build/deps:v8.MODULE.bazel")
Expand Down
22 changes: 22 additions & 0 deletions build/deps/doxygen.MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Doxygen dependency configuration.

This module builds doxygen from source with libclang support, enabling
clang-assisted parsing of C++ code for accurate documentation generation.
"""

doxygen_repository = use_repo_rule("//build/doxygen:doxygen.bzl", "doxygen_repository")

DOXYGEN_VERSION = "1.13.2"

doxygen_repository(
name = "doxygen",
sha256 = "4c9d9c8e95c2af4163ee92bcb0f3af03b2a4089402a353e4715771e8d3701c48",
strip_prefix = "doxygen-Release_{version}".format(
version = DOXYGEN_VERSION.replace(".", "_"),
),
urls = [
"https://github.com/doxygen/doxygen/archive/refs/tags/Release_{version}.tar.gz".format(
version = DOXYGEN_VERSION.replace(".", "_"),
),
],
)
8 changes: 8 additions & 0 deletions build/doxygen/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Build rules for generating doxygen documentation."""

# Re-export the doxygen binary from the external repository
alias(
name = "doxygen",
actual = "@doxygen//:doxygen",
visibility = ["//visibility:public"],
)
109 changes: 109 additions & 0 deletions build/doxygen/doxygen.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""Repository rule for building doxygen from source with libclang support.

This rule downloads and builds doxygen from source using CMake, linking against
the system LLVM/clang installation to enable clang-assisted parsing of C++ code.
"""

def _doxygen_repository_impl(ctx):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wot in tarnation... is there really no easier way to build Doxygen from Bazel?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea. I didn't try lol. I really dislike dealing with build tooling so went with the easiest thing that could possibly work

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's wait to see if Felix agrees, but I'd suggest asking Claude to use rules_doxygen. If it works, there'll be a lot less code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... if we're going for the easiest thing then doing bazel_dep(name = "rules_doxygen", version = "2.6.1") and following the Use instructions is a lot easier here than this approach. Sometimes we don't need to reinvent the wheel, even if we have automated the reinventing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another vote for rules_doxygen then

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had tried that approach initially but kept running into issues with the clang support... building the doxygen here was the only way I was able to get it to work reasonably with a couple of the other updates.

"""Builds doxygen from source with libclang support."""

# Download doxygen source
ctx.download_and_extract(
url = ctx.attr.urls,
sha256 = ctx.attr.sha256,
stripPrefix = ctx.attr.strip_prefix,
)

# Create the build script
build_script = """#!/bin/bash
set -euo pipefail

cd "{src_dir}"
mkdir -p build
cd build

# Find LLVM installation
LLVM_DIR=""
for v in 21 20 19 18; do
if [ -d "/usr/lib/llvm-$v" ]; then
LLVM_DIR="/usr/lib/llvm-$v"
break
fi
done

if [ -z "$LLVM_DIR" ]; then
echo "ERROR: No LLVM installation found" >&2
exit 1
fi

echo "Using LLVM from: $LLVM_DIR"

# Configure with CMake
cmake .. \\
-DCMAKE_BUILD_TYPE=Release \\
-DCMAKE_C_COMPILER=clang \\
-DCMAKE_CXX_COMPILER=clang++ \\
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" \\
-DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=lld" \\
-Duse_libclang=ON \\
-Duse_libc++=OFF \\
-DLLVM_DIR="$LLVM_DIR/lib/cmake/llvm" \\
-DClang_DIR="$LLVM_DIR/lib/cmake/clang" \\
-DCMAKE_INSTALL_PREFIX="{install_dir}"

# Build
make -j$(nproc)
make install
""".format(
src_dir = ctx.path("."),
install_dir = ctx.path("install"),
)

ctx.file("build_doxygen.sh", build_script, executable = True)

# Execute the build
result = ctx.execute(
["bash", "build_doxygen.sh"],
timeout = 1800, # 30 minutes
quiet = False,
)

if result.return_code != 0:
fail("Failed to build doxygen:\nstdout:\n{}\nstderr:\n{}".format(
result.stdout,
result.stderr,
))

# Create BUILD file exposing the doxygen binary
ctx.file("BUILD.bazel", """
package(default_visibility = ["//visibility:public"])

filegroup(
name = "doxygen_bin",
srcs = ["install/bin/doxygen"],
)

filegroup(
name = "doxygen",
srcs = ["install/bin/doxygen"],
)
""")

doxygen_repository = repository_rule(
implementation = _doxygen_repository_impl,
attrs = {
"urls": attr.string_list(
mandatory = True,
doc = "URLs to download doxygen source archive",
),
"sha256": attr.string(
mandatory = True,
doc = "SHA256 checksum of the archive",
),
"strip_prefix": attr.string(
mandatory = True,
doc = "Prefix to strip from the archive",
),
},
doc = "Downloads and builds doxygen from source with libclang support",
)
84 changes: 84 additions & 0 deletions build/doxygen/doxygen_docs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""Rules for generating doxygen documentation."""

def _doxygen_docs_impl(ctx):
"""Generates doxygen documentation."""

# Create output directory
output_dir = ctx.actions.declare_directory(ctx.attr.name + "_html")

# Get the doxygen binary
doxygen_files = ctx.attr.doxygen[DefaultInfo].files.to_list()
if not doxygen_files:
fail("No doxygen binary found")
doxygen_bin = doxygen_files[0]

# Create a script to run doxygen
script = ctx.actions.declare_file(ctx.attr.name + "_run.sh")

script_content = """#!/bin/bash
set -e

DOXYGEN="{doxygen}"
DOXYFILE="{doxyfile}"
OUTPUT_DIR="{output_dir}"
WORKSPACE="{workspace}"

# Create output directory
mkdir -p "$OUTPUT_DIR"

# Run doxygen from workspace root
cd "$WORKSPACE"
"$DOXYGEN" "$DOXYFILE"

# Move output to bazel output location
if [ -d "docs/api/html" ]; then
cp -r docs/api/html/* "$OUTPUT_DIR/"
fi
""".format(
doxygen = doxygen_bin.path,
doxyfile = ctx.file.doxyfile.path,
output_dir = output_dir.path,
workspace = ctx.file.doxyfile.dirname,
)

ctx.actions.write(
output = script,
content = script_content,
is_executable = True,
)

# Collect all source files
srcs = []
for src in ctx.attr.srcs:
srcs.extend(src[DefaultInfo].files.to_list())

ctx.actions.run(
executable = script,
inputs = [ctx.file.doxyfile, doxygen_bin] + srcs,
outputs = [output_dir],
mnemonic = "Doxygen",
progress_message = "Generating doxygen documentation",
use_default_shell_env = True,
)

return [DefaultInfo(files = depset([output_dir]))]

doxygen_docs = rule(
implementation = _doxygen_docs_impl,
attrs = {
"doxyfile": attr.label(
mandatory = True,
allow_single_file = True,
doc = "The Doxyfile configuration",
),
"srcs": attr.label_list(
allow_files = True,
doc = "Source files to document",
),
"doxygen": attr.label(
default = "//build/doxygen",
doc = "The doxygen binary",
),
},
doc = "Generates doxygen documentation from source files",
)
Loading
Loading