Skip to content

GH-55279: [C++] Fix build errors with ARROW_BUILD_{SHARED,STATIC,TESTS}=ON on Windows - #55294

Open
kou wants to merge 10 commits into
apache:mainfrom
kou:ci-windows-build-static
Open

kou wants to merge 10 commits into
apache:mainfrom
kou:ci-windows-build-static

Conversation

@kou

@kou kou commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Rationale for this change

We can't build Arrow C++ with ARROW_BUILD_SHARED=ON, ARROW_BUILD_STATIC=ON and ARROW_BUILD_TESTS=ON on Windows. Tests are linked with shared libraries by default (ARROW_TEST_LINKAGE=shared) but some targets use ARROW_BUILD_STATIC to choose static libraries/definitions:

  • arrow_compute_testing is an object library and it sets ARROW_STATIC/ARROW_COMPUTE_STATIC as public compile definitions with ARROW_BUILD_STATIC. So tests that use arrow_compute_testing are compiled with ARROW_STATIC/ARROW_COMPUTE_STATIC even when they are linked with shared libraries.
  • arrow-compute-grouper-benchmark links arrow_compute_static with ARROW_BUILD_STATIC. So it's linked with both of arrow_static and arrow_shared.

parquet_static can't be built with Parquet encryption on Windows too. It doesn't link OpenSSL. We don't use a shared object library for shared and static libraries on Windows. So parquet_static can't find OpenSSL headers. parquet/arrow/reader.cc uses OpenTelemetry headers via arrow/util/tracing_internal.h but parquet_static doesn't link OpenTelemetry.

Our CI doesn't detect them because we don't have any Windows job that uses ARROW_BUILD_SHARED=ON and ARROW_BUILD_STATIC=ON.

There are similar problems that aren't detected by our CI:

  • Parquet benchmarks use parquet_shared with static test libraries when ARROW_BUILD_SHARED=ON, ARROW_BUILD_STATIC=ON and ARROW_TEST_LINKAGE=static. So they're linked with both of arrow_static and arrow_shared.
  • parquet_testing is an object library that doesn't have ARROW_STATIC/PARQUET_STATIC. So parquet/test_util.cc is compiled without them even when tests are linked with static libraries on Windows.

What changes are included in this PR?

  • Use ARROW_BUILD_STATIC=ON in the Windows CI job to detect this case.
  • Link OpenSSL to parquet_static when Parquet encryption is enabled.
  • Link OpenTelemetry to parquet_static when OpenTelemetry is enabled.
  • Use static libraries instead of object libraries for arrow_compute_core_testing, arrow_compute_kernels_testing, arrow_acero_testing, arrow_dataset_testing and parquet_testing. They link libraries for ARROW_TEST_LINKAGE as PUBLIC. So they're compiled with the same compile definitions (e.g. ARROW_STATIC on Windows) as tests. We don't need to set ARROW_STATIC/ARROW_COMPUTE_STATIC manually. Their sources are compiled only once.
  • Split arrow_compute_testing to arrow_compute_core_testing (helpers) and arrow_compute_testing_main (main() in test_env.cc).
    • arrow_compute_testing_main is an interface library. If we use a static library for it, main() in GTest::gmock_main may be used instead of main() in test_env.cc. Interface library sources are compiled as sources of each test executable, so main() in test_env.cc is always used.
    • arrow_compute_testing_main doesn't link any Arrow library. So it can be used by tests that use different linkage from ARROW_TEST_LINKAGE such as Flight SQL tests (ARROW_FLIGHT_TEST_LINKAGE).
    • arrow_compute_testing_main must not be linked as PUBLIC from static testing libraries. If it's linked as PUBLIC, test_env.cc is also compiled into these static libraries. So tests link it explicitly.
  • Use testing libraries instead of ARROW_ACERO_TEST_LINK_LIBS, ARROW_DATASET_TEST_LINK_LIBS and PARQUET_TEST_LINK_LIBS in tests and benchmarks. Testing libraries already link libraries for ARROW_TEST_LINKAGE.
  • Use ARROW_TEST_LINKAGE instead of ARROW_BUILD_STATIC to choose a compute library for arrow-compute-grouper-benchmark.
  • Use ARROW_TEST_LINKAGE instead of ARROW_BUILD_SHARED to choose a Parquet library for Parquet benchmarks.

