Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ jobs:
run: |
cmake -S lang/cpp -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DVORTEX_DEBUG_INFO=0 \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DVORTEX_SANITIZER=asan \
Expand Down Expand Up @@ -879,6 +879,7 @@ jobs:
RUSTUP_TOOLCHAIN: ${{ env.NIGHTLY_TOOLCHAIN }}
run: |
cmake -S vortex-ffi -B vortex-ffi/build \
-DBUILD_SHARED_LIBS=ON \
-DVORTEX_CARGO_PROFILE=ci \
-DVORTEX_BUILD_TESTS=ON
cmake --build vortex-ffi/build --parallel "$(nproc)"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/rust-instrumented.yml
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ jobs:
run: |
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DVORTEX_SANITIZER=${{ matrix.sanitizer }} \
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
# target_link_libraries(my_c_target PRIVATE Vortex::ffi_static)
# target_link_libraries(my_cpp_target PRIVATE Vortex::cpp_static)
#
# Use Vortex::ffi_shared and Vortex::cpp_shared for shared linkage.
#
# See lang/cpp/README.md for build options and embedding requirements,
# and vortex-ffi/README.md for C API development.

Expand Down
58 changes: 38 additions & 20 deletions lang/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright the Vortex contributors

# Entry point for the static Vortex C++ wrapper. It consumes the Rust FFI
# archive from vortex-ffi and exports Vortex::cpp_static. It supports standalone
# Entry point for the Vortex C++ wrapper. It consumes the Rust FFI library
# from vortex-ffi and exports static and shared targets. It supports standalone
# configuration and add_subdirectory() from the repository root or a parent.

