diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 7755818f9e48..d3116e5de893 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -487,6 +487,7 @@ jobs: path: ${{ steps.ccache-info.outputs.cache-dir }} key: jni-windows + # On Linux, link ODBC dynamically to follow general RPM/DEB guidelines odbc-linux: needs: check-enabled if: needs.check-enabled.outputs.is_enabled == 'true' @@ -529,6 +530,17 @@ jobs: sudo sysctl -w vm.mmap_rnd_bits=28 source ci/scripts/util_enable_core_dumps.sh archery docker run ubuntu-cpp-odbc + - name: Check ODBC Dependency + run: | + # The ODBC driver should link Arrow libraries dynamically on Linux + lib="$(pwd)/build/cpp/release/libarrow_flight_sql_odbc.so" + ldd "${lib}" + for arrow_lib in libarrow libarrow_compute libarrow_flight libarrow_flight_sql; do + ldd "${lib}" | grep -Fq "${arrow_lib}.so" || { + echo "Error: ${arrow_lib} is not dynamically linked to ${lib}" + exit 1 + } + done - name: Save Docker Volumes if: ${{ !cancelled() }} continue-on-error: true @@ -561,6 +573,7 @@ jobs: - { architecture: ARM64, macos-version: "26", build-type : debug } - { architecture: ARM64, macos-version: "26", build-type : release } env: + # on macOS, always link ODBC statically to support sandbox env ARROW_BUILD_TESTS: ON ARROW_BUILD_TYPE: ${{ matrix.build-type }} ARROW_DEPENDENCY_SOURCE: BUNDLED @@ -801,6 +814,7 @@ jobs: contents: read packages: write env: + # on Windows, link ODBC statically and compile into 1 DLL to minimize signing ARROW_BUILD_SHARED: OFF ARROW_BUILD_STATIC: ON ARROW_BUILD_TESTS: ON diff --git a/ci/docker/ubuntu-24.04-cpp.dockerfile b/ci/docker/ubuntu-24.04-cpp.dockerfile index 051a2577487e..72e7bcae380d 100644 --- a/ci/docker/ubuntu-24.04-cpp.dockerfile +++ b/ci/docker/ubuntu-24.04-cpp.dockerfile @@ -75,6 +75,7 @@ RUN apt-get update -y -q && \ git \ libbenchmark-dev \ libboost-filesystem-dev \ + libboost-locale-dev \ libbrotli-dev \ libbz2-dev \ libc-ares-dev \ diff --git a/compose.yaml b/compose.yaml index a3a65c4c2d04..ef81ea499183 100644 --- a/compose.yaml +++ b/compose.yaml @@ -518,7 +518,7 @@ services: command: *cpp-command ubuntu-cpp-odbc: - # Arrow Flight SQL ODBC build with BUNDLED dependencies with downloaded dependencies. + # Arrow Flight SQL ODBC build with shared dependencies, like arrow.spec.in <<: *ubuntu-cpp-base environment: <<: [*common, *ccache, *sccache, *cpp] @@ -527,8 +527,8 @@ services: ARROW_BUILD_TYPE: RELEASE ARROW_CSV: "OFF" ARROW_DATASET: "OFF" - ARROW_DEPENDENCY_SOURCE: BUNDLED - ARROW_DEPENDENCY_USE_SHARED: "OFF" + ARROW_DEPENDENCY_SOURCE: AUTO + ARROW_DEPENDENCY_USE_SHARED: "ON" ARROW_FLIGHT_SQL_ODBC: "ON" ARROW_FLIGHT_SQL_ODBC_CONN: "driver={Apache Arrow Flight SQL ODBC Driver};HOST=dremio;port=32010;pwd=admin2025;uid=admin;useEncryption=false;UseWideChar=true;" ARROW_GANDIVA: "OFF" @@ -542,11 +542,12 @@ services: depends_on: dremio: condition: service_healthy + # Use `/arrow/build` so build artifacts are visible on the CI host command: > /bin/bash -c " - /arrow/ci/scripts/cpp_build.sh /arrow /build && + /arrow/ci/scripts/cpp_build.sh /arrow /arrow/build && sudo /arrow/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh /usr/local/lib/libarrow_flight_sql_odbc.so && - /arrow/ci/scripts/cpp_test.sh /arrow /build" + /arrow/ci/scripts/cpp_test.sh /arrow /arrow/build" ubuntu-cpp-minimal: # Arrow build with minimal components/dependencies diff --git a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt index 033a2775b663..ed0a9a335e4d 100644 --- a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt @@ -59,34 +59,36 @@ if(WIN32) list(APPEND ARROW_FLIGHT_SQL_ODBC_SRCS odbc.def install/versioninfo.rc) endif() -# Initialize install interface libs (only set in Windows static build) +# Initialize install interface libs (only set on Windows and Linux) set(ARROW_FLIGHT_SQL_ODBC_SHARED_INSTALL_INTERFACE_LIBS "") set(ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS "") set(ARROW_FLIGHT_SQL_ODBC_SHARED_PRIVATE_LINK_LIBS "") -if(WIN32) - if(ARROW_BUILD_STATIC) - # Static Arrow deps on Windows — self-contained ODBC DLL - set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_flight_sql_static +# On macOS, always link Arrow libraries statically. +# On Windows and Linux, link Arrow libraries dynamically if the shared libraries are +# built, and statically otherwise. +if(NOT APPLE) + if(ARROW_BUILD_SHARED) + set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_flight_sql_shared arrow_odbc_spi_impl) set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS arrow_flight_sql_static) list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_INSTALL_INTERFACE_LIBS - ArrowFlight::arrow_flight_sql_static) + ArrowFlight::arrow_flight_sql_shared) list(APPEND ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS ArrowFlight::arrow_flight_sql_static) else() - set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_flight_sql_shared + # Static Arrow deps — self-contained ODBC library + set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_flight_sql_static arrow_odbc_spi_impl) set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS arrow_flight_sql_static) list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_INSTALL_INTERFACE_LIBS - ArrowFlight::arrow_flight_sql_shared) + ArrowFlight::arrow_flight_sql_static) list(APPEND ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS ArrowFlight::arrow_flight_sql_static) endif() list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_PRIVATE_LINK_LIBS ODBC::ODBC ${ODBCINST}) else() - # Unix/macOS: driver dynamically links arrow_flight_sql so the driver and test - # binary share the same grpc/arrow_flight runtime. + # macOS: arrow_odbc_spi_impl always links Arrow statically. set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_odbc_spi_impl) set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS ODBC::ODBC ${ODBCINST}) endif() diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt index 17d2ee1ffeea..78d7540014bc 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt @@ -130,26 +130,29 @@ if(WIN32) win_system_dsn.cc) endif() -if(WIN32) +# On macOS, always link Arrow libraries statically. +# On Windows and Linux, link Arrow libraries dynamically if the shared libraries are +# built, and statically otherwise. +if(NOT APPLE) find_package(ODBC REQUIRED) target_include_directories(arrow_odbc_spi_impl PUBLIC ${ODBC_INCLUDE_DIR}) - if(ARROW_BUILD_STATIC) + if(ARROW_BUILD_SHARED) target_link_libraries(arrow_odbc_spi_impl - PUBLIC arrow_flight_sql_static - arrow_compute_static + PUBLIC arrow_flight_sql_shared + arrow_compute_shared Boost::locale arrow::simdjson ${ODBCINST}) else() target_link_libraries(arrow_odbc_spi_impl - PUBLIC arrow_flight_sql_shared - arrow_compute_shared + PUBLIC arrow_flight_sql_static + arrow_compute_static Boost::locale arrow::simdjson ${ODBCINST}) endif() else() - # Unix + # macOS - always link Arrow statically to support sandbox env target_include_directories(arrow_odbc_spi_impl SYSTEM BEFORE PUBLIC ${ODBC_INCLUDE_DIR}) target_link_libraries(arrow_odbc_spi_impl PUBLIC arrow_flight_sql_static @@ -157,11 +160,6 @@ else() Boost::locale Boost::headers arrow::simdjson) - - if(NOT APPLE) - # Explicitly link to unix-odbc on Linux - target_link_libraries(arrow_odbc_spi_impl PUBLIC ${ODBCINST}) - endif() endif() # CLI @@ -173,18 +171,17 @@ target_link_libraries(arrow_odbc_spi_impl_cli arrow_odbc_spi_impl) # Unit tests -# On Windows, dynamic linking ODBC is supported. -# On unix systems, static linking ODBC is supported, thus the library linking is static. +# On macOS, only static linking ODBC is supported, thus the library linking is static. # Use STATIC_LINK_LIBS when Flight tests require static linkage to avoid mixing static/shared Arrow -if(WIN32 AND ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static") +if(NOT APPLE AND ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static") set(ODBC_SPI_IMPL_TEST_STATIC_LIBS arrow_odbc_spi_impl arrow_flight_testing_static ${ARROW_TEST_STATIC_LINK_LIBS}) set(ODBC_SPI_IMPL_TEST_EXTRA_LIBS "") -elseif(WIN32) +elseif(NOT APPLE) set(ODBC_SPI_IMPL_TEST_STATIC_LIBS "") set(ODBC_SPI_IMPL_TEST_EXTRA_LIBS arrow_odbc_spi_impl arrow_flight_testing_shared) else() - # Unix - always static + # macOS - always static set(ODBC_SPI_IMPL_TEST_STATIC_LIBS arrow_odbc_spi_impl arrow_flight_testing_static ${ARROW_TEST_STATIC_LINK_LIBS}) set(ODBC_SPI_IMPL_TEST_EXTRA_LIBS "") diff --git a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt index f3c345e2449f..8a62a45fa047 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt @@ -57,21 +57,13 @@ elseif(WIN32) set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS arrow_odbc_spi_impl ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS} arrow_flight_sql_odbc_static ${ARROW_TEST_STATIC_LINK_LIBS}) -elseif(APPLE) - # GH-49651: Link the ODBC driver dynamically on macOS. +else() + # GH-49651: Link the ODBC driver dynamically on macOS and Linux. The tests call the + # driver functions directly, so they need the driver library. set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_MODE STATIC_LINK_LIBS) set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS} arrow_flight_sql_odbc_shared ${ARROW_TEST_SHARED_LINK_LIBS}) -else() - # GH-49651: Link the ODBC driver statically on Linux to avoid a segfault. - set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_MODE STATIC_LINK_LIBS) - set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS - ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS} - arrow_flight_sql_odbc_static - ${ARROW_TEST_STATIC_LINK_LIBS} - arrow_odbc_spi_impl - ${ARROW_PROTOBUF_LIBPROTOBUF}) endif() add_arrow_test(flight_sql_odbc_test