Note that the ORC adapter test still uses ARROW_BUILD_STATIC to choose libraries. It uses liborc directly and links orc::orc. If it's linked with arrow_shared, ORC's protobuf messages are registered twice (by libarrow and the test). We'll work on it separately if we need it.

Are these changes tested?

Yes.

Are there any user-facing changes?

No.

Was AI used for this PR?

In accordance to the AI generation guidelines, please disclose below whether and how AI was used in this PR.

PR code and description written by:

  • Human
  • AI

Reviewed before submission by:

  • Human
  • AI
  • Not reviewed

Copilot AI balanced review requested due to automatic review settings October 28, 2026 00:07
@kou
kou marked this pull request as draft October 28, 2026 00:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@github-actions github-actions Bot added the awaiting committer review Awaiting committer review label Oct 28, 2026
parquet_static isn't compiled from the shared object library on
Windows. So it needs OpenSSL in its own link libraries to find OpenSSL
headers.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@kou

kou commented Oct 28, 2026

Copy link
Copy Markdown
Member Author

Confirmed: https://github.com/apache/arrow/actions/runs/40611094510/job/122562525836?pr=55294#step:11:6776

FAILED: [code=2] src/arrow/c/CMakeFiles/arrow-c-bridge-test.dir/Unity/unity_0_cxx.cxx.obj 
"C:\Program Files\Git\usr\bin\ccache.exe" C:\PROGRA~1\MICROS~2\2022\ENTERP~1\VC\Tools\MSVC\1444~1.352\bin\Hostx64\x64\cl.exe  /nologo /TP -DARROW_COMPUTE_STATIC -DARROW_HAVE_AVX2 -DARROW_HAVE_BMI2 -DARROW_HAVE_RUNTIME_AVX2 -DARROW_HAVE_RUNTIME_AVX512 -DARROW_HAVE_RUNTIME_BMI2 -DARROW_HAVE_RUNTIME_SSE4_2 -DARROW_HAVE_SSE4_2 -DARROW_STATIC -DARROW_WITH_BENCHMARKS_REFERENCE -DARROW_WITH_TIMING_TESTS -DGTEST_LINKED_AS_SHARED_LIBRARY=1 -D_CRT_SECURE_NO_WARNINGS -ID:\a\arrow\arrow\build\cpp\src -ID:\a\arrow\arrow\cpp\src -external:ID:\a\arrow\arrow\build\cpp\_deps\googletest-src\googlemock\include -external:ID:\a\arrow\arrow\build\cpp\_deps\googletest-src\googletest\include -external:ID:\a\arrow\arrow\cpp\thirdparty\flatbuffers\include -external:ID:\a\arrow\arrow\build\cpp\_deps\googletest-src\googletest -external:ID:\a\arrow\arrow\build\cpp\_deps\googletest-src\googlemock -external:W0 /D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING /W3 /EHsc /Zc:preprocessor /bigobj /utf-8 /W3 /wd4365 /wd4267 /wd4838 /wd4800 /wd4996 /wd4065 /arch:AVX2  /Ob0 /Od /RTC1 /WX -std:c++20 -MDd -Z7 /showIncludes /Fosrc\arrow\c\CMakeFiles\arrow-c-bridge-test.dir\Unity\unity_0_cxx.cxx.obj /Fdsrc\arrow\c\CMakeFiles\arrow-c-bridge-test.dir\ /FS -c D:\a\arrow\arrow\build\cpp\src\arrow\c\CMakeFiles\arrow-c-bridge-test.dir\Unity\unity_0_cxx.cxx
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(30): error C2220: the following warning is treated as an error
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(30): warning C4275: non dll-interface class 'arrow::ExtensionArray' used as base for dll-interface class 'arrow::ExampleUuidArray'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(107): note: see declaration of 'arrow::ExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(30): note: see declaration of 'arrow::ExampleUuidArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(35): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::ExampleUuidType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(35): note: see declaration of 'arrow::ExampleUuidType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(52): warning C4275: non dll-interface class 'arrow::ExtensionArray' used as base for dll-interface class 'arrow::SmallintArray'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(107): note: see declaration of 'arrow::ExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(52): note: see declaration of 'arrow::SmallintArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(57): warning C4275: non dll-interface class 'arrow::ExtensionArray' used as base for dll-interface class 'arrow::TinyintArray'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(107): note: see declaration of 'arrow::ExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(57): note: see declaration of 'arrow::TinyintArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(62): warning C4275: non dll-interface class 'arrow::ExtensionArray' used as base for dll-interface class 'arrow::ListExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(107): note: see declaration of 'arrow::ExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(62): note: see declaration of 'arrow::ListExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(67): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::SmallintType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(67): note: see declaration of 'arrow::SmallintType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(84): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::TinyintType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(84): note: see declaration of 'arrow::TinyintType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(101): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::ListExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(101): note: see declaration of 'arrow::ListExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(118): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::DictExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(118): note: see declaration of 'arrow::DictExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(135): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::BinaryViewExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(135): note: see declaration of 'arrow::BinaryViewExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(153): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::MetadataOptionalExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(153): note: see declaration of 'arrow::MetadataOptionalExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(171): warning C4275: non dll-interface class 'arrow::ExtensionArray' used as base for dll-interface class 'arrow::UnionExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(107): note: see declaration of 'arrow::ExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(171): note: see declaration of 'arrow::UnionExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(181): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::UnionExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(181): note: see declaration of 'arrow::UnionExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(203): warning C4275: non dll-interface class 'arrow::ExtensionArray' used as base for dll-interface class 'arrow::Complex128Array'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(107): note: see declaration of 'arrow::ExtensionArray'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(203): note: see declaration of 'arrow::Complex128Array'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(208): warning C4275: non dll-interface class 'arrow::ExtensionType' used as base for dll-interface class 'arrow::Complex128Type'
D:\a\arrow\arrow\cpp\src\arrow/extension_type.h(39): note: see declaration of 'arrow::ExtensionType'
D:\a\arrow\arrow\cpp\src\arrow/testing/extension_type.h(208): note: see declaration of 'arrow::Complex128Type'

