From 17a5688cb522697612da63a9de93cc834b1746bf Mon Sep 17 00:00:00 2001 From: ColinLee Date: Mon, 24 Aug 2026 12:24:22 +0800 Subject: [PATCH] fix: provision C++ clang-format for spotless --- CLAUDE.md | 12 +++++- cpp/CLAUDE.md | 3 ++ cpp/pom.xml | 28 ++++++++++++-- cpp/tools/clang-format | 86 ++++++++++++++++++++++++++++++++++++++++++ python/CLAUDE.md | 2 +- 5 files changed, 125 insertions(+), 6 deletions(-) create mode 100755 cpp/tools/clang-format diff --git a/CLAUDE.md b/CLAUDE.md index d2a394c1a..440534046 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -54,10 +54,18 @@ The root `pom.xml` orchestrates all three via Maven profiles: ## Code Formatting ```bash -./mvnw spotless:apply # Format all languages (Java: Google Java Format, C++: clang-format, Python: Black) -./mvnw spotless:check # Check formatting without modifying +./mvnw spotless:apply -P with-java,with-cpp # Format Java and C++ +./mvnw spotless:check -P with-java,with-cpp # Check Java and C++ formatting +./mvnw initialize spotless:apply -P with-java,with-python # Format Java, C++, and Python +./mvnw process-sources -P with-java,with-python # Check Java, C++, and Python formatting ``` +Java uses Google Java Format. C++ uses clang-format 17.0.6 via Spotless; on +supported Linux and Apple Silicon macOS hosts, Maven downloads the LLVM release +archive into `cpp/target/clang-format` before running Spotless. +Python uses Black 26.3.1 from the virtual environment created by the +`with-python` profile; that profile also includes the C++ module. + ## Internationalization Java logs and exception messages use a runtime `ResourceBundle` approach so the same JAR can emit English or Simplified Chinese based on a JVM startup property. See `java/CLAUDE.md` for the convention. Switch language with `-Dtsfile.locale=zh`. diff --git a/cpp/CLAUDE.md b/cpp/CLAUDE.md index 02dc4186e..447e4fc10 100644 --- a/cpp/CLAUDE.md +++ b/cpp/CLAUDE.md @@ -101,6 +101,9 @@ cpp/src/ - **Formatter**: clang-format (Google style), configured in `.clang-format` - After modifying C++ code, run from the repo root to format: `./mvnw spotless:apply -P with-cpp` +- Spotless uses clang-format 17.0.6. On supported Linux and Apple Silicon macOS + hosts, Maven downloads the LLVM release archive into `cpp/target/clang-format` + and runs that private binary; other hosts fall back to `clang-format` on `PATH`. ## Testing diff --git a/cpp/pom.xml b/cpp/pom.xml index c0fbbc2c5..b3ae81346 100644 --- a/cpp/pom.xml +++ b/cpp/pom.xml @@ -52,6 +52,7 @@ OFF ON ON + clang-format ${project.basedir} @@ -361,11 +362,9 @@ test/**/*.cc - - + ${clang.format.executable} ${clang.format.version} - UNIX @@ -384,5 +383,28 @@ + + .clang-format-linux + + + unix + Linux + + + + ${project.basedir}/tools/clang-format + + + + .clang-format-mac + + + mac + + + + ${project.basedir}/tools/clang-format + + diff --git a/cpp/tools/clang-format b/cpp/tools/clang-format new file mode 100755 index 000000000..339d127b7 --- /dev/null +++ b/cpp/tools/clang-format @@ -0,0 +1,86 @@ +#!/usr/bin/env sh +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +set -eu + +VERSION="${CLANG_FORMAT_VERSION:-17.0.6}" +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +CPP_DIR="$(CDPATH= cd -- "${SCRIPT_DIR}/.." && pwd)" +TOOL_DIR="${CPP_DIR}/target/clang-format" +BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${VERSION}" + +check_version() { + exe="$1" + actual="$("${exe}" --version 2>/dev/null || true)" + case "${actual}" in + *"${VERSION}"*) ;; + *) + echo "Expected clang-format ${VERSION}, but found: ${actual:-not executable}" >&2 + exit 1 + ;; + esac +} + +download() { + url="$1" + output="$2" + if command -v curl >/dev/null 2>&1; then + curl -fL "${url}" -o "${output}" + elif command -v wget >/dev/null 2>&1; then + wget -O "${output}" "${url}" + else + echo "Neither curl nor wget is available to download clang-format ${VERSION}." >&2 + exit 1 + fi +} + +asset="" +case "$(uname -s):$(uname -m)" in + Linux:x86_64 | Linux:amd64) + asset="clang+llvm-${VERSION}-x86_64-linux-gnu-ubuntu-22.04" + ;; + Linux:aarch64 | Linux:arm64) + asset="clang+llvm-${VERSION}-aarch64-linux-gnu" + ;; + Darwin:arm64) + asset="clang+llvm-${VERSION}-arm64-apple-darwin22.0" + ;; +esac + +if [ -n "${asset}" ]; then + exe="${TOOL_DIR}/${asset}/bin/clang-format" + archive="${TOOL_DIR}/${asset}.tar.xz" + if [ ! -x "${exe}" ]; then + mkdir -p "${TOOL_DIR}" + if [ ! -f "${archive}" ]; then + download "${BASE_URL}/${asset}.tar.xz" "${archive}" + fi + tar -xJf "${archive}" -C "${TOOL_DIR}" + fi +else + exe="$(command -v clang-format || true)" + if [ -z "${exe}" ]; then + echo "No bundled clang-format ${VERSION} is available for $(uname -s) $(uname -m), and clang-format is not on PATH." >&2 + exit 1 + fi +fi + +check_version "${exe}" +exec "${exe}" "$@" diff --git a/python/CLAUDE.md b/python/CLAUDE.md index 2fc0ca88e..979125df9 100644 --- a/python/CLAUDE.md +++ b/python/CLAUDE.md @@ -49,7 +49,7 @@ pytest tests/ pytest tests/test_write_and_read.py -k "test_name" # Format code -cd ../ && ./mvnw spotless:apply # Uses Black 26.3.1 +cd ../ && ./mvnw initialize spotless:apply -P with-python # Uses Black 26.3.1 ``` ## Source Structure