# CMake 3.25 is required for block() and FetchContent SYSTEM.
Expand Down Expand Up @@ -33,6 +33,7 @@ if(_vortex_top_level AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()

option(BUILD_SHARED_LIBS "Use shared libraries for Vortex builds, tests, and examples" OFF)
option(VORTEX_BUILD_TESTS "Build Vortex tests" OFF)
option(VORTEX_BUILD_EXAMPLES "Build Vortex examples" OFF)
option(VORTEX_WARNINGS_AS_ERRORS
Expand All @@ -50,27 +51,44 @@ endif()
# The C++ wrapper over the C FFI. Public headers live under include/.
file(GLOB _vortex_cpp_sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")

# Consumers inherit the FFI archive, its headers, and its system libraries
# through this target. Hidden visibility keeps wrapper symbols out of a parent
# shared library's exports.
add_library(vortex_cxx STATIC ${_vortex_cpp_sources})
set_target_properties(vortex_cxx PROPERTIES
add_library(vortex_cxx_static STATIC ${_vortex_cpp_sources})
set_target_properties(vortex_cxx_static PROPERTIES
OUTPUT_NAME vortex_cxx
# Allow embedding the static archive in a shared library.
POSITION_INDEPENDENT_CODE ON
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON)
target_compile_features(vortex_cxx PUBLIC cxx_std_20)
target_include_directories(vortex_cxx PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(vortex_cxx PUBLIC Vortex::ffi_static)

# Warning policy is private to Vortex-owned sources so embedding this target
# never injects warning flags into consumers.
target_compile_options(vortex_cxx PRIVATE -Wall -Wextra -Wpedantic)
if(VORTEX_WARNINGS_AS_ERRORS)
target_compile_options(vortex_cxx PRIVATE -Werror)
# Keep embedded wrapper symbols out of the parent library's exports.
CXX_VISIBILITY_PRESET hidden)
target_link_libraries(vortex_cxx_static PUBLIC Vortex::ffi_static)
add_library(Vortex::cpp_static ALIAS vortex_cxx_static)

# CMake enables PIC automatically for SHARED targets.
add_library(vortex_cxx_shared SHARED ${_vortex_cpp_sources})
# Override an inherited hidden preset so the shared C++ API remains exported.
set_target_properties(vortex_cxx_shared PROPERTIES
OUTPUT_NAME vortex_cxx
CXX_VISIBILITY_PRESET default)
target_link_libraries(vortex_cxx_shared PUBLIC Vortex::ffi_shared)
add_library(Vortex::cpp_shared ALIAS vortex_cxx_shared)

if(BUILD_SHARED_LIBS)
set_target_properties(vortex_cxx_static PROPERTIES EXCLUDE_FROM_ALL TRUE)
set(_vortex_cpp_target Vortex::cpp_shared)
else()
set_target_properties(vortex_cxx_shared PROPERTIES EXCLUDE_FROM_ALL TRUE)
set(_vortex_cpp_target Vortex::cpp_static)
endif()

# The only supported consumer-facing name for the C++ API.
add_library(Vortex::cpp_static ALIAS vortex_cxx)
foreach(_target IN ITEMS vortex_cxx_static vortex_cxx_shared)
# Hide inline symbols in the shared library and when embedding the static archive.
set_target_properties(${_target} PROPERTIES VISIBILITY_INLINES_HIDDEN ON)
target_compile_features(${_target} PUBLIC cxx_std_20)
target_include_directories(${_target} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
# Warning policy must not propagate into consumers.
target_compile_options(${_target} PRIVATE -Wall -Wextra -Wpedantic)
if(VORTEX_WARNINGS_AS_ERRORS)
target_compile_options(${_target} PRIVATE -Werror)
endif()
endforeach()

# Test and example dependencies are fetched at configure time and never installed.
if(VORTEX_BUILD_TESTS OR VORTEX_BUILD_EXAMPLES)
Expand Down
12 changes: 8 additions & 4 deletions lang/cpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,30 @@ cmake --build build/cpp --parallel
CMake runs Cargo for you. Configuration and builds download uncached dependencies.

**Native builds only:** GNU/Linux x86_64 and aarch64, plus macOS arm64 for standalone development.
Cross-compilation, universal binaries, Windows, musl, and shared Vortex targets are unsupported.
Cross-compilation, universal binaries, Windows, and musl are unsupported.

## Embed in a CMake project

Vendor or fetch a pinned, complete checkout:

```cmake
add_subdirectory(path/to/vortex vortex)
target_link_libraries(my_cpp_target PRIVATE Vortex::cpp_static)
target_link_libraries(my_c_target PRIVATE Vortex::ffi_static)
target_link_libraries(my_cpp_target PRIVATE Vortex::cpp_shared)
target_link_libraries(my_c_target PRIVATE Vortex::ffi_shared)
```

Vortex leaves parent build settings unchanged. Its archives are position-independent.

For static linkage, use `Vortex::ffi_static` and `Vortex::cpp_static`.

## Build options

Pass `-D<OPTION>=<VALUE>` or set options before `add_subdirectory`. Both bindings share these
options. Defaults below are for standalone builds.

| Option | Default | Purpose |
| --------------------------- | -------- | ----------------------------------------------------------- |
| `BUILD_SHARED_LIBS` | `OFF` | Build shared Vortex libraries. |
| `VORTEX_BUILD_TESTS` | `OFF` | C API and C++23 wrapper tests. |
| `VORTEX_BUILD_EXAMPLES` | `OFF` | C/C++ examples. |
| `VORTEX_WARNINGS_AS_ERRORS` | `ON` | Warnings as errors for Vortex targets only. |
Expand All @@ -48,6 +51,7 @@ options. Defaults below are for standalone builds.
| `VORTEX_DEBUG_INFO` | `2` | C/C++ and Rust debug info: `0` none, `1` limited, `2` full. |
| `VORTEX_ENABLE_CUDA` | `OFF` | Linux-only [CUDA build](#cuda). |

As a standard CMake option, `BUILD_SHARED_LIBS` also affects dependencies such as Catch2.
Embedded builds default `VORTEX_WARNINGS_AS_ERRORS` to `OFF`. Parents must call
`enable_testing()` to register tests.

Expand Down Expand Up @@ -172,7 +176,7 @@ This does not retarget the prebuilt nvCOMP SDK.

- Kernel sources are generated in the checkout. Compiled kernels live in Cargo's build directory
and are embedded in the archive as fat binaries.
- CMake does not stage shared libraries. `libvortex_cub.so` must remain at its Cargo build path
- CMake does not stage CUDA dependency libraries. `libvortex_cub.so` must remain at its Cargo build path
or beside the executable. `libnvcomp.so` is loaded from its original Cargo build path.
- CUDA operations require a compatible NVIDIA driver and an accessible GPU.

Expand Down
3 changes: 2 additions & 1 deletion lang/cpp/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ foreach(_name reader writer dtype scan scan_to_arrow)
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
# Drop the inherited per-config override so the local output directory takes effect.
set_property(TARGET cpp_${_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY_${_config_upper})
target_link_libraries(cpp_${_name} PRIVATE Vortex::cpp_static nanoarrow_shared)
target_link_libraries(cpp_${_name} PRIVATE ${_vortex_cpp_target})
endforeach()
target_link_libraries(cpp_scan_to_arrow PRIVATE nanoarrow_shared)
13 changes: 11 additions & 2 deletions lang/cpp/gcov-report.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,26 @@
set -eu
cd "$(dirname "$0")"

coverage_key='$<TARGET_PROPERTY:BINARY_DIR>/$<TARGET_PROPERTY:NAME>'
coverage_launcher="cmake;-E;env;SCCACHE_C_CUSTOM_CACHE_BUSTER=${SCCACHE_C_CUSTOM_CACHE_BUSTER:-}:$coverage_key"
coverage_launcher="$coverage_launcher${CMAKE_CXX_COMPILER_LAUNCHER:+;$CMAKE_CXX_COMPILER_LAUNCHER}"

# CMAKE_SHARED_LINKER_FLAGS links gcov into C-linked shared libraries.
# CMAKE_CXX_COMPILER_LAUNCHER keeps cached .gcda paths target-specific.
cmake -S . -B build \
-DBUILD_SHARED_LIBS=ON \
-DVORTEX_BUILD_TESTS=ON \
-DCMAKE_CXX_FLAGS=--coverage
-DCMAKE_CXX_FLAGS=--coverage \
-DCMAKE_SHARED_LINKER_FLAGS=--coverage \
-DCMAKE_CXX_COMPILER_LAUNCHER="$coverage_launcher"

# getconf works on Linux and macOS; nproc is not installed on stock macOS.
cmake --build build \
--parallel "${CMAKE_BUILD_PARALLEL_LEVEL:-$(getconf _NPROCESSORS_ONLN)}"
ctest --test-dir build --output-on-failure

# lcov matches exclude globs against full source paths.
geninfo build/CMakeFiles/vortex_cxx.dir/ \
geninfo build/CMakeFiles/vortex_cxx_shared.dir/ \
build/tests/CMakeFiles/vortex_cxx_test.dir/ \
--rc geninfo_unexecuted_blocks=1 \
--exclude '/usr/*' --exclude '*/_deps/*' --exclude '*/tests/*' \
Expand Down
2 changes: 1 addition & 1 deletion lang/cpp/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ add_executable(vortex_cxx_test ${TEST_FILES})
target_compile_features(vortex_cxx_test PRIVATE cxx_std_23)
target_include_directories(vortex_cxx_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(vortex_cxx_test PRIVATE
Vortex::cpp_static
${_vortex_cpp_target}
Catch2::Catch2WithMain
magic_enum::magic_enum
nanoarrow_shared)
Expand Down
19 changes: 12 additions & 7 deletions vortex-ffi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright the Vortex contributors

# Entry point for the Rust FFI archive. It builds vortex-ffi with Cargo and
# exports Vortex::ffi_static for C consumers; lang/cpp layers the C++ wrapper on
# top. It supports standalone configuration and add_subdirectory() from a parent.
# Entry point for the Rust FFI libraries. It exports Vortex::ffi_static and
# Vortex::ffi_shared for C consumers; lang/cpp layers the C++ wrapper on top.
# It supports standalone configuration and add_subdirectory() from a parent.

# CMake 3.25 is required for block() and FetchContent SYSTEM.
cmake_minimum_required(VERSION 3.25)
Expand Down Expand Up @@ -33,13 +33,14 @@ if(_vortex_top_level AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()

option(BUILD_SHARED_LIBS "Use shared libraries for Vortex builds, tests, and examples" OFF)
option(VORTEX_BUILD_TESTS "Build Vortex tests" OFF)
option(VORTEX_BUILD_EXAMPLES "Build Vortex examples" OFF)
option(VORTEX_ENABLE_CUDA "Build the CUDA-enabled Vortex FFI" OFF)
set(VORTEX_CARGO_PROFILE "" CACHE STRING "Override the Cargo profile selected from CMAKE_BUILD_TYPE")

# Sanitizers instrument the Rust archive, its C dependencies, and every target
# that links Vortex::ffi_static; Configure.cmake enforces the toolchain constraints.
# Sanitizers instrument the Rust archive, its C dependencies, and consumers of
# either FFI target; Configure.cmake enforces the toolchain constraints.
set(VORTEX_SANITIZER "" CACHE STRING
"Comma-separated sanitizers for Vortex and its consumers: asan, lsan, ubsan, tsan")
option(VORTEX_SANITIZE_RUST_STD
Expand All @@ -50,11 +51,15 @@ option(VORTEX_WARNINGS_AS_ERRORS
"Treat warnings in Vortex-owned sources as errors"
"${_vortex_top_level}")

# Define the Cargo build and the imported vortex_ffi_static archive.
# Define the Cargo build and both FFI library targets.
include(cmake/Configure.cmake)

# The only supported consumer-facing name for the C API.
add_library(Vortex::ffi_static ALIAS vortex_ffi_static)
add_library(Vortex::ffi_shared ALIAS vortex_ffi_shared)
set(_vortex_ffi_target Vortex::ffi_static)
if(BUILD_SHARED_LIBS)
set(_vortex_ffi_target Vortex::ffi_shared)
endif()

# Test and example dependencies are fetched at configure time and never installed.
if(VORTEX_BUILD_TESTS OR VORTEX_BUILD_EXAMPLES)
Expand Down
9 changes: 5 additions & 4 deletions vortex-ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ Add a complete Vortex checkout. CMake builds the Rust archive for you:

```cmake
add_subdirectory(path/to/vortex vortex)
target_link_libraries(my_target PRIVATE Vortex::ffi_static)
target_link_libraries(my_target PRIVATE Vortex::ffi_shared)
```

The target supplies the archive, headers, and native libraries. You can also add `vortex-ffi`
directly. See the [CMake build guide](../lang/cpp/README.md) for shared requirements, options,
and deployment limits.
The target supplies the library and headers. For static linkage, use `Vortex::ffi_static`.
Both targets are available regardless of `BUILD_SHARED_LIBS`. You can also add `vortex-ffi`
directly. See the [CMake build guide](../lang/cpp/README.md) for requirements, options, and
deployment limits.

### Examples and tests

Expand Down
40 changes: 38 additions & 2 deletions vortex-ffi/cmake/Configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,45 @@ block(SCOPE_FOR VARIABLES)
INTERFACE_INCLUDE_DIRECTORIES "${_ffi_include_dir}")
add_dependencies(vortex_ffi_static vortex_ffi_cargo_build)
_vortex_attach_system_dependencies(vortex_ffi_static "${VORTEX_RUST_TARGET}")
# Link Rust once, and keep its internal symbols out of the shared C ABI.
add_library(vortex_ffi_shared SHARED "${CMAKE_CURRENT_LIST_DIR}/shared.c")
if(NOT BUILD_SHARED_LIBS OR NOT PROJECT_IS_TOP_LEVEL)
set_target_properties(vortex_ffi_shared PROPERTIES EXCLUDE_FROM_ALL TRUE)
endif()
target_link_libraries(vortex_ffi_shared PRIVATE
"$<LINK_LIBRARY:WHOLE_ARCHIVE,vortex_ffi_static>")
target_include_directories(vortex_ffi_shared INTERFACE "${_ffi_include_dir}")
set_target_properties(vortex_ffi_shared PROPERTIES OUTPUT_NAME vortex_ffi)
if(APPLE)
target_link_options(vortex_ffi_shared PRIVATE
# Export only the C ABI; Mach-O prefixes C symbols with an underscore.
"LINKER:-exported_symbol,_vx_*"
# Discard unreachable code and data pulled in by whole-archive linking.
"LINKER:-dead_strip")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Keep the generated linker script in the build tree.
set(_exports "${CMAKE_CURRENT_BINARY_DIR}/vortex-ffi-exports.map")
# Export vx_*; localize all other symbols. GENERATE preserves unchanged timestamps.
file(GENERATE OUTPUT "${_exports}" CONTENT "{ global: vx_*; local: *; };\n")
target_link_options(vortex_ffi_shared PRIVATE
# Apply the export allowlist to the Rust archive and its dependencies.
"LINKER:--version-script=${_exports}"
# Discard sections unreachable from exported symbols and other linker roots.
"LINKER:--gc-sections")
# Relink if the generated export policy changes.
set_property(TARGET vortex_ffi_shared APPEND PROPERTY LINK_DEPENDS "${_exports}")

# GNU ld depfiles break on spaces; CMake already tracks the archive and script.
# Defer disabling linker depfiles so child directories keep their settings.
cmake_language(DEFER CALL set CMAKE_LINK_DEPENDS_USE_LINKER FALSE)
else()
message(FATAL_ERROR "Vortex shared-library exports are not configured for ${CMAKE_SYSTEM_NAME}")
endif()
if(_sanitizer_compile_flag)
target_compile_options(vortex_ffi_static INTERFACE "${_sanitizer_compile_flag}")
target_link_options(vortex_ffi_static INTERFACE "${_sanitizer_compile_flag}")
foreach(_target IN ITEMS vortex_ffi_static vortex_ffi_shared)
target_compile_options(${_target} INTERFACE "${_sanitizer_compile_flag}")
target_link_options(${_target} INTERFACE "${_sanitizer_compile_flag}")
endforeach()
endif()

message(STATUS "Vortex Rust target: ${VORTEX_RUST_TARGET}")
Expand Down
4 changes: 3 additions & 1 deletion vortex-ffi/cmake/SystemDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ function(_vortex_attach_system_dependencies target rust_target)
# The archive needs no C++ runtime, so C and C++ consumers alike only
# need libSystem from their driver plus these extra libraries.
find_library(_vortex_core_foundation CoreFoundation REQUIRED NO_CACHE)
target_link_libraries("${target}" INTERFACE iconv "${_vortex_core_foundation}")
find_library(_vortex_security Security REQUIRED NO_CACHE)
target_link_libraries("${target}" INTERFACE
iconv "${_vortex_core_foundation}" "${_vortex_security}")
else()
message(FATAL_ERROR
"Vortex has no validated native static-link manifest for Rust target "
Expand Down
5 changes: 5 additions & 0 deletions vortex-ffi/cmake/shared.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

// The implementation is supplied by the whole-archive Rust dependency.
#include "vortex.h"
2 changes: 1 addition & 1 deletion vortex-ffi/cmake/tests/test_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def setUp(self) -> None:
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/defaults.txt"
"${CMAKE_BUILD_TYPE}\n${VORTEX_WARNINGS_AS_ERRORS}\n")
if(PROJECT_NAME STREQUAL "VortexCXX")
get_target_property(options vortex_cxx COMPILE_OPTIONS)
get_target_property(options vortex_cxx_static COMPILE_OPTIONS)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/defaults.txt" "${options}\n")
endif()
endfunction()
Expand Down
2 changes: 1 addition & 1 deletion vortex-ffi/cmake/tests/test_cuda_architectures.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def test_configure_forwards_flags_and_cpu_ignores_policy(self) -> None:
"source/CMakeLists.txt",
f"""\
cmake_minimum_required(VERSION 3.25)
project(CudaArchitectureFixture LANGUAGES NONE)
project(CudaArchitectureFixture LANGUAGES C)
set(CMAKE_SYSTEM_NAME Linux)
set(APPLE FALSE)
set(CMAKE_BUILD_TYPE Debug)
Expand Down
2 changes: 1 addition & 1 deletion vortex-ffi/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ foreach(_name scan scan_to_arrow dtype write_sample)
if(VORTEX_WARNINGS_AS_ERRORS)
target_compile_options(ffi_${_name} PRIVATE -Werror)
endif()
target_link_libraries(ffi_${_name} PRIVATE Vortex::ffi_static)
target_link_libraries(ffi_${_name} PRIVATE ${_vortex_ffi_target})
endforeach()
target_link_libraries(ffi_scan_to_arrow PRIVATE nanoarrow_shared)
2 changes: 1 addition & 1 deletion vortex-ffi/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ if(VORTEX_WARNINGS_AS_ERRORS)
target_compile_options(vortex_ffi_test PRIVATE -Werror)
endif()
target_link_libraries(vortex_ffi_test PRIVATE
Vortex::ffi_static
${_vortex_ffi_target}
Catch2::Catch2WithMain
nanoarrow_shared)

Expand Down
Loading