mirror of
https://github.com/hanzoai/datastore.git
synced 2026-10-30 14:48:37 +00:00
Configure now COMPLETES ("Configuring done (19.3s)") and the build died in the
generate step instead, on "No SOURCES given to target" for _zxc, _zxc_*_avx2/512,
_simdutf and libdeflate.
The targets are not empty; the paths were. CMake defines <PROJECT>_SOURCE_DIR,
and CMakeLists.txt:18 declares project(Datastore), so ClickHouse_SOURCE_DIR is
simply an undefined variable that expands to the empty string. Every contrib
wrapper still spelling it that way built its source path as "/contrib/zxc" or
"/contrib/simdutf/src" — rooted at /, not at the source tree — so the globs
matched nothing and add_library was handed an empty list. An undefined variable
is not an error in CMake, which is why this surfaced as a missing-sources
complaint about the target rather than a bad path.
This is the same unfinished rename as the previous commit wearing different
clothes. Swept both spellings across every in-repo cmake file: exactly two tokens,
ClickHouse_SOURCE_DIR and ClickHouse_BINARY_DIR, 23 occurrences in 13 files, all
of them contrib/*-cmake wrappers plus src/CMakeLists.txt. The submodules
themselves are untouched — the wrappers are ours, contrib/<name>-cmake is not a
.gitmodules path.
Renamed rather than aliased. A one-line set(ClickHouse_SOURCE_DIR
${Datastore_SOURCE_DIR}) in the root would also have worked and would cost less
on the next upstream merge, but the tree already carries hundreds of
Datastore_SOURCE_DIR uses in these same directories: the choice to rename was
made when the project was renamed, and these 13 files are the remainder of that
job, not a new decision. Two spellings for one path is the thing that produced
this bug in the first place.
490 lines
25 KiB
CMake
490 lines
25 KiB
CMake
# See https://doc.rust-lang.org/nightly/rustc/platform-support.html
|
|
|
|
macro(set_rust_target)
|
|
if(DEFINED CMAKE_TOOLCHAIN_FILE AND NOT DEFINED Rust_CARGO_TARGET)
|
|
if(CMAKE_TOOLCHAIN_FILE MATCHES "ppc64le")
|
|
set(Rust_CARGO_TARGET "powerpc64le-unknown-linux-gnu" CACHE INTERNAL "Rust config")
|
|
elseif((CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-x86_64") AND (CMAKE_TOOLCHAIN_FILE MATCHES "musl"))
|
|
set(Rust_CARGO_TARGET "x86_64-unknown-linux-musl" CACHE INTERNAL "Rust config")
|
|
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-x86_64")
|
|
set(Rust_CARGO_TARGET "x86_64-unknown-linux-gnu" CACHE INTERNAL "Rust config")
|
|
elseif((CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-aarch64") AND (CMAKE_TOOLCHAIN_FILE MATCHES "musl"))
|
|
set(Rust_CARGO_TARGET "aarch64-unknown-linux-musl" CACHE INTERNAL "Rust config")
|
|
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-aarch64")
|
|
set(Rust_CARGO_TARGET "aarch64-unknown-linux-gnu" CACHE INTERNAL "Rust config")
|
|
elseif((CMAKE_TOOLCHAIN_FILE MATCHES "darwin") AND (CMAKE_TOOLCHAIN_FILE MATCHES "x86_64"))
|
|
set(Rust_CARGO_TARGET "x86_64-apple-darwin" CACHE INTERNAL "Rust config")
|
|
elseif((CMAKE_TOOLCHAIN_FILE MATCHES "darwin") AND (CMAKE_TOOLCHAIN_FILE MATCHES "aarch64"))
|
|
set(Rust_CARGO_TARGET "aarch64-apple-darwin" CACHE INTERNAL "Rust config")
|
|
elseif((CMAKE_TOOLCHAIN_FILE MATCHES "freebsd") AND (CMAKE_TOOLCHAIN_FILE MATCHES "x86_64"))
|
|
set(Rust_CARGO_TARGET "x86_64-unknown-freebsd" CACHE INTERNAL "Rust config")
|
|
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-riscv64")
|
|
set(Rust_CARGO_TARGET "riscv64gc-unknown-linux-gnu" CACHE INTERNAL "Rust config")
|
|
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-loongarch64")
|
|
set(Rust_CARGO_TARGET "loongarch64-unknown-linux-gnu" CACHE INTERNAL "Rust config")
|
|
else()
|
|
message(FATAL_ERROR "Unknown rust target for toolchain ${CMAKE_TOOLCHAIN_FILE}")
|
|
endif()
|
|
message(STATUS "Set Rust target to ${Rust_CARGO_TARGET}")
|
|
endif ()
|
|
|
|
# FindRust.cmake
|
|
set(RUST_MODULE_PATH "${Datastore_SOURCE_DIR}/contrib/corrosion/cmake")
|
|
if (NOT "${RUST_MODULE_PATH}" IN_LIST "${CMAKE_MODULE_PATH}")
|
|
list (APPEND CMAKE_MODULE_PATH "${RUST_MODULE_PATH}")
|
|
endif()
|
|
endmacro()
|
|
|
|
# Keep in sync with toolchain in docker images
|
|
# (must be called before find_package(Rust) and inclusion of Corrosion.cmake)
|
|
set(Rust_TOOLCHAIN "nightly-2026-03-22")
|
|
|
|
macro(find_rust)
|
|
set_rust_target()
|
|
if (NOT DEFINED Rust_FOUND)
|
|
find_package(Rust)
|
|
endif()
|
|
if (NOT Rust_FOUND)
|
|
message(${RECONFIGURE_MESSAGE_LEVEL} "Cannot find ${Rust_TOOLCHAIN} Rust toolchain. You can install it with 'rustup toolchain install ${Rust_TOOLCHAIN}'")
|
|
endif()
|
|
endmacro()
|
|
|
|
if (NOT ENABLE_LIBRARIES)
|
|
set(DEFAULT_ENABLE_RUST FALSE)
|
|
elseif (NOT DEFINED ENABLE_RUST)
|
|
find_rust()
|
|
set(DEFAULT_ENABLE_RUST ${Rust_FOUND})
|
|
else()
|
|
if (ENABLE_RUST)
|
|
# Give a sensible warning if Rust is not available
|
|
find_rust()
|
|
set(DEFAULT_ENABLE_RUST TRUE)
|
|
else()
|
|
set(DEFAULT_ENABLE_RUST FALSE)
|
|
endif()
|
|
endif()
|
|
|
|
option(ENABLE_RUST "Enable rust" ${DEFAULT_ENABLE_RUST})
|
|
if(NOT ENABLE_RUST)
|
|
message(STATUS "Not using Rust")
|
|
return()
|
|
endif()
|
|
|
|
set_rust_target()
|
|
# Define function corrosion_import_crate()
|
|
include ("${Datastore_SOURCE_DIR}/contrib/corrosion/cmake/Corrosion.cmake")
|
|
|
|
set(CXX_INCLUDE_DIR "${Datastore_SOURCE_DIR}/contrib/llvm-project/libcxx/include")
|
|
|
|
# For musl, libc++ headers must come before musl's, but the toolchain puts musl includes
|
|
# into CMAKE_*_FLAGS. Strip them and re-add them after libc++ for CXXFLAGS.
|
|
if (USE_MUSL)
|
|
string(REGEX REPLACE "-isystem [^ ]*musl[^ ]*" "" CMAKE_C_FLAGS_STRIPPED "${CMAKE_C_FLAGS}")
|
|
string(REGEX REPLACE "-isystem [^ ]*musl[^ ]*" "" CMAKE_CXX_FLAGS_STRIPPED "${CMAKE_CXX_FLAGS}")
|
|
|
|
set(MUSL_STUB_INCLUDE_DIR "${Datastore_SOURCE_DIR}/contrib/musl-cmake/include")
|
|
set(MUSL_GENERATED_DIR "${Datastore_BINARY_DIR}/contrib/musl-cmake/include")
|
|
set(MUSL_INCLUDE_DIR "${Datastore_SOURCE_DIR}/contrib/musl/include")
|
|
set(MUSL_ARCH_DIR "${Datastore_SOURCE_DIR}/contrib/musl/arch/${MUSL_ARCH}")
|
|
set(MUSL_GENERIC_DIR "${Datastore_SOURCE_DIR}/contrib/musl/arch/generic")
|
|
set(MUSL_KERNEL_HEADERS_DIR "${Datastore_BINARY_DIR}/contrib/musl-cmake/kernel-headers")
|
|
|
|
# The regex above strips every "-isystem ...musl..." entry, so we must reconstruct the full
|
|
# musl header surface that cmake/linux/toolchain-*-musl.cmake puts into CMAKE_*_FLAGS via
|
|
# MUSL_INCLUDE_FLAGS. Keep this in sync with that toolchain: the stub headers (e.g.
|
|
# execinfo.h) and the kernel-headers directory are part of the set and must not be dropped,
|
|
# otherwise Cargo cc/cxx builds compile against a narrower header surface than the rest of
|
|
# the tree. The order matches the toolchain's -isystem order.
|
|
set(MUSL_C_INCLUDES "-isystem ${MUSL_STUB_INCLUDE_DIR} -isystem ${MUSL_GENERATED_DIR} -isystem ${MUSL_INCLUDE_DIR} -isystem ${MUSL_ARCH_DIR} -isystem ${MUSL_GENERIC_DIR} -isystem ${MUSL_KERNEL_HEADERS_DIR}")
|
|
|
|
set(MUSL_CXX_INCLUDES "-isystem ${CXX_INCLUDE_DIR} -nostdinc++ ${MUSL_C_INCLUDES} -D_LIBCPP_HAS_MUSL_LIBC=1")
|
|
|
|
# Mirror the per-build-type selection of the non-musl branch below so that Release and
|
|
# MinSizeRel musl artifacts do not silently compile Cargo cc/cxx shims with RelWithDebInfo
|
|
# optimisation/debug flags.
|
|
if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG")
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS_STRIPPED} ${CMAKE_C_FLAGS_DEBUG} ${MUSL_C_INCLUDES}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS_STRIPPED} ${CMAKE_CXX_FLAGS_DEBUG} ${MUSL_CXX_INCLUDES}")
|
|
elseif (CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE")
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS_STRIPPED} ${CMAKE_C_FLAGS_RELEASE} ${MUSL_C_INCLUDES}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS_STRIPPED} ${CMAKE_CXX_FLAGS_RELEASE} ${MUSL_CXX_INCLUDES}")
|
|
elseif (CMAKE_BUILD_TYPE_UC STREQUAL "MINSIZEREL")
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS_STRIPPED} ${CMAKE_C_FLAGS_MINSIZEREL} ${MUSL_C_INCLUDES}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS_STRIPPED} ${CMAKE_CXX_FLAGS_MINSIZEREL} ${MUSL_CXX_INCLUDES}")
|
|
else ()
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS_STRIPPED} ${CMAKE_C_FLAGS_RELWITHDEBINFO} ${MUSL_C_INCLUDES}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS_STRIPPED} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${MUSL_CXX_INCLUDES}")
|
|
endif()
|
|
else()
|
|
if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG")
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_DEBUG}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG} -isystem ${CXX_INCLUDE_DIR} -nostdinc++")
|
|
elseif (CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE")
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_RELEASE}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} -isystem ${CXX_INCLUDE_DIR} -nostdinc++")
|
|
elseif (CMAKE_BUILD_TYPE_UC STREQUAL "MINSIZEREL")
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_MINSIZEREL}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_MINSIZEREL} -isystem ${CXX_INCLUDE_DIR} -nostdinc++")
|
|
else ()
|
|
set(RUST_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
|
set(RUST_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -isystem ${CXX_INCLUDE_DIR} -nostdinc++")
|
|
endif()
|
|
endif()
|
|
|
|
if (CMAKE_OSX_SYSROOT)
|
|
set(RUST_CXXFLAGS "${RUST_CXXFLAGS} -isysroot ${CMAKE_OSX_SYSROOT}")
|
|
set(RUST_CFLAGS "${RUST_CFLAGS} -isysroot ${CMAKE_OSX_SYSROOT}")
|
|
elseif(CMAKE_SYSROOT)
|
|
set(RUST_CXXFLAGS "${RUST_CXXFLAGS} --sysroot ${CMAKE_SYSROOT}")
|
|
set(RUST_CFLAGS "${RUST_CFLAGS} --sysroot ${CMAKE_SYSROOT}")
|
|
endif()
|
|
|
|
if (CMAKE_OSX_DEPLOYMENT_TARGET)
|
|
set(RUST_CXXFLAGS "${RUST_CXXFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
|
set(RUST_CFLAGS "${RUST_CFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
|
endif()
|
|
|
|
get_target_property(CXX_PUBLIC_DEFS cxx INTERFACE_COMPILE_DEFINITIONS)
|
|
if (CXX_PUBLIC_DEFS)
|
|
list(TRANSFORM CXX_PUBLIC_DEFS PREPEND "-D")
|
|
list(JOIN CXX_PUBLIC_DEFS " " CXX_PUBLIC_DEFS)
|
|
set(RUST_CXXFLAGS "${RUST_CXXFLAGS} ${CXX_PUBLIC_DEFS}")
|
|
endif()
|
|
|
|
if(CCACHE_EXECUTABLE MATCHES "/chcache$" OR CCACHE_EXECUTABLE MATCHES "/sccache$")
|
|
message(STATUS "Using RUSTC_WRAPPER: ${CCACHE_EXECUTABLE}")
|
|
set(RUSTCWRAPPER "${CCACHE_EXECUTABLE}")
|
|
else()
|
|
set(RUSTCWRAPPER "")
|
|
endif()
|
|
|
|
# Note that RUSTFLAGS_CPU is defined in cpu_features.cmake
|
|
set(RUSTFLAGS ${RUSTFLAGS_CPU})
|
|
|
|
# Otherwise /usr/bin/ld will not be able to link our openssl build (built with lld) to openssl rust wrapper (built ld)
|
|
if (LINKER_NAME MATCHES "lld")
|
|
list(APPEND RUSTFLAGS "-C" "link-arg=-fuse-ld=lld")
|
|
endif()
|
|
|
|
if (CMAKE_OSX_SYSROOT)
|
|
list(APPEND RUSTFLAGS "-C" "link-arg=-isysroot")
|
|
list(APPEND RUSTFLAGS "-C" "link-arg=${CMAKE_OSX_SYSROOT}")
|
|
elseif(CMAKE_SYSROOT)
|
|
list(APPEND RUSTFLAGS "-C" "link-arg=--sysroot")
|
|
list(APPEND RUSTFLAGS "-C" "link-arg=${CMAKE_SYSROOT}")
|
|
endif()
|
|
|
|
if (TOOLCHAIN_PATH)
|
|
list(APPEND RUSTFLAGS "-C" "link-arg=--gcc-toolchain=${TOOLCHAIN_PATH}")
|
|
endif()
|
|
|
|
set(RUST_CARGO_BUILD_STD "")
|
|
# For more info: https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#memorysanitizer
|
|
if (SANITIZE STREQUAL "memory")
|
|
set(RUST_CARGO_BUILD_STD "-Zbuild-std=std,panic_abort,core,alloc")
|
|
list(APPEND RUSTFLAGS "-Zsanitizer=memory" "-Zsanitizer-memory-track-origins")
|
|
elseif (SANITIZE STREQUAL "thread")
|
|
set(RUST_CARGO_BUILD_STD "-Zbuild-std=std,panic_abort,core,alloc")
|
|
list(APPEND RUSTFLAGS "-Zsanitizer=thread")
|
|
elseif (SANITIZE STREQUAL "address" OR SANITIZE STREQUAL "address,undefined")
|
|
# Rust has no UBSan, so the combined ASan+UBSan build applies only ASan. Besides the
|
|
# instrumentation itself, `-Zsanitizer=address` arms wasmtime's `cfg(asan)` guard, preventing
|
|
# a stray munmap of live memory at thread exit: https://github.com/bytecodealliance/wasmtime/issues/13857
|
|
set(RUST_CARGO_BUILD_STD "-Zbuild-std=std,panic_abort,core,alloc")
|
|
list(APPEND RUSTFLAGS "-Zsanitizer=address")
|
|
endif()
|
|
|
|
# Force `rustix` to use its libc backend under sanitizers.
|
|
# On Linux `rustix` defaults to the `linux_raw` backend, which issues `mmap`, `munmap` and
|
|
# other syscalls directly via the `syscall` instruction, bypassing libc. The sanitizers
|
|
# intercept these operations at the libc symbol boundary, so with the raw backend they never
|
|
# observe `rustix`'s memory mappings. For ThreadSanitizer this means the shadow memory of a
|
|
# region is not reset when `rustix` (used by `wasmtime` for compiled-code `mmap` allocations)
|
|
# maps or unmaps it, so a freshly mapped region inherits the stale shadow of whatever
|
|
# previously occupied that virtual address, producing false-positive data races. The same gap
|
|
# affects MemorySanitizer (freshly mapped memory looks uninitialized) and AddressSanitizer.
|
|
# `--cfg=rustix_use_libc` is the mechanism `rustix` provides for transitive consumers to select
|
|
# the libc backend; it also activates the `libc` dependency (already pinned in `Cargo.lock`).
|
|
if (NOT SANITIZE STREQUAL "")
|
|
list(APPEND RUSTFLAGS "--cfg" "rustix_use_libc")
|
|
endif()
|
|
|
|
# Set metadata flag to force different hashes for different sanitizers
|
|
if (SANITIZE STREQUAL "")
|
|
list(APPEND RUSTFLAGS "-C" "metadata=no-sanitizer")
|
|
else()
|
|
list(APPEND RUSTFLAGS "-C" "metadata=with-sanitizer-${SANITIZE}")
|
|
endif()
|
|
|
|
# Use v0 symbol mangling for shorter symbol names.
|
|
# The legacy mangling produces extremely long symbols (up to 165 KB) from deeply nested
|
|
# generic types in parser combinator libraries like chumsky (used by prqlc).
|
|
# v0 mangling uses backreference compression for repeated type paths.
|
|
list(APPEND RUSTFLAGS "-C" "symbol-mangling-version=v0")
|
|
|
|
# Suppress warnings
|
|
list(APPEND RUSTFLAGS
|
|
# delta-kernel-rs
|
|
"-Adead_code"
|
|
# skim
|
|
"-Amismatched_lifetime_syntaxes"
|
|
# wasmtime
|
|
"-Aunused_parens -Aunused_imports"
|
|
)
|
|
|
|
list(JOIN RUSTFLAGS " " RUSTFLAGS)
|
|
|
|
message(STATUS "RUST_CFLAGS: ${RUST_CFLAGS}")
|
|
message(STATUS "RUST_CXXFLAGS: ${RUST_CXXFLAGS}")
|
|
message(STATUS "RUSTFLAGS: ${RUSTFLAGS}")
|
|
message(STATUS "RUST_CARGO_BUILD_STD: ${RUST_CARGO_BUILD_STD}")
|
|
|
|
set(RUST_VENDOR_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../rust_vendor")
|
|
|
|
# Sanitizer instrumentation combined with opt-level=3 and the default codegen-units=16
|
|
# causes LLVM to use too much memory while compiling large crates like cranelift-codegen
|
|
# and polyglot-sql (with all-dialects). Set opt-level and codegen-units via the Cargo
|
|
# profile so that there is no conflict with the default profile flags.
|
|
if (NOT SANITIZE STREQUAL "")
|
|
set(RUST_RELEASE_PROFILE_EXTRA "opt-level = 0
|
|
codegen-units = 4")
|
|
else()
|
|
set(RUST_RELEASE_PROFILE_EXTRA "")
|
|
endif()
|
|
|
|
# The vendored Rust crates otherwise build with cargo's default dev profile (full DWARF debug=2 +
|
|
# incremental). debug=1 is cargo's "limited" level: line tables plus function/scope info - so Rust
|
|
# backtraces still resolve file:line - but no type or variable-level info; and dropping the
|
|
# incremental cache stops target/debug/incremental growing unbounded across rebuilds. On by default
|
|
# to keep Debug build dirs lean; set -DREDUCE_RUST_DEBUG_INFO=OFF for full DWARF + incremental when
|
|
# stepping into the crates. Affects Debug only (Release uses profile.release, where this is inert).
|
|
option(REDUCE_RUST_DEBUG_INFO "Build vendored Rust crates with reduced debug info (cargo debug=1, the \"limited\" level) and no incremental caches" ON)
|
|
if (REDUCE_RUST_DEBUG_INFO)
|
|
set(RUST_DEV_PROFILE "[profile.dev]
|
|
debug = 1
|
|
incremental = false
|
|
")
|
|
else()
|
|
set(RUST_DEV_PROFILE "")
|
|
endif()
|
|
|
|
# We now prepare a custom config.toml with all the flags and add it to cargo via flags
|
|
configure_file("config.toml.in" "config.toml" @ONLY)
|
|
set(RUST_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/config.toml" CACHE INTERNAL "Rust config")
|
|
set(RUST_CFLAGS ${RUST_CFLAGS} CACHE INTERNAL "Rust config")
|
|
set(RUST_CXXFLAGS ${RUST_CXXFLAGS} CACHE INTERNAL "Rust config")
|
|
set(RUSTFLAGS "${RUSTFLAGS}" CACHE INTERNAL "Rust config")
|
|
set(RUSTCWRAPPER ${RUSTCWRAPPER} CACHE INTERNAL "Rust config")
|
|
set(RUST_CARGO_BUILD_STD ${RUST_CARGO_BUILD_STD} CACHE INTERNAL "Rust config")
|
|
|
|
function(datastore_import_crate)
|
|
if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG")
|
|
set(profile "")
|
|
else()
|
|
if (ENABLE_THINLTO)
|
|
set(profile "release-thinlto")
|
|
else()
|
|
set(profile "release")
|
|
endif()
|
|
endif()
|
|
|
|
disable_dummy_launchers_if_needed()
|
|
corrosion_import_crate(${ARGN}
|
|
# We set manually the cargo config flags via command line `--config` option
|
|
# We have to do it this way because workspaces are built from source folder and we can't place the `config.toml`
|
|
# there, as it would conflict if you have multiple build folders
|
|
FLAGS "--config=${RUST_CONFIG_FILE}"
|
|
NO_STD
|
|
PROFILE ${profile}
|
|
# We only care about static libraries and want to avoid as much dynamic libs as possible
|
|
CRATE_TYPES staticlib
|
|
# LOCKED (use the committed Cargo.lock) but NOT --offline: let cargo fetch the exact
|
|
# locked crate versions over the network. Our build host isn't fully vendored after the
|
|
# 26.6 merge; offline resolution fails. Keeps reproducibility (locked) without requiring
|
|
# a pre-populated cargo cache.
|
|
LOCKED
|
|
NO_DEFAULT_FEATURES
|
|
)
|
|
enable_dummy_launchers_if_needed()
|
|
endfunction()
|
|
|
|
# Configure a Rust crate target with Datastore-specific flags.
|
|
function(datastore_config_crate_flags target_name)
|
|
corrosion_set_env_vars(${target_name} "CFLAGS=${RUST_CFLAGS}")
|
|
corrosion_set_env_vars(${target_name} "CXXFLAGS=${RUST_CXXFLAGS}")
|
|
corrosion_set_env_vars(${target_name} "RUSTFLAGS=${RUSTFLAGS}")
|
|
corrosion_set_env_vars(${target_name} "RUSTDOCFLAGS=${RUSTFLAGS}")
|
|
if (CMAKE_OSX_SYSROOT)
|
|
corrosion_set_env_vars(${target_name} "SDKROOT=${CMAKE_OSX_SYSROOT}")
|
|
endif()
|
|
|
|
# sccache seems to be broken and mixes up builds
|
|
if (NOT "${RUSTCWRAPPER}" STREQUAL "")
|
|
corrosion_set_env_vars(${target_name} "CARGO_BUILD_RUSTC_WRAPPER=${RUSTCWRAPPER}")
|
|
endif()
|
|
|
|
if (NOT "${RUST_CARGO_BUILD_STD}" STREQUAL "")
|
|
corrosion_set_cargo_flags(${target_name} "${RUST_CARGO_BUILD_STD}")
|
|
endif()
|
|
|
|
# See [1] for more details, but basically:
|
|
# - we need to explicitly set CXXSTDLIB to avoid using of libstdc++
|
|
# - link with the library explicitly to add search path (-L)
|
|
#
|
|
# [1]: https://github.com/rust-lang/cc-rs/blob/7666d4f4f36d3bcacce9ab72fc6538fcc0ea1716/src/lib.rs#L762-L775
|
|
corrosion_set_env_vars(${target_name} "CXXSTDLIB=cxx")
|
|
# Datastore: allow cargo network at build time. After the 26.6 upstream merge our build host's
|
|
# cargo cache/index can't resolve the rust workspace fully offline (the pinned crate set the
|
|
# merge brought isn't all vendored locally). Letting cargo fetch the locked versions is the
|
|
# reliable path; CI can re-pin to fully-vendored offline once the rust deps are vendored.
|
|
corrosion_set_env_vars(${target_name} "CARGO_NET_OFFLINE=false")
|
|
corrosion_link_libraries(${target_name} cxx)
|
|
|
|
# Localize all C-namespace symbols from Rust static libraries so they
|
|
# don't shadow our own implementations (libllvmlibc, glibc-compat).
|
|
# Rust's compiler_builtins exports cbrt, fma, sin, etc. as global symbols;
|
|
# without this, they silently win at link time and bypass our -falign-functions=64
|
|
# and -march flags, causing performance regressions.
|
|
#
|
|
# For workspace crates the .a may land in a parent directory rather than
|
|
# CMAKE_CURRENT_BINARY_DIR. Set IMPORTED_LOCATION on the target before
|
|
# calling this function if the default path is wrong (see wasmtime for an
|
|
# example).
|
|
get_target_property(_rust_lib_path ${target_name} IMPORTED_LOCATION)
|
|
if (NOT _rust_lib_path OR _rust_lib_path MATCHES "NOTFOUND")
|
|
set(_rust_lib_path "${CMAKE_CURRENT_BINARY_DIR}/lib${target_name}.a")
|
|
endif()
|
|
|
|
# Skip on Darwin (Mach-O), ppc64le (broken .eh_frame), and dummy builds.
|
|
if (CMAKE_OBJCOPY AND NOT OS_DARWIN
|
|
AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le"
|
|
AND NOT CMAKE_AR MATCHES "dummy_compiler_linker")
|
|
# Verify the library path looks plausible at configure time. The file
|
|
# won't exist yet (cargo hasn't run), but the parent directory must exist
|
|
# and the filename must end in .a — otherwise someone forgot to set
|
|
# IMPORTED_LOCATION for a workspace subcrate.
|
|
get_filename_component(_rust_lib_dir "${_rust_lib_path}" DIRECTORY)
|
|
if (NOT IS_DIRECTORY "${_rust_lib_dir}")
|
|
message(FATAL_ERROR
|
|
"localize_rust_c_symbols: output directory '${_rust_lib_dir}' for "
|
|
"target '${target_name}' does not exist. If this is a workspace "
|
|
"subcrate, set IMPORTED_LOCATION on the target before calling "
|
|
"datastore_config_crate_flags(). Expected library: ${_rust_lib_path}")
|
|
endif()
|
|
|
|
# Reference libraries that define the C symbols Rust bundles. The script
|
|
# localizes exactly the symbols defined by both these libraries and the
|
|
# Rust archive, so the binary's own copies win at link time.
|
|
#
|
|
# libllvmlibc (our optimized libm, AMD64/AARCH64 only) and clang_rt_builtins
|
|
# (compiler-rt, every ELF target) are contrib targets, defined before any
|
|
# caller of this function.
|
|
set(_localize_ref_libs "")
|
|
set(_localize_ref_deps "")
|
|
foreach (_ref_target libllvmlibc clang_rt_builtins)
|
|
if (TARGET ${_ref_target})
|
|
list(APPEND _localize_ref_libs "$<TARGET_FILE:${_ref_target}>")
|
|
list(APPEND _localize_ref_deps ${_ref_target})
|
|
endif()
|
|
endforeach()
|
|
|
|
# Platform math provider: the library supplying the libm functions
|
|
# libllvmlibc lacks (round, copysign, the ceil/rint/trunc IFUNCs, ...) and
|
|
# the only such provider on arches without libllvmlibc.
|
|
if (USE_MUSL)
|
|
# musl has no separate libm: the math lives in libc, and libc is the
|
|
# in-tree `musl` target built from sources (contrib/musl-cmake) — the
|
|
# -static link uses it instead of a sysroot libc.a / -lc (see
|
|
# cmake/musl.cmake and cmake/linux/default_libs.cmake). Probing the
|
|
# toolchain with -print-file-name would find a glibc library or
|
|
# nothing, so use the built archive itself as the reference and add a
|
|
# build dependency on it.
|
|
list(APPEND _localize_ref_libs "$<TARGET_FILE:musl>")
|
|
list(APPEND _localize_ref_deps musl)
|
|
else()
|
|
# Glibc keeps the math in libm (dynamic, -lm). It is a prebuilt
|
|
# sysroot/toolchain file, so no build dependency is needed.
|
|
#
|
|
# Resolve it once with the same constraints the toolchain compiles
|
|
# with (--target/--sysroot/--gcc-toolchain/--no-default-config);
|
|
# otherwise -print-file-name can return a host multiarch library.
|
|
# Reject any result outside the sysroot/toolchain tree, or one
|
|
# defining no symbols (an empty stub): a wrong or empty reference
|
|
# would leave Rust's libm exports global and shadow the platform's.
|
|
if (NOT DEFINED CACHE{CH_RUST_LOCALIZE_MATHLIB})
|
|
set(_math_probe_flags "")
|
|
set(_math_roots "")
|
|
if (CMAKE_C_COMPILER_TARGET)
|
|
list(APPEND _math_probe_flags "--target=${CMAKE_C_COMPILER_TARGET}")
|
|
endif()
|
|
if (CMAKE_SYSROOT)
|
|
list(APPEND _math_probe_flags "--sysroot=${CMAKE_SYSROOT}")
|
|
list(APPEND _math_roots "${CMAKE_SYSROOT}")
|
|
endif()
|
|
if (TOOLCHAIN_PATH)
|
|
list(APPEND _math_probe_flags "--gcc-toolchain=${TOOLCHAIN_PATH}" "--no-default-config")
|
|
list(APPEND _math_roots "${TOOLCHAIN_PATH}")
|
|
endif()
|
|
|
|
set(_found_math "")
|
|
foreach (_math_name libm.so.6 libm.a libm.so)
|
|
execute_process(
|
|
COMMAND "${CMAKE_C_COMPILER}" ${_math_probe_flags} "-print-file-name=${_math_name}"
|
|
OUTPUT_VARIABLE _math_out OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
|
|
if (NOT _math_out OR NOT EXISTS "${_math_out}")
|
|
continue()
|
|
endif()
|
|
# Must live inside the sysroot/toolchain tree (skipped only for a
|
|
# sysroot-less native build, where the host library is correct).
|
|
if (_math_roots)
|
|
set(_in_tree FALSE)
|
|
get_filename_component(_math_real "${_math_out}" REALPATH)
|
|
foreach (_root ${_math_roots})
|
|
get_filename_component(_root_real "${_root}" REALPATH)
|
|
string(FIND "${_math_real}" "${_root_real}/" _math_pos)
|
|
if (_math_pos EQUAL 0)
|
|
set(_in_tree TRUE)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
if (NOT _in_tree)
|
|
continue()
|
|
endif()
|
|
endif()
|
|
# Must define symbols (static archive: nm; shared object: nm -D);
|
|
# an empty stub is unusable.
|
|
execute_process(COMMAND "${NM_PATH}" "${_math_out}" OUTPUT_VARIABLE _nm_a ERROR_QUIET)
|
|
execute_process(COMMAND "${NM_PATH}" -D "${_math_out}" OUTPUT_VARIABLE _nm_d ERROR_QUIET)
|
|
if (NOT "${_nm_a}${_nm_d}" MATCHES "[0-9a-f] [TDBCWVi] ")
|
|
continue()
|
|
endif()
|
|
set(_found_math "${_math_out}")
|
|
break()
|
|
endforeach()
|
|
set(CH_RUST_LOCALIZE_MATHLIB "${_found_math}" CACHE INTERNAL
|
|
"Platform libm used as a reference for localizing Rust C symbols")
|
|
endif()
|
|
if (CH_RUST_LOCALIZE_MATHLIB)
|
|
list(APPEND _localize_ref_libs "${CH_RUST_LOCALIZE_MATHLIB}")
|
|
endif()
|
|
endif()
|
|
|
|
if (_localize_ref_libs)
|
|
add_custom_target(localize_rust_c_${target_name}
|
|
COMMAND bash "${Datastore_SOURCE_DIR}/cmake/localize_rust_c_symbols.sh"
|
|
"${_rust_lib_path}" "${CMAKE_AR}" "${CMAKE_OBJCOPY}" "${NM_PATH}"
|
|
${_localize_ref_libs}
|
|
COMMENT "Localizing C-namespace symbols in ${target_name}"
|
|
VERBATIM
|
|
)
|
|
add_dependencies(localize_rust_c_${target_name}
|
|
cargo-build_${target_name} ${_localize_ref_deps})
|
|
add_dependencies(${target_name} localize_rust_c_${target_name})
|
|
else()
|
|
message(STATUS
|
|
"localize_rust_c_symbols: no reference C libraries for this "
|
|
"platform; skipping symbol localization for ${target_name}")
|
|
endif()
|
|
endif()
|
|
endfunction()
|