@kou
kou force-pushed the ci-windows-build-static branch 2 times, most recently from 15d8bbc to 24e1a08 Compare October 28, 2026 02:22
kou and others added 2 commits October 28, 2026 11:46
arrow_compute_core_testing, arrow_compute_testing,
arrow_compute_kernels_testing, arrow_acero_testing and
arrow_dataset_testing were object libraries. Object libraries are
compiled with their own compile definitions, not with test's compile
definitions. So we needed to set ARROW_STATIC and ARROW_COMPUTE_STATIC
manually for arrow_compute_testing on Windows. But it was wrong with
ARROW_BUILD_SHARED=ON, ARROW_BUILD_STATIC=ON and
ARROW_TEST_LINKAGE=shared.

Interface libraries with interface sources are compiled as sources of
each test executable. So they use the same compile definitions as the
test automatically.

Testing interface libraries must be linked only by test and benchmark
executables. If they are linked by other targets such as object
libraries, their sources are also compiled into the targets.

arrow_compute_kernels_testing and arrow_acero_testing now link
arrow_compute_core_testing because they use arrow_compute_core_testing.

Sources of testing interface libraries are compiled in unity build
files with test sources. So we need to use a fully qualified name for
MapVector in arrow/compute/test_util_internal.cc. internal:: refers
to arrow::compute::internal:: in unity build files.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
ARROW_BUILD_STATIC=ON doesn't mean that benchmarks are linked
statically. Benchmarks use ARROW_TEST_LINK_LIBS that depends on
ARROW_TEST_LINKAGE. If we use arrow_compute_static with
ARROW_TEST_LINKAGE=shared, both arrow_static and arrow_shared are
linked. It causes duplicated symbol errors on Windows.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@kou
kou force-pushed the ci-windows-build-static branch from 24e1a08 to ee78b4d Compare October 28, 2026 02:46
@kou

kou commented Oct 28, 2026

Copy link
Copy Markdown
Member Author

@github-actions crossbow submit -g cpp

@github-actions

Copy link
Copy Markdown

Revision: ee78b4d

Submitted crossbow builds: ursacomputing/crossbow @ actions-9252eadce2

