[verified] feat: pin native protobuf and gRPC generation
This commit is contained in:
@@ -1,18 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a protobuf C++ toolchain for the native Shard protocol.
|
||||
#
|
||||
# The Python side needs nothing beyond `pip install grpcio-tools` — it bundles
|
||||
# protoc. The C++ side needs libprotobuf headers and a protoc binary, and a
|
||||
# machine that has neither (no protobuf-devel, no cmake, no system protoc) can
|
||||
# still get a working one from source with this script. It is the exact recipe
|
||||
# DGR-002 used to build and run the C++ conformance test.
|
||||
#
|
||||
# gRPC C++ is deliberately NOT built here. The conformance test only needs
|
||||
# message types, so verifying the schema does not require the whole gRPC stack.
|
||||
# The worker (DGR-008) will need gRPC C++ and should extend this script then.
|
||||
# The Python side uses the exact grpcio-tools pin declared below. The C++ side
|
||||
# builds exact Protobuf, Abseil, and gRPC source revisions so `protoc`,
|
||||
# `grpc_cpp_plugin`, headers, and libraries all come from one ignored prefix.
|
||||
# No system Protobuf/gRPC installation is accepted by the documented build.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/bootstrap_native_toolchain.sh [install-prefix]
|
||||
# bash scripts/bootstrap_native_toolchain.sh [install-prefix]
|
||||
#
|
||||
# Then:
|
||||
# cmake -S packages/node/native -B build/native -DCMAKE_PREFIX_PATH=<prefix>
|
||||
@@ -21,7 +16,17 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PREFIX="${1:-${PWD}/build/native-toolchain}"
|
||||
resolve_prefix() {
|
||||
local candidate="${1:-${PWD}/build/native-toolchain}"
|
||||
realpath -m -- "${candidate}"
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--print-prefix" ]]; then
|
||||
resolve_prefix "${2:-}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PREFIX="$(resolve_prefix "${1:-}")"
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "${WORK}"' EXIT
|
||||
|
||||
@@ -29,11 +34,15 @@ trap 'rm -rf "${WORK}"' EXIT
|
||||
# that stub is allowed to use, so these are exact, not floating.
|
||||
PROTOBUF_VERSION="33.1"
|
||||
ABSEIL_VERSION="20250814.1"
|
||||
GRPC_VERSION="1.82.1"
|
||||
GRPC_COMMIT="acccf84c0df20487d64101f528e5d426541ca4e5"
|
||||
|
||||
command -v cmake >/dev/null || {
|
||||
echo "cmake is required (pip install cmake==4.4.0)" >&2
|
||||
exit 1
|
||||
}
|
||||
for tool in cmake curl git realpath sha256sum tar; do
|
||||
command -v "${tool}" >/dev/null || {
|
||||
echo "${tool} is required" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
echo "--- fetching protobuf ${PROTOBUF_VERSION} and abseil ${ABSEIL_VERSION}"
|
||||
cd "${WORK}"
|
||||
@@ -41,26 +50,77 @@ curl -sfL -o protobuf.tar.gz \
|
||||
"https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-${PROTOBUF_VERSION}.tar.gz"
|
||||
tar xzf protobuf.tar.gz
|
||||
|
||||
# The protobuf release tarball ships utf8_range but not abseil, and its default
|
||||
# CMake provider expects abseil as a submodule, so vendor it into place.
|
||||
curl -sfL -o abseil.tar.gz \
|
||||
"https://github.com/abseil/abseil-cpp/releases/download/${ABSEIL_VERSION}/abseil-cpp-${ABSEIL_VERSION}.tar.gz"
|
||||
tar xzf abseil.tar.gz
|
||||
rm -rf "protobuf-${PROTOBUF_VERSION}/third_party/abseil-cpp"
|
||||
mv "abseil-cpp-${ABSEIL_VERSION}" "protobuf-${PROTOBUF_VERSION}/third_party/abseil-cpp"
|
||||
|
||||
echo "--- building protobuf into ${PREFIX}"
|
||||
cmake -S "protobuf-${PROTOBUF_VERSION}" -B build \
|
||||
echo "--- building abseil ${ABSEIL_VERSION} into ${PREFIX}"
|
||||
cmake -S "abseil-cpp-${ABSEIL_VERSION}" -B abseil-build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="${PREFIX}" \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-Dprotobuf_ABSL_PROVIDER=module \
|
||||
-Dprotobuf_BUILD_TESTS=OFF \
|
||||
-Dprotobuf_BUILD_SHARED_LIBS=OFF \
|
||||
-DABSL_ENABLE_INSTALL=ON \
|
||||
-DABSL_BUILD_TESTING=OFF \
|
||||
-DABSL_PROPAGATE_CXX_STD=ON
|
||||
cmake --build build -j"$(nproc)"
|
||||
cmake --install build
|
||||
cmake --build abseil-build -j"$(nproc)"
|
||||
cmake --install abseil-build
|
||||
|
||||
echo "--- building protobuf ${PROTOBUF_VERSION} into ${PREFIX}"
|
||||
cmake -S "protobuf-${PROTOBUF_VERSION}" -B protobuf-build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="${PREFIX}" \
|
||||
-DCMAKE_PREFIX_PATH="${PREFIX}" \
|
||||
-Dabsl_DIR="${PREFIX}/lib64/cmake/absl" \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-Dprotobuf_LOCAL_DEPENDENCIES_ONLY=ON \
|
||||
-Dprotobuf_BUILD_TESTS=OFF \
|
||||
-Dprotobuf_BUILD_SHARED_LIBS=OFF
|
||||
cmake --build protobuf-build -j"$(nproc)"
|
||||
cmake --install protobuf-build
|
||||
|
||||
echo "--- fetching gRPC ${GRPC_VERSION} at ${GRPC_COMMIT}"
|
||||
git init -q grpc-source
|
||||
git -C grpc-source remote add origin https://github.com/grpc/grpc.git
|
||||
git -C grpc-source fetch --depth 1 origin "${GRPC_COMMIT}"
|
||||
git -C grpc-source checkout --detach FETCH_HEAD
|
||||
git -C grpc-source submodule update --init --recursive --depth 1
|
||||
[[ "$(git -C grpc-source rev-parse HEAD)" == "${GRPC_COMMIT}" ]] || {
|
||||
echo "gRPC checkout identity mismatch" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "--- building gRPC ${GRPC_VERSION} and grpc_cpp_plugin into ${PREFIX}"
|
||||
cmake -S grpc-source -B grpc-build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="${PREFIX}" \
|
||||
-DCMAKE_PREFIX_PATH="${PREFIX}" \
|
||||
-DProtobuf_DIR="${PREFIX}/lib64/cmake/protobuf" \
|
||||
-Dabsl_DIR="${PREFIX}/lib64/cmake/absl" \
|
||||
-DgRPC_INSTALL=ON \
|
||||
-DgRPC_BUILD_TESTS=OFF \
|
||||
-DgRPC_PROTOBUF_PROVIDER=package \
|
||||
-DgRPC_ABSL_PROVIDER=package \
|
||||
-DgRPC_CARES_PROVIDER=module \
|
||||
-DgRPC_RE2_PROVIDER=module \
|
||||
-DgRPC_SSL_PROVIDER=module \
|
||||
-DgRPC_ZLIB_PROVIDER=module \
|
||||
-DgRPC_BUILD_GRPC_CPP_PLUGIN=ON \
|
||||
-DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF \
|
||||
-DgRPC_BUILD_GRPC_NODE_PLUGIN=OFF \
|
||||
-DgRPC_BUILD_GRPC_OBJECTIVE_C_PLUGIN=OFF \
|
||||
-DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF \
|
||||
-DgRPC_BUILD_GRPC_PYTHON_PLUGIN=OFF \
|
||||
-DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF
|
||||
cmake --build grpc-build -j"$(nproc)"
|
||||
cmake --install grpc-build
|
||||
|
||||
echo "--- done"
|
||||
"${PREFIX}/bin/protoc" --version
|
||||
[[ -x "${PREFIX}/bin/grpc_cpp_plugin" ]] || {
|
||||
echo "grpc_cpp_plugin was not installed" >&2
|
||||
exit 1
|
||||
}
|
||||
printf 'gRPC %s commit %s\n' "${GRPC_VERSION}" "${GRPC_COMMIT}"
|
||||
printf 'grpc_cpp_plugin sha256 '
|
||||
sha256sum "${PREFIX}/bin/grpc_cpp_plugin" | cut -d' ' -f1
|
||||
echo "configure the protocol build with: -DCMAKE_PREFIX_PATH=${PREFIX}"
|
||||
|
||||
@@ -20,6 +20,7 @@ already requires a toolchain and nothing is gained by committing them.
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from importlib import metadata
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -38,15 +39,32 @@ REQUIRED_GRPCIO_TOOLS = "1.82.1"
|
||||
_HEADER = "# Generated by scripts/generate_native_protocol.py. Do not edit.\n"
|
||||
|
||||
|
||||
def _generate(into: pathlib.Path) -> None:
|
||||
"""Run protoc, writing generated modules into `into`."""
|
||||
def _require_grpcio_tools_version() -> None:
|
||||
try:
|
||||
from grpc_tools import protoc
|
||||
except ImportError: # pragma: no cover - exercised only without the toolchain
|
||||
actual = metadata.version("grpcio-tools")
|
||||
except metadata.PackageNotFoundError:
|
||||
sys.exit(
|
||||
"grpc_tools is required to generate stubs:\n"
|
||||
f" pip install grpcio-tools=={REQUIRED_GRPCIO_TOOLS}"
|
||||
)
|
||||
if actual != REQUIRED_GRPCIO_TOOLS:
|
||||
sys.exit(
|
||||
"wrong grpcio-tools version for deterministic generation: "
|
||||
f"found {actual}, require {REQUIRED_GRPCIO_TOOLS}\n"
|
||||
f" pip install --upgrade grpcio-tools=={REQUIRED_GRPCIO_TOOLS}"
|
||||
)
|
||||
|
||||
|
||||
def _generate(into: pathlib.Path) -> None:
|
||||
"""Run the exactly pinned protoc, writing generated modules into `into`."""
|
||||
_require_grpcio_tools_version()
|
||||
try:
|
||||
from grpc_tools import protoc
|
||||
except ImportError: # pragma: no cover - inconsistent/broken installation
|
||||
sys.exit(
|
||||
"grpcio-tools metadata exists but grpc_tools cannot be imported; reinstall it:\n"
|
||||
f" pip install --force-reinstall grpcio-tools=={REQUIRED_GRPCIO_TOOLS}"
|
||||
)
|
||||
|
||||
into.mkdir(parents=True, exist_ok=True)
|
||||
# grpc_tools bundles protoc and the well-known types, so generation needs no
|
||||
|
||||
Reference in New Issue
Block a user