@@ -2381,22 +2381,28 @@ build_lance_c() {
23812381
23822382 local cargo_bin=" ${LANCE_C_CARGO:- ${CARGO:- cargo} } "
23832383 if ! command -v " ${cargo_bin} " > /dev/null 2>&1 ; then
2384- echo " cargo is required to build lance-c. Install Rust 1.91 .0 or set LANCE_C_CARGO."
2384+ echo " cargo is required to build lance-c. Install Rust 1.94 .0 or set LANCE_C_CARGO."
23852385 exit 1
23862386 fi
23872387 if [[ ! -x " ${TP_INSTALL_DIR} /bin/protoc" ]]; then
23882388 echo " protoc is required to build lance-c. Build protobuf first."
23892389 exit 1
23902390 fi
23912391
2392- local required_rust_version=" 1.91 .0"
2392+ local required_rust_version=" 1.94 .0"
23932393 local cargo_env=(
23942394 " CARGO_BUILD_JOBS=${PARALLEL} "
23952395 " CARGO_TARGET_DIR=${PWD} /${BUILD_DIR} "
23962396 " PROTOC=${TP_INSTALL_DIR} /bin/protoc"
23972397 )
23982398 if command -v rustup > /dev/null 2>&1 && [[ -z " ${RUSTUP_TOOLCHAIN} " ]]; then
2399- if ! rustup toolchain list | grep -Eq ' ^1\.91\.0([[:space:]-]|$)' ; then
2399+ # The presence check must look for the toolchain the minimum actually
2400+ # requires, not a literal: with only an older toolchain installed the
2401+ # stale check would skip the install below and then force
2402+ # RUSTUP_TOOLCHAIN to a version rustup cannot dispatch, failing the
2403+ # build before any archive is produced.
2404+ local required_rust_regex=" ${required_rust_version// ./ \\ .} "
2405+ if ! rustup toolchain list | grep -Eq " ^${required_rust_regex} ([[:space:]-]|$)" ; then
24002406 rustup toolchain install " ${required_rust_version} " --profile minimal
24012407 fi
24022408 cargo_env+=(" RUSTUP_TOOLCHAIN=${required_rust_version} " )
@@ -2407,7 +2413,7 @@ build_lance_c() {
24072413 echo " failed to get cargo version for lance-c. Install Rust ${required_rust_version} or set LANCE_C_CARGO/RUSTUP_TOOLCHAIN."
24082414 exit 1
24092415 fi
2410- # Rust 1.91 .0 is the minimum supported version. Allow newer toolchains when
2416+ # Rust 1.94 .0 is the minimum supported version. Allow newer toolchains when
24112417 # callers explicitly select one or rustup is unavailable on the system.
24122418 if ! awk -v required=" ${required_rust_version} " -v actual=" ${cargo_version} " ' BEGIN {
24132419 split(required, r, ".");
@@ -2447,6 +2453,131 @@ build_lance_c() {
24472453 fi
24482454}
24492455
2456+ build_paimon_rust () {
2457+ check_if_source_exist " ${PAIMON_RUST_SOURCE} "
2458+ cd " ${TP_SOURCE_DIR} /${PAIMON_RUST_SOURCE} "
2459+
2460+ rm -rf " ${BUILD_DIR} "
2461+ mkdir -p " ${BUILD_DIR} "
2462+
2463+ local cargo_bin=" ${PAIMON_RUST_CARGO:- ${CARGO:- cargo} } "
2464+ if ! command -v " ${cargo_bin} " > /dev/null 2>&1 ; then
2465+ echo " cargo is required to build paimon-rust. Install Rust 1.94.0 or set PAIMON_RUST_CARGO."
2466+ exit 1
2467+ fi
2468+
2469+ local required_rust_version=" 1.94.0"
2470+ local cargo_env=(
2471+ " CARGO_BUILD_JOBS=${PARALLEL} "
2472+ " CARGO_TARGET_DIR=${PWD} /${BUILD_DIR} "
2473+ )
2474+ if command -v rustup > /dev/null 2>&1 && [[ -z " ${RUSTUP_TOOLCHAIN} " ]]; then
2475+ # The presence check must look for the toolchain the minimum actually
2476+ # requires, not a literal: with only an older toolchain installed the
2477+ # stale check would skip the install below and then force
2478+ # RUSTUP_TOOLCHAIN to a version rustup cannot dispatch, failing the
2479+ # build before any archive is produced.
2480+ local required_rust_regex=" ${required_rust_version// ./ \\ .} "
2481+ if ! rustup toolchain list | grep -Eq " ^${required_rust_regex} ([[:space:]-]|$)" ; then
2482+ rustup toolchain install " ${required_rust_version} " --profile minimal
2483+ fi
2484+ cargo_env+=(" RUSTUP_TOOLCHAIN=${required_rust_version} " )
2485+ fi
2486+
2487+ local cargo_version
2488+ if ! cargo_version=" $( env " ${cargo_env[@]} " " ${cargo_bin} " --version | awk ' {print $2}' ) " ; then
2489+ echo " failed to get cargo version for paimon-rust. Install Rust ${required_rust_version} or set PAIMON_RUST_CARGO/RUSTUP_TOOLCHAIN."
2490+ exit 1
2491+ fi
2492+ # Rust 1.94.0 is the minimum supported version. Allow newer toolchains when
2493+ # callers explicitly select one or rustup is unavailable on the system.
2494+ # NOTE: paimon_c and lance_c are both Rust staticlibs linked into the same
2495+ # BE binary; they must be built with the SAME rustc toolchain so the linker
2496+ # resolves both crates' std references against a single std copy. Mixing
2497+ # toolchains makes the precompiled std hashes differ and the linker pulls
2498+ # both std copies in, colliding on the unmangled `rust_eh_personality`
2499+ # (duplicate symbol). Rebuild both lance_c and paimon_rust whenever the
2500+ # toolchain changes, using the same RUSTUP_TOOLCHAIN for both builds.
2501+ if ! awk -v required=" ${required_rust_version} " -v actual=" ${cargo_version} " ' BEGIN {
2502+ split(required, r, ".");
2503+ split(actual, a, ".");
2504+ for (i = 1; i <= 3; i++) {
2505+ if ((a[i] + 0) > (r[i] + 0)) {
2506+ exit 0;
2507+ }
2508+ if ((a[i] + 0) < (r[i] + 0)) {
2509+ exit 1;
2510+ }
2511+ }
2512+ exit 0;
2513+ }' ; then
2514+ echo " paimon-rust requires Rust/Cargo ${required_rust_version} or newer, but found ${cargo_version} ."
2515+ echo " Install Rust ${required_rust_version} or set PAIMON_RUST_CARGO/RUSTUP_TOOLCHAIN."
2516+ exit 1
2517+ fi
2518+
2519+ if [[ " ${KERNEL} " != ' Darwin' ]]; then
2520+ cargo_env+=(" CFLAGS=${CFLAGS:- } -std=gnu17" )
2521+ fi
2522+
2523+ local cargo_args=(build --release --locked -p paimon-c --features paimon/storage-hdfs)
2524+ if [[ " $( echo " ${PAIMON_RUST_CARGO_OFFLINE} " | tr ' [:lower:]' ' [:upper:]' ) " == " ON" ]]; then
2525+ cargo_args+=(--offline)
2526+ fi
2527+ env " ${cargo_env[@]} " " ${cargo_bin} " " ${cargo_args[@]} "
2528+
2529+ # Generate the C header from the Rust extern "C" surface via cbindgen.
2530+ # cbindgen is a pinned, Doris-controlled input: an unpinned "current"
2531+ # release would regenerate paimon.h differently between builds. The
2532+ # pinned version installs under a Doris-controlled --root and its
2533+ # resolved absolute path is invoked directly (a custom CARGO_HOME does
2534+ # not necessarily put cargo-installed binaries on PATH). Offline builds
2535+ # pass --offline to the install command, exactly like the fetch/build
2536+ # handling above — cargo fails on a missing local crate cache instead
2537+ # of reaching for the network.
2538+ local cbindgen_version=" 0.29.4"
2539+ local cbindgen_bin=" ${PAIMON_RUST_CBINDGEN:- } "
2540+ if [[ -z " ${cbindgen_bin} " ]]; then
2541+ local cbindgen_root=" ${TP_SOURCE_DIR} /.doris-cbindgen-${cbindgen_version} "
2542+ cbindgen_bin=" ${cbindgen_root} /bin/cbindgen"
2543+ if [[ ! -x " ${cbindgen_bin} " ]]; then
2544+ local cbindgen_install_args=(install cbindgen
2545+ --version " ${cbindgen_version} " --locked --root " ${cbindgen_root} " )
2546+ if [[ " $( echo " ${PAIMON_RUST_CARGO_OFFLINE} " | tr ' [:lower:]' ' [:upper:]' ) " == " ON" ]]; then
2547+ cbindgen_install_args+=(--offline)
2548+ fi
2549+ echo " cbindgen not found; installing pinned ${cbindgen_version} via cargo install ..."
2550+ env " ${cargo_env[@]} " " ${cargo_bin} " " ${cbindgen_install_args[@]} "
2551+ fi
2552+ elif [[ ! -x " ${cbindgen_bin} " ]]; then
2553+ echo " PAIMON_RUST_CBINDGEN=${cbindgen_bin} is not an executable file."
2554+ exit 1
2555+ fi
2556+ # Write a temporary cbindgen.toml so the generated header carries our
2557+ # include-guard / cpp-compat settings without touching the upstream tree.
2558+ local cbindgen_toml=" ${BUILD_DIR} /cbindgen.toml"
2559+ mkdir -p " ${BUILD_DIR} "
2560+ cat > " ${cbindgen_toml} " << 'EOF '
2561+ language = "C"
2562+ include_guard = "PAIMON_C_H"
2563+ pragma_once = true
2564+ cpp_compat = true
2565+ EOF
2566+ env " ${cargo_env[@]} " " ${cbindgen_bin} " bindings/c \
2567+ --config " ${cbindgen_toml} " \
2568+ --output " ${BUILD_DIR} /release/paimon.h"
2569+
2570+ mkdir -p " ${TP_INSTALL_DIR} /include" " ${TP_INSTALL_DIR} /lib64"
2571+ rm -rf " ${TP_INSTALL_DIR} /include/paimon_rust"
2572+ mkdir -p " ${TP_INSTALL_DIR} /include/paimon_rust"
2573+ cp -v " ${BUILD_DIR} /release/paimon.h" " ${TP_INSTALL_DIR} /include/paimon_rust/"
2574+ cp -v " ${BUILD_DIR} /release/libpaimon_c.a" " ${TP_INSTALL_DIR} /lib64/"
2575+
2576+ if [[ " ${STRIP_TP_LIB} " = " ON" && " ${KERNEL} " != ' Darwin' ]]; then
2577+ strip --strip-debug --strip-unneeded " ${TP_INSTALL_DIR} /lib64/libpaimon_c.a"
2578+ fi
2579+ }
2580+
24502581if [[ " ${# packages[@]} " -eq 0 ]]; then
24512582 packages=(
24522583 jindofs
@@ -2526,6 +2657,7 @@ if [[ "${#packages[@]}" -eq 0 ]]; then
25262657 icu
25272658 mecab_ipadic
25282659 pugixml
2660+ paimon_rust
25292661 )
25302662 if [[ " $( uname -s) " == ' Darwin' ]]; then
25312663 read -r -a packages <<< " binutils gettext ${packages[*]}"
@@ -2636,6 +2768,7 @@ cleanup_package_source() {
26362768 juicefs) src_var=" JUICEFS_SOURCE" ;;
26372769 pugixml) src_var=" PUGIXML_SOURCE" ;;
26382770 lance_c) src_var=" LANCE_C_SOURCE" ;;
2771+ paimon_rust) src_var=" PAIMON_RUST_SOURCE" ;;
26392772 aws_sdk) src_var=" AWS_SDK_SOURCE" ;;
26402773 lzma) src_var=" LZMA_SOURCE" ;;
26412774 xml2) src_var=" XML2_SOURCE" ;;
0 commit comments