Task Status
example-cpp-minimal-build-static GitHub Actions
example-cpp-minimal-build-static-system-dependency GitHub Actions
example-cpp-tutorial GitHub Actions
test-build-cpp-fuzz GitHub Actions
test-conda-cpp GitHub Actions
test-conda-cpp-valgrind GitHub Actions
test-debian-13-cpp-amd64 GitHub Actions
test-debian-13-cpp-i386 GitHub Actions
test-debian-experimental-cpp-gcc-15 GitHub Actions
test-fedora-42-cpp GitHub Actions
test-ubuntu-22.04-cpp GitHub Actions
test-ubuntu-22.04-cpp-bundled GitHub Actions
test-ubuntu-22.04-cpp-emscripten GitHub Actions
test-ubuntu-22.04-cpp-no-threading GitHub Actions
test-ubuntu-24.04-cpp GitHub Actions
test-ubuntu-24.04-cpp-gcc-13-bundled GitHub Actions
test-ubuntu-24.04-cpp-gcc-14 GitHub Actions
test-ubuntu-24.04-cpp-minimal-with-formats GitHub Actions
test-ubuntu-24.04-cpp-thread-sanitizer GitHub Actions

@kou kou added the CI: Extra: C++ Run extra C++ CI label Oct 28, 2026
@kou
kou marked this pull request as ready for review October 28, 2026 05:23
Copilot AI balanced review requested due to automatic review settings October 28, 2026 05:24
@kou kou changed the title GH-55279: [C++] Fix a build error with ARROW_BUILD_{SHARED,STATIC,TESTS}=ON on Windows GH-55279: [C++] Fix build errors with ARROW_BUILD_{SHARED,STATIC,TESTS}=ON on Windows Oct 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@kou

kou commented Oct 28, 2026

Copy link
Copy Markdown
Member Author

This is ready.

I think that we should use INTERFACE instead of OBJECT + manual configurations for *_testing CMake targets. If we use INTERFACE, we don't need to set manual configurations because INTERFACE CMake targets use configurations of dependencies automatically.

We need to build the same source files multiple times with INTERFACE but it's not a problem with ccache. We can reuse build results by ccache.

@github-actions github-actions Bot added the awaiting merge Awaiting merge label Oct 28, 2026
Copilot AI balanced review requested due to automatic review settings October 29, 2026 02:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

parquet/arrow/reader.cc uses OpenTelemetry headers via
arrow/util/tracing_internal.h. parquet_static can't find them on
Windows because we don't use a shared object library for shared and
static libraries on Windows.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@kou
kou force-pushed the ci-windows-build-static branch from 1c48296 to a958284 Compare October 29, 2026 03:12
Copilot AI balanced review requested due to automatic review settings October 29, 2026 03:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@github-actions github-actions Bot added awaiting changes Awaiting changes and removed awaiting merge Awaiting merge labels Oct 29, 2026
kou and others added 2 commits October 29, 2026 17:01
Parquet benchmarks used parquet_shared with static test libraries when
ARROW_BUILD_SHARED=ON and ARROW_TEST_LINKAGE=static.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
test_util.cc is compiled as a source of each test executable so that
it uses the same compile definitions as the test.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@kou
kou force-pushed the ci-windows-build-static branch from a958284 to 5756a51 Compare October 29, 2026 08:02
Copilot AI balanced review requested due to automatic review settings October 29, 2026 08:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@github-actions github-actions Bot added awaiting change review Awaiting change review awaiting changes Awaiting changes and removed awaiting changes Awaiting changes awaiting change review Awaiting change review labels Oct 29, 2026
@pitrou

pitrou commented Oct 29, 2026

Copy link
Copy Markdown
Member

We need to build the same source files multiple times with INTERFACE but it's not a problem with ccache. We can reuse build results by ccache.

That doesn't sound great. Not everyone uses ccache I suppose, and it can have limitations too (such as unsupported compile options).

For example, "AMD64 Conda C++ AVX2" used to have 1312 build steps, now it has 1522 build steps...

kou and others added 2 commits October 30, 2026 16:38
Testing libraries link libraries for ARROW_TEST_LINKAGE. So they use
the same compile definitions (e.g. ARROW_STATIC on Windows) as tests
without compiling their sources for each test executable.

arrow_compute_testing is split into arrow_compute_core_testing for
helpers and arrow_compute_testing_main for main(). Only
arrow_compute_testing_main is an interface library because test_env.cc
has main(). If we use a static library, main() in GTest::gmock_main
may be used instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Testing libraries link libraries for ARROW_TEST_LINKAGE. So tests and
benchmarks can just link to them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@kou
kou requested a review from lidavidm as a code owner October 30, 2026 07:45
Copilot AI balanced review requested due to automatic review settings October 30, 2026 07:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@github-actions github-actions Bot added Component: FlightRPC awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Oct 30, 2026
Copilot AI balanced review requested due to automatic review settings October 30, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants