cmake_minimum_required(VERSION 3.16) project(bexcli LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # ── Release Optimization Flags ──────────────────────────────────────────── # Full static binary, size-optimized, no debug symbols in release mode. if(CMAKE_BUILD_TYPE STREQUAL "Release") # Strip all debug symbols from the final binary set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s -Wl,--gc-sections -Wl,--strip-all") # Optimize for size set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os") endif() # ── Build Configuration ────────────────────────────────────────────────── if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() # ── Bex Engine Integration ─────────────────────────────────────────────── # This CMake is designed to be self-contained and reusable. # Copy this directory into any C++ project and it will automatically # find and link the Rust Bex Engine static library. # # Requirements: # 1. Build the Rust library first: cargo build -p bex-runtime --release # 2. Set BEX_ENGINE_ROOT if this directory is not inside the bex-engine repo # # The Rust library exports a pure C ABI via bex_engine.h — no bridge crate needed. # Find the Bex Engine root directory if(NOT BEX_ENGINE_ROOT) # Default: assume we're inside bex-engine/cpp-cli/ get_filename_component(_BEX_ROOT "${CMAKE_SOURCE_DIR}/.." ABSOLUTE) if(EXISTS "${_BEX_ROOT}/Cargo.toml") set(BEX_ENGINE_ROOT "${_BEX_ROOT}") else() message(FATAL_ERROR "Cannot find Bex Engine root. Set -DBEX_ENGINE_ROOT=/path/to/bex-engine\n" "The bex-engine directory should contain Cargo.toml and the crates/ directory." ) endif() endif() message(STATUS "Bex Engine root: ${BEX_ENGINE_ROOT}") # ── Rust Target Directory ──────────────────────────────────────────────── # CMake uses "Release" / "Debug", but Rust uses "release" / "debug" if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") set(RUST_PROFILE "release") else() set(RUST_PROFILE "debug") endif() set(RUST_TARGET_DIR "${BEX_ENGINE_ROOT}/target/${RUST_PROFILE}") # ── Detect the Rust library name ───────────────────────────────────────── # bex-runtime compiles as both cdylib and staticlib. The produced filename # differs by platform/toolchain: Windows (MSVC) -> "bex_runtime.lib"/.dll, # GNU toolchain -> "libbex_runtime.a"/.so. Prefer static when available. if(WIN32) set(RUST_STATIC_LIB "${RUST_TARGET_DIR}/bex_runtime.lib") set(RUST_SHARED_LIB "${RUST_TARGET_DIR}/bex_runtime.dll") else() set(RUST_STATIC_LIB "${RUST_TARGET_DIR}/libbex_runtime.a") set(RUST_SHARED_LIB "${RUST_TARGET_DIR}/libbex_runtime.so") endif() if(EXISTS "${RUST_STATIC_LIB}") set(BEX_LINK_MODE "static") set(BEX_LIB_PATH "${RUST_STATIC_LIB}") message(STATUS "Found Rust static library: ${BEX_LIB_PATH}") elseif(EXISTS "${RUST_SHARED_LIB}") set(BEX_LINK_MODE "shared") set(BEX_LIB_PATH "${RUST_SHARED_LIB}") message(STATUS "Found Rust shared library: ${BEX_LIB_PATH}") else() message(WARNING "Rust library not found at ${RUST_STATIC_LIB} or ${RUST_SHARED_LIB}\n" "Build it first: cd ${BEX_ENGINE_ROOT} && cargo build -p bex-runtime --release" ) set(BEX_LINK_MODE "static") set(BEX_LIB_PATH "${RUST_STATIC_LIB}") endif() if(WIN32) set(BEX_WINDOWS_SYS_LIBS bcrypt userenv ntdll advapi32) endif() # ── C Header Location ──────────────────────────────────────────────────── set(BEX_INCLUDE_DIR "${CMAKE_SOURCE_DIR}") # ── Bex Engine Library (Imported Target) ───────────────────────────────── # Create an INTERFACE library target so other projects can simply do: # target_link_libraries(myapp PRIVATE bex::engine) # target_include_directories(myapp PRIVATE ${BEX_INCLUDE_DIR}) add_library(bex_engine_lib INTERFACE) add_library(bex::engine ALIAS bex_engine_lib) target_include_directories(bex_engine_lib INTERFACE "${BEX_INCLUDE_DIR}") if(BEX_LINK_MODE STREQUAL "static") if(WIN32) target_link_libraries(bex_engine_lib INTERFACE "${BEX_LIB_PATH}" ${BEX_WINDOWS_SYS_LIBS} ) else() target_link_libraries(bex_engine_lib INTERFACE "${BEX_LIB_PATH}" dl pthread m ) target_link_directories(bex_engine_lib INTERFACE "${RUST_TARGET_DIR}/deps") endif() else() if(WIN32) target_link_libraries(bex_engine_lib INTERFACE "${BEX_LIB_PATH}" ) else() target_link_libraries(bex_engine_lib INTERFACE "${BEX_LIB_PATH}" dl pthread m ) endif() endif() # ── Executable: bexcli ─────────────────────────────────────────────────── add_executable(bexcli bexcli.cpp) target_include_directories(bexcli PRIVATE "${BEX_INCLUDE_DIR}") target_link_libraries(bexcli PRIVATE bex_engine_lib) # ── Static Linking for Release ──────────────────────────────────────────── # Produce a fully static binary in release mode (no runtime dependencies). if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT WIN32) target_link_options(bexcli PRIVATE -static) endif() # ── Helper Target: Build Rust Library ──────────────────────────────────── add_custom_target(rustlib COMMAND ${CMAKE_COMMAND} -E env cargo build -p bex-runtime --release WORKING_DIRECTORY ${BEX_ENGINE_ROOT} COMMENT "Building Rust bex-runtime library (pure C ABI)..." VERBATIM ) # Make bexcli depend on rustlib if the library file doesn't exist yet if(NOT EXISTS "${BEX_LIB_PATH}") add_dependencies(bexcli rustlib) endif() # ── Install Rules (for integration into other projects) ────────────────── install(TARGETS bexcli RUNTIME DESTINATION bin) install(FILES "${CMAKE_SOURCE_DIR}/bex_engine.h" DESTINATION include/bex ) # ── Print Configuration Summary ────────────────────────────────────────── message(STATUS "") message(STATUS "=== Bex CLI Configuration (Pure C ABI) ===") message(STATUS " Build type: ${CMAKE_BUILD_TYPE}") message(STATUS " Rust profile: ${RUST_PROFILE}") message(STATUS " Engine root: ${BEX_ENGINE_ROOT}") message(STATUS " Rust target dir: ${RUST_TARGET_DIR}") message(STATUS " Link mode: ${BEX_LINK_MODE}") message(STATUS " Library path: ${BEX_LIB_PATH}") message(STATUS " Include dir: ${BEX_INCLUDE_DIR}") message(STATUS " FFI: Pure C ABI (bex_engine.h)") message(STATUS "==========================================") message(STATUS "")