| # 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 |
| # |
| # http://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. |
| |
| cmake_minimum_required(VERSION 3.22) |
| |
| if (POLICY CMP0135) |
| cmake_policy(SET CMP0135 NEW) |
| endif() |
| |
| project(fluss-cpp LANGUAGES CXX) |
| |
| include(FetchContent) |
| set(FLUSS_GOOGLETEST_VERSION 1.15.2 CACHE STRING "version of GoogleTest") |
| set(CMAKE_EXPORT_COMPILE_COMMANDS ON) |
| |
| set(FLUSS_CPP_DEP_MODE "system" CACHE STRING "Dependency provisioning mode for fluss-cpp (system|build)") |
| set_property(CACHE FLUSS_CPP_DEP_MODE PROPERTY STRINGS system build) |
| set(FLUSS_CPP_ARROW_VERSION "19.0.1" CACHE STRING "Arrow C++ version baseline for fluss-cpp") |
| set(FLUSS_CPP_PROTOBUF_VERSION "3.25.5" CACHE STRING "Protobuf/protoc version baseline for fluss-cpp") |
| set(FLUSS_CPP_ARROW_SYSTEM_ROOT "" CACHE PATH "Optional Arrow installation prefix for system mode") |
| set(FLUSS_CPP_ARROW_SOURCE_URL |
| "https://github.com/apache/arrow/archive/refs/tags/apache-arrow-19.0.1.tar.gz" |
| CACHE STRING |
| "Arrow source archive URL used in build mode") |
| set(FLUSS_CPP_ARROW_SOURCE_SHA256 |
| "4c898504958841cc86b6f8710ecb2919f96b5e10fa8989ac10ac4fca8362d86a" |
| CACHE STRING |
| "SHA256 for the Arrow source archive used in build mode") |
| |
| find_package(Threads REQUIRED) |
| |
| if (NOT CMAKE_BUILD_TYPE) |
| set(CMAKE_BUILD_TYPE Release) |
| endif() |
| |
| set(CMAKE_CXX_STANDARD 17) |
| set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| |
| option(FLUSS_ENABLE_ADDRESS_SANITIZER "Enable address sanitizer" OFF) |
| option(FLUSS_ENABLE_TESTING "Enable building test binary for fluss" OFF) |
| option(FLUSS_DEV "Enable dev mode" OFF) |
| |
| if (FLUSS_DEV) |
| set(FLUSS_ENABLE_ADDRESS_SANITIZER ON) |
| set(FLUSS_ENABLE_TESTING ON) |
| endif() |
| |
| if (NOT FLUSS_CPP_DEP_MODE STREQUAL "system" AND NOT FLUSS_CPP_DEP_MODE STREQUAL "build") |
| message(FATAL_ERROR "Unsupported FLUSS_CPP_DEP_MODE='${FLUSS_CPP_DEP_MODE}'. Expected 'system' or 'build'.") |
| endif() |
| |
| find_program(FLUSS_PROTOC_EXECUTABLE NAMES protoc) |
| if (NOT FLUSS_PROTOC_EXECUTABLE) |
| message(FATAL_ERROR "protoc not found. Install protoc or set it in PATH. (Fluss baseline: ${FLUSS_CPP_PROTOBUF_VERSION})") |
| endif() |
| |
| if (DEFINED ENV{CARGO} AND NOT "$ENV{CARGO}" STREQUAL "" AND EXISTS "$ENV{CARGO}") |
| set(FLUSS_CARGO_EXECUTABLE "$ENV{CARGO}") |
| else() |
| if (DEFINED ENV{CARGO} AND NOT "$ENV{CARGO}" STREQUAL "") |
| get_filename_component(_FLUSS_CARGO_HINT_DIR "$ENV{CARGO}" DIRECTORY) |
| endif() |
| find_program(FLUSS_CARGO_EXECUTABLE NAMES cargo HINTS "${_FLUSS_CARGO_HINT_DIR}") |
| endif() |
| if (NOT FLUSS_CARGO_EXECUTABLE) |
| message(FATAL_ERROR "cargo not found. Install Rust toolchain or set CARGO/PATH.") |
| endif() |
| |
| execute_process( |
| COMMAND ${FLUSS_PROTOC_EXECUTABLE} --version |
| OUTPUT_VARIABLE FLUSS_PROTOC_VERSION_OUTPUT |
| OUTPUT_STRIP_TRAILING_WHITESPACE |
| ERROR_QUIET |
| ) |
| string(REGEX MATCH "([0-9]+\\.[0-9]+\\.[0-9]+)" FLUSS_PROTOC_VERSION "${FLUSS_PROTOC_VERSION_OUTPUT}") |
| set(FLUSS_PROTOC_VERSION_NORM "${FLUSS_PROTOC_VERSION}") |
| set(FLUSS_CPP_PROTOBUF_VERSION_NORM "${FLUSS_CPP_PROTOBUF_VERSION}") |
| string(REGEX REPLACE "^3\\." "" FLUSS_PROTOC_VERSION_NORM "${FLUSS_PROTOC_VERSION_NORM}") |
| string(REGEX REPLACE "^3\\." "" FLUSS_CPP_PROTOBUF_VERSION_NORM "${FLUSS_CPP_PROTOBUF_VERSION_NORM}") |
| if (FLUSS_PROTOC_VERSION AND |
| NOT FLUSS_PROTOC_VERSION VERSION_EQUAL FLUSS_CPP_PROTOBUF_VERSION AND |
| NOT FLUSS_PROTOC_VERSION_NORM VERSION_EQUAL FLUSS_CPP_PROTOBUF_VERSION_NORM) |
| message(WARNING |
| "protoc version (${FLUSS_PROTOC_VERSION}) does not match Fluss baseline " |
| "(${FLUSS_CPP_PROTOBUF_VERSION}). Build may still work, but this is outside the tested baseline.") |
| endif() |
| |
| message(STATUS "Fluss C++ dependency mode: ${FLUSS_CPP_DEP_MODE}") |
| message(STATUS "Fluss C++ protoc executable: ${FLUSS_PROTOC_EXECUTABLE} (${FLUSS_PROTOC_VERSION_OUTPUT})") |
| message(STATUS "Fluss C++ cargo executable: ${FLUSS_CARGO_EXECUTABLE}") |
| |
| if (FLUSS_CPP_DEP_MODE STREQUAL "system") |
| if (FLUSS_CPP_ARROW_SYSTEM_ROOT) |
| list(APPEND CMAKE_PREFIX_PATH "${FLUSS_CPP_ARROW_SYSTEM_ROOT}") |
| set(Arrow_ROOT "${FLUSS_CPP_ARROW_SYSTEM_ROOT}") |
| endif() |
| |
| find_package(Arrow REQUIRED) |
| |
| if (DEFINED Arrow_VERSION AND Arrow_VERSION AND NOT Arrow_VERSION VERSION_EQUAL FLUSS_CPP_ARROW_VERSION) |
| message(WARNING |
| "Arrow version (${Arrow_VERSION}) does not match Fluss baseline " |
| "(${FLUSS_CPP_ARROW_VERSION}). Build may still work, but this is outside the tested baseline.") |
| endif() |
| else() |
| # Build mode: provision Arrow C++ from source in-tree. |
| set(ARROW_BUILD_SHARED ON CACHE BOOL "" FORCE) |
| set(ARROW_BUILD_STATIC OFF CACHE BOOL "" FORCE) |
| set(ARROW_BUILD_TESTS OFF CACHE BOOL "" FORCE) |
| set(ARROW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) |
| set(ARROW_BUILD_BENCHMARKS OFF CACHE BOOL "" FORCE) |
| set(ARROW_BUILD_INTEGRATION OFF CACHE BOOL "" FORCE) |
| set(ARROW_BUILD_UTILITIES OFF CACHE BOOL "" FORCE) |
| set(ARROW_COMPUTE OFF CACHE BOOL "" FORCE) |
| set(ARROW_CSV OFF CACHE BOOL "" FORCE) |
| set(ARROW_DATASET OFF CACHE BOOL "" FORCE) |
| set(ARROW_FILESYSTEM OFF CACHE BOOL "" FORCE) |
| set(ARROW_JSON OFF CACHE BOOL "" FORCE) |
| set(ARROW_PARQUET OFF CACHE BOOL "" FORCE) |
| set(ARROW_IPC ON CACHE BOOL "" FORCE) |
| # Reduce third-party sub-build complexity in build mode. |
| set(ARROW_JEMALLOC OFF CACHE BOOL "" FORCE) |
| set(ARROW_MIMALLOC OFF CACHE BOOL "" FORCE) |
| set(ARROW_DEPENDENCY_SOURCE BUNDLED CACHE STRING "" FORCE) |
| set(ARROW_SIMD_LEVEL NONE CACHE STRING "" FORCE) |
| set(ARROW_RUNTIME_SIMD_LEVEL NONE CACHE STRING "" FORCE) |
| |
| FetchContent_Declare( |
| apache_arrow_src |
| URL ${FLUSS_CPP_ARROW_SOURCE_URL} |
| URL_HASH SHA256=${FLUSS_CPP_ARROW_SOURCE_SHA256} |
| SOURCE_SUBDIR cpp |
| ) |
| FetchContent_MakeAvailable(apache_arrow_src) |
| set(FLUSS_CPP_ARROW_EXTRA_INCLUDE_DIRS |
| "${apache_arrow_src_SOURCE_DIR}/cpp/src" |
| "${apache_arrow_src_BINARY_DIR}/src") |
| |
| if (TARGET arrow_shared AND NOT TARGET Arrow::arrow_shared) |
| add_library(Arrow::arrow_shared ALIAS arrow_shared) |
| endif() |
| if (NOT TARGET Arrow::arrow_shared) |
| message(FATAL_ERROR "Arrow build mode did not produce target Arrow::arrow_shared (or arrow_shared).") |
| endif() |
| endif() |
| |
| # Get cargo target dir |
| execute_process(COMMAND ${FLUSS_CARGO_EXECUTABLE} locate-project --workspace --message-format plain |
| OUTPUT_VARIABLE CARGO_MANIFEST_PATH |
| OUTPUT_STRIP_TRAILING_WHITESPACE |
| WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) |
| if (NOT CARGO_MANIFEST_PATH) |
| message(FATAL_ERROR |
| "Failed to resolve Cargo workspace target dir via '${FLUSS_CARGO_EXECUTABLE} locate-project'. " |
| "Check Rust toolchain installation and PATH/CARGO.") |
| endif() |
| get_filename_component(CARGO_WORKSPACE_DIR "${CARGO_MANIFEST_PATH}" DIRECTORY) |
| set(CARGO_TARGET_DIR "${CARGO_WORKSPACE_DIR}/target") |
| |
| set(CARGO_MANIFEST ${PROJECT_SOURCE_DIR}/Cargo.toml) |
| set(RUST_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/lib.rs) |
| set(RUST_BRIDGE_CPP ${CARGO_TARGET_DIR}/cxxbridge/fluss-cpp/src/lib.rs.cc) |
| set(RUST_HEADER_FILE ${CARGO_TARGET_DIR}/cxxbridge/fluss-cpp/src/lib.rs.h) |
| |
| if (CMAKE_BUILD_TYPE STREQUAL "Debug") |
| set(RUST_LIB ${CARGO_TARGET_DIR}/debug/${CMAKE_STATIC_LIBRARY_PREFIX}fluss_cpp${CMAKE_STATIC_LIBRARY_SUFFIX}) |
| else() |
| set(RUST_LIB ${CARGO_TARGET_DIR}/release/${CMAKE_STATIC_LIBRARY_PREFIX}fluss_cpp${CMAKE_STATIC_LIBRARY_SUFFIX}) |
| endif() |
| |
| set(CPP_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include |
| ${PROJECT_SOURCE_DIR}/src |
| ${CARGO_TARGET_DIR}/cxxbridge |
| ${CARGO_TARGET_DIR}/cxxbridge/fluss-cpp/src) |
| |
| file(GLOB CPP_SOURCE_FILE "src/*.cpp") |
| file(GLOB CPP_HEADER_FILE "include/*.hpp") |
| |
| if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") |
| list(APPEND CARGO_BUILD_FLAGS "--release") |
| endif() |
| |
| add_custom_target(cargo_build |
| COMMAND ${CMAKE_COMMAND} -E env PROTOC=${FLUSS_PROTOC_EXECUTABLE} ${FLUSS_CARGO_EXECUTABLE} build --manifest-path ${CARGO_MANIFEST} ${CARGO_BUILD_FLAGS} |
| BYPRODUCTS ${RUST_BRIDGE_CPP} ${RUST_LIB} ${RUST_HEADER_FILE} |
| DEPENDS ${RUST_SOURCE_FILE} |
| USES_TERMINAL |
| COMMENT "Running cargo..." |
| ) |
| |
| add_library(fluss_cpp STATIC ${CPP_SOURCE_FILE} ${RUST_BRIDGE_CPP}) |
| target_sources(fluss_cpp PUBLIC ${CPP_HEADER_FILE}) |
| target_sources(fluss_cpp PRIVATE ${RUST_HEADER_FILE}) |
| target_include_directories(fluss_cpp PUBLIC ${CPP_INCLUDE_DIR}) |
| if (FLUSS_CPP_ARROW_EXTRA_INCLUDE_DIRS) |
| target_include_directories(fluss_cpp PUBLIC ${FLUSS_CPP_ARROW_EXTRA_INCLUDE_DIRS}) |
| endif() |
| target_link_libraries(fluss_cpp PUBLIC ${RUST_LIB}) |
| target_link_libraries(fluss_cpp PRIVATE ${CMAKE_DL_LIBS} Threads::Threads) |
| target_link_libraries(fluss_cpp PUBLIC Arrow::arrow_shared) |
| target_compile_definitions(fluss_cpp PRIVATE ARROW_FOUND) |
| if(APPLE) |
| target_link_libraries(fluss_cpp PUBLIC "-framework CoreFoundation" "-framework Security") |
| endif() |
| |
| add_executable(fluss_cpp_example examples/example.cpp) |
| target_link_libraries(fluss_cpp_example PRIVATE fluss_cpp) |
| target_link_libraries(fluss_cpp_example PRIVATE Arrow::arrow_shared) |
| target_compile_definitions(fluss_cpp_example PRIVATE ARROW_FOUND) |
| target_include_directories(fluss_cpp_example PUBLIC ${CPP_INCLUDE_DIR}) |
| |
| add_executable(fluss_cpp_admin_example examples/admin_example.cpp) |
| target_link_libraries(fluss_cpp_admin_example PRIVATE fluss_cpp) |
| target_link_libraries(fluss_cpp_admin_example PRIVATE Arrow::arrow_shared) |
| target_compile_definitions(fluss_cpp_admin_example PRIVATE ARROW_FOUND) |
| target_include_directories(fluss_cpp_admin_example PUBLIC ${CPP_INCLUDE_DIR}) |
| |
| add_executable(fluss_cpp_kv_example examples/kv_example.cpp) |
| target_link_libraries(fluss_cpp_kv_example PRIVATE fluss_cpp) |
| target_link_libraries(fluss_cpp_kv_example PRIVATE Arrow::arrow_shared) |
| target_compile_definitions(fluss_cpp_kv_example PRIVATE ARROW_FOUND) |
| target_include_directories(fluss_cpp_kv_example PUBLIC ${CPP_INCLUDE_DIR}) |
| |
| if (CARGO_TARGET_DIR) |
| set_target_properties(fluss_cpp |
| PROPERTIES ADDITIONAL_CLEAN_FILES "${CARGO_TARGET_DIR}" |
| ) |
| endif() |
| add_dependencies(fluss_cpp cargo_build) |
| |
| if (FLUSS_ENABLE_ADDRESS_SANITIZER) |
| target_compile_options(fluss_cpp PRIVATE -fsanitize=leak,address,undefined -fno-omit-frame-pointer -fno-common -O1) |
| target_link_options(fluss_cpp PRIVATE -fsanitize=leak,address,undefined) |
| endif() |
| |
| if (FLUSS_ENABLE_TESTING) |
| FetchContent_Declare( |
| googletest |
| URL https://github.com/google/googletest/archive/refs/tags/v${FLUSS_GOOGLETEST_VERSION}.tar.gz |
| ) |
| set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) |
| FetchContent_MakeAvailable(googletest) |
| |
| enable_testing() |
| include(GoogleTest) |
| |
| file(GLOB TEST_SOURCE_FILES "test/*.cpp") |
| add_executable(fluss_cpp_test ${TEST_SOURCE_FILES}) |
| target_link_libraries(fluss_cpp_test PRIVATE fluss_cpp GTest::gtest) |
| target_link_libraries(fluss_cpp_test PRIVATE Arrow::arrow_shared) |
| target_compile_definitions(fluss_cpp_test PRIVATE ARROW_FOUND) |
| target_include_directories(fluss_cpp_test PRIVATE |
| ${CPP_INCLUDE_DIR} |
| ${PROJECT_SOURCE_DIR}/test |
| ) |
| |
| # Individual tests for parallel execution via ctest -j. |
| gtest_discover_tests(fluss_cpp_test |
| PROPERTIES |
| TIMEOUT 120 |
| FIXTURES_REQUIRED fluss_cluster |
| ) |
| |
| # Cleanup: stop Docker containers after all tests finish. |
| # Mirrors Python's pytest_unconfigure and Rust's atexit cleanup. |
| add_test(NAME fluss_cluster_cleanup COMMAND fluss_cpp_test --cleanup) |
| set_tests_properties(fluss_cluster_cleanup PROPERTIES |
| FIXTURES_CLEANUP fluss_cluster |
| ) |
| endif() |