Skip to content

fix: resolve static linking failures with OpenSSL and duplicate symbols#438

Open
dkropachev wants to merge 5 commits into
masterfrom
fix/164-static-linking-openssl
Open

fix: resolve static linking failures with OpenSSL and duplicate symbols#438
dkropachev wants to merge 5 commits into
masterfrom
fix/164-static-linking-openssl

Conversation

@dkropachev

@dkropachev dkropachev commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix the static-linking regressions behind #164 at the installed-package boundary, not just for the in-tree integration binary. The branch now publishes the static driver's transitive link requirements through pkg-config, teaches the package smoke app to consume that metadata safely, removes duplicate testing stubs from the C++ side, and keeps the package CI coverage readable with dedicated static-smoke targets.

Fixes: #164

What Changed

  1. Support installed static consumers and package checks
  • publish transitive static-link dependencies in scylla-cpp-driver_static.pc
  • resolve static pkg-config compile/link flags in the smoke app, including Apple framework flags
  • keep the Windows external OpenSSL path explicit when the static integration build falls back to the vendored project
  • align the package/static-integration checks with the installed artifacts rather than only the in-tree target
  1. Remove duplicate static-integration stubs
  • drop the C++ stubs from src/testing_unimplemented.cpp that are already provided by the Rust integration layer during cpp_integration_testing
  1. Fix Windows OPENSSL_LIBS assembly
  • build OPENSSL_LIBS with an explicit join so openssl-sys receives real library names in package and static-integration builds
  1. Split static package smoke checks into dedicated CI targets
  • add dedicated make targets for static smoke builds/runs
  • call those targets directly from the package workflow instead of threading SCYLLA_SMOKE_BUILD_STATIC=ON through CI YAML

Commit Structure

  • c1eeee8 static linking: support installed consumers and package checks
  • 61d6d5f testing: remove duplicate static-integration stubs
  • 1dd2538 windows: assemble OPENSSL_LIBS from discovered libraries
  • 08cec82 ci: split static package smoke checks into dedicated targets
  • 5f4f201 gitignore: ignore build_static

Testing

  • cmake -S . -B /tmp/cpp-rs-driver-cmake-check -G Ninja -DCMAKE_BUILD_TYPE=Release
  • make check
  • make run-test-unit
  • cmake -S . -B /tmp/cpp-rs-driver-install-build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/tmp/cpp-rs-driver-install-prefix && cmake --build /tmp/cpp-rs-driver-install-build -j 4 && cmake --install /tmp/cpp-rs-driver-install-build
  • PKG_CONFIG_PATH=/tmp/cpp-rs-driver-install-prefix/lib/pkgconfig:/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig cmake -S packaging/smoke-test-app -B /tmp/cpp-rs-driver-smoke-build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSCYLLA_SMOKE_BUILD_STATIC=ON && PKG_CONFIG_PATH=/tmp/cpp-rs-driver-install-prefix/lib/pkgconfig:/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig cmake --build /tmp/cpp-rs-driver-smoke-build -j 4
  • cmake --build build_static -j 4 --target cassandra-integration-tests
  • make -n OS=Windows_NT build-driver CMAKE_BUILD_TYPE=Release | rg "OPENSSL_LIBS|Join\(':', @\("
  • make -n OS=Windows_NT build-static-integration-test-bin | rg "OPENSSL_LIBS|Join\(':', @\("
  • make -n test-package-deb-static-smoke
  • make -n test-package-rpm-native-static-smoke SCYLLA_HOST=scylla SKIP_DOCKER_COMPOSE=1
  • make -n test-package-macos-static-smoke

Pre-review checklist

  • I have split my patch into logically separate commits.
  • All commit messages clearly explain what they change and why.
  • PR description sums up the changes and reasons why they should be introduced.
  • I have implemented Rust unit tests for the features/changes introduced.
  • I have enabled appropriate tests in Makefile in {SCYLLA,CASSANDRA}_(NO_VALGRIND_)TEST_FILTER.
  • I added appropriate Fixes: annotations to PR description.

@dkropachev dkropachev force-pushed the fix/164-static-linking-openssl branch 10 times, most recently from 97356ff to 3b91f17 Compare April 3, 2026 14:02
@dkropachev dkropachev marked this pull request as ready for review April 3, 2026 18:37
@dkropachev dkropachev self-assigned this Apr 3, 2026
@dkropachev

Copy link
Copy Markdown
Contributor Author

I am not sure if I took correct way regarding Duplicate symbol guards.

@wprzytula

wprzytula commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

I am not sure if I took correct way regarding Duplicate symbol guards.

No, it's not correct. The real problem in the first place is is that they are duplicated in the sources. I think a proper solution is to delete them from the testing_unimplemented.cpp. This will resolve the linking issues.

Optionally, we could make the stubs present in integration.rs print an error message and call sysexit. Unfortunately, throwing C++ exceptions is not possible from pure Rust with C FFI. @Lorak-mmk Should we bother with this?

@Lorak-mmk

Copy link
Copy Markdown
Contributor

No, it's not correct. The real problem in the first place is is that they are duplicated in the sources. I think a proper solution is to delete them from the testing_unimplemented.cpp. This will resolve the linking issues.

Agreed.

@Lorak-mmk Should we bother with this?

Do we need to? Can't we use the stubs from integration.rs?

@wprzytula

Copy link
Copy Markdown
Contributor

@Lorak-mmk Should we bother with this?

Do we need to? Can't we use the stubs from integration.rs?

I do propose using stubs from integration.rs. Additionally, I say that optionally we can make them call sysexit. Currently, they are just no-ops. The stubs in testing_unimplemented.cpp have a nice feature of throwing an exception, which fails nonsupported tests with a meaningful message.
But perhaps it's not important at all that nonsupported tests throw such exception / end in a distinctive way. I think so. Let's not bother.

@Lorak-mmk

Copy link
Copy Markdown
Contributor

Sysexit or other abort method sounds reasonable.

@dkropachev

Copy link
Copy Markdown
Contributor Author

Guys, could you please tell me what to do with the pr

@Lorak-mmk

Copy link
Copy Markdown
Contributor

Section "Fix: Duplicate symbol guards (src/testing_unimplemented.cpp)" should be reverted. The correct fix is to remove those symbols from testing_unimplemented.cpp

@wprzytula wprzytula 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.

Please improve commit messages. I can't read them.

Comment thread .github/workflows/build-cpack-packages.yml
Comment thread Makefile
@dkropachev dkropachev force-pushed the fix/164-static-linking-openssl branch 2 times, most recently from 5f4f201 to 621b995 Compare April 9, 2026 02:42
@wprzytula

Copy link
Copy Markdown
Contributor

Commit Structure

* `c1eeee8` `static linking: support installed consumers and package checks`

* `61d6d5f` `testing: remove duplicate static-integration stubs`

* `1dd2538` `windows: assemble OPENSSL_LIBS from discovered libraries`

* `08cec82` `ci: split static package smoke checks into dedicated targets`

* `5f4f201` `gitignore: ignore build_static`

What's the point of including this in the cover letter?

  • I can see such list in the Commits tab anyway.
  • There's 0 additional info here.

Comment thread .github/workflows/build-cpack-packages.yml Outdated
Comment thread .github/workflows/build-cpack-packages.yml
Comment thread .github/workflows/build-cpack-packages.yml
@dkropachev dkropachev force-pushed the fix/164-static-linking-openssl branch 2 times, most recently from 15203e1 to 391f3b5 Compare April 30, 2026 13:58
Publish transitive dependencies for the static driver in generated
pkg-config metadata. Teach the smoke app to consume static pkg-config
output safely, and add package-level/static-integration checks that
exercise the installed artifacts.

This keeps installed static consumers aligned with the in-tree target.
It also makes the Windows OpenSSL external-project path explicit
during static integration builds.
The Rust integration layer already provides these test-only symbols when cpp_integration_testing is enabled. Drop the duplicate C++ stubs from testing_unimplemented.cpp so static integration builds link against a single definition.
Build the OPENSSL_LIBS environment variable with an explicit join instead of relying on PowerShell interpolation. This keeps openssl-sys from seeing a literal variable name in package and static-integration builds.
Split the static driver build from the static integration-test build and share the configured build directory setup. This keeps the static integration target focused on building and probing the test binary.
Add dedicated static-smoke make targets and call them directly from the package workflow. This keeps CI failures scoped to one smoke mode and avoids threading SCYLLA_SMOKE_BUILD_STATIC through the dynamic package checks.
@dkropachev dkropachev force-pushed the fix/164-static-linking-openssl branch from 391f3b5 to 015dd2c Compare April 30, 2026 15:04
@dkropachev dkropachev requested a review from wprzytula April 30, 2026 15:12
@dkropachev

Copy link
Copy Markdown
Contributor Author

@wprzytula , @Lorak-mmk , ping

@wprzytula wprzytula 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.

I have hard time grasping this PR, because some commits are bags of loosely-related changes. Please split into smaller commits, with proper exhaustive explanation of the changes in the commit messages.

Commit windows: assemble OPENSSL_LIBS from discovered libraries is a good example - there is a single change + an explanation why, what is done, and how it works now.

Comment on lines 14 to 396
@@ -384,9 +385,14 @@ test-app-package: .prepare-for-test
@pwsh.exe -NoProfile -Command "\
\$$ErrorActionPreference = 'Stop'; \
\$$composeFile = '${MAKEFILE_PATH}/../../tests/examples_cluster/docker-compose.yml'; \
\$$smokePaths = @('$(SMOKE_TEST_INSTALL_PATH)\bin\scylla-cpp-driver-smoke-test.exe'); \
\$$smokePaths = @(); \
if ('$(SCYLLA_SMOKE_ONLY_STATIC)' -ne 'ON') { \
\$$smokePaths += '$(SMOKE_TEST_INSTALL_PATH)\bin\scylla-cpp-driver-smoke-test.exe'; \
}; \
if ('$(SCYLLA_SMOKE_BUILD_STATIC)' -eq 'ON') { \
\$$smokePaths += '$(SMOKE_TEST_INSTALL_PATH)\bin\scylla-cpp-driver-smoke-test-static.exe'; \
} elseif ('$(SCYLLA_SMOKE_ONLY_STATIC)' -eq 'ON') { \
throw 'SCYLLA_SMOKE_ONLY_STATIC requires SCYLLA_SMOKE_BUILD_STATIC=ON'; \
}; \

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.

🔧 I dislike that building static smoke app is opt-in, but building dynamic smoke app is opt-out. Please use opt-in for both, e.g., SCYLLA_SMOKE_BUILD_STATIC and SCYLLA_SMOKE_BUILD_DYNAMIC.

Comment on lines -12 to 15
# TODO: Remove `build/libscylla-cpp-driver.*` after https://github.com/scylladb/cpp-rs-driver/issues/164 is fixed.
INTEGRATION_TEST_BIN: |
build/cassandra-integration-tests
build/libscylla-cpp-driver.*

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.

🤔 You removed the TODO but didn't do what it was saying.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Move it out ot a separate commit with explanation.

Comment thread Makefile
@cd "${BUILD_DIR}"
cmake -DCASS_BUILD_INTEGRATION_TESTS=ON -DCMAKE_BUILD_TYPE=Release .. && (make -j 4 || make)

STATIC_BUILD_DIR := $(CURRENT_DIR)build-static

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.

♻️ This should be put along other constants in this file (next to BUILD_DIR).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread Makefile Outdated
Comment on lines +280 to +318
build-static-integration-test-bin:
ifeq ($(OS_TYPE),windows)
$(MAKE) .package-build-prepare-windows
cmake -S . -B build-static -G "Visual Studio 17 2022" -A x64 -DCASS_BUILD_INTEGRATION_TESTS=ON -DCASS_USE_STATIC_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DOPENSSL_VERSION=$(OPENSSL_WIN_VERSION)
@pwsh -NoProfile -Command "\
$$useExternalOpenSSL = ((Select-String -Path 'build-static\\CMakeCache.txt' -Pattern '^SCYLLA_OPENSSL_EXTERNAL_PROJECT:BOOL=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
$$externalOpenSSLTarget = ((Select-String -Path 'build-static\\CMakeCache.txt' -Pattern '^SCYLLA_OPENSSL_EXTERNAL_TARGET:STRING=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
if ($$useExternalOpenSSL -eq 'ON' -and $$externalOpenSSLTarget) { \
cmake --build build-static --config Release --target $$externalOpenSSLTarget; \
if ($$LASTEXITCODE -ne 0) { exit $$LASTEXITCODE } \
}; \
$$opensslIncDir = ((Select-String -Path 'build-static\\CMakeCache.txt' -Pattern '^OPENSSL_INCLUDE_DIR:PATH=' | Select-Object -First 1).Line -split '=', 2)[1]; \
$$opensslSslLibPath = ((Select-String -Path 'build-static\\CMakeCache.txt' -Pattern '^OPENSSL_SSL_LIBRARY(_RELEASE)?:FILEPATH=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
$$opensslCryptoLibPath = ((Select-String -Path 'build-static\\CMakeCache.txt' -Pattern '^OPENSSL_CRYPTO_LIBRARY(_RELEASE)?:FILEPATH=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
if ($$opensslIncDir) { \
$$env:OPENSSL_DIR = (Split-Path $$opensslIncDir -Parent); \
$$env:OPENSSL_INCLUDE_DIR = $$opensslIncDir; \
if (-not $$opensslSslLibPath) { \
$$opensslSslLibPath = (Get-ChildItem -Path $$env:OPENSSL_DIR -Recurse -Include 'libssl*.lib','ssleay32*.lib' -File -ErrorAction SilentlyContinue | Select-Object -First 1).FullName; \
} \
if (-not $$opensslCryptoLibPath) { \
$$opensslCryptoLibPath = (Get-ChildItem -Path $$env:OPENSSL_DIR -Recurse -Include 'libcrypto*.lib','libeay32*.lib' -File -ErrorAction SilentlyContinue | Select-Object -First 1).FullName; \
} \
$$opensslLibPath = if ($$opensslSslLibPath) { $$opensslSslLibPath } elseif ($$opensslCryptoLibPath) { $$opensslCryptoLibPath } else { '' }; \
if ($$opensslLibPath) { \
$$env:OPENSSL_LIB_DIR = Split-Path $$opensslLibPath -Parent; \
} else { \
$$env:OPENSSL_LIB_DIR = Join-Path $$env:OPENSSL_DIR 'lib'; \
} \
if ($$opensslSslLibPath -and $$opensslCryptoLibPath) { \
$$opensslSslLibName = [System.IO.Path]::GetFileNameWithoutExtension($$opensslSslLibPath); \
$$opensslCryptoLibName = [System.IO.Path]::GetFileNameWithoutExtension($$opensslCryptoLibPath); \
$$env:OPENSSL_LIBS = \"$$opensslSslLibName`:`$$opensslCryptoLibName\"; \
} \
}; \
cmake --build build-static --config Release; \
if ($$LASTEXITCODE -ne 0) { exit $$LASTEXITCODE } \
"
build-static\Release\cassandra-integration-tests.exe --gtest_list_tests > NUL

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.

🔧 This is some enormous gibberish, without a single comment explaining it.

Comment thread Makefile
.package-configure: .package-build-prepare
ifeq ($(OS_TYPE),windows)
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DOPENSSL_VERSION=1.1.1u $(CMAKE_FLAGS)
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DOPENSSL_VERSION=$(OPENSSL_WIN_VERSION) $(CMAKE_FLAGS)

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.

♻️ Extracting this should constitute a separate refactor commit, to reduce stress on the reviewers'/readers' context window.

Comment thread Makefile
Comment on lines 403 to +438
build-driver: .package-configure
ifeq ($(OS_TYPE),windows)
@pwsh -NoProfile -Command "$$opensslVersion = ((Select-String -Path 'build\\CMakeCache.txt' -Pattern '^OPENSSL_VERSION:STRING=' | Select-Object -First 1).Line -split '=', 2)[1]; $$opensslTarget = \"openssl-$${opensslVersion}-library\"; cmake --build build --config $(CMAKE_BUILD_TYPE) --target $$opensslTarget; $$env:OPENSSL_DIR = (Resolve-Path 'build\\libs\\openssl').Path; $$env:OPENSSL_INCLUDE_DIR = \"$$env:OPENSSL_DIR\\include\"; $$env:OPENSSL_LIB_DIR = \"$$env:OPENSSL_DIR\\lib\"; cmake --build build --config $(CMAKE_BUILD_TYPE)"
@pwsh -NoProfile -Command "\
$$useExternalOpenSSL = ((Select-String -Path 'build\\CMakeCache.txt' -Pattern '^SCYLLA_OPENSSL_EXTERNAL_PROJECT:BOOL=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
$$externalOpenSSLTarget = ((Select-String -Path 'build\\CMakeCache.txt' -Pattern '^SCYLLA_OPENSSL_EXTERNAL_TARGET:STRING=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
if ($$useExternalOpenSSL -eq 'ON' -and $$externalOpenSSLTarget) { \
cmake --build build --config $(CMAKE_BUILD_TYPE) --target $$externalOpenSSLTarget; \
if ($$LASTEXITCODE -ne 0) { exit $$LASTEXITCODE } \
}; \
$$opensslIncDir = ((Select-String -Path 'build\\CMakeCache.txt' -Pattern '^OPENSSL_INCLUDE_DIR:PATH=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
$$opensslSslLibPath = ((Select-String -Path 'build\\CMakeCache.txt' -Pattern '^OPENSSL_SSL_LIBRARY(_RELEASE)?:FILEPATH=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
$$opensslCryptoLibPath = ((Select-String -Path 'build\\CMakeCache.txt' -Pattern '^OPENSSL_CRYPTO_LIBRARY(_RELEASE)?:FILEPATH=' -ErrorAction SilentlyContinue | Select-Object -First 1).Line -split '=', 2)[1]; \
if ($$opensslIncDir) { \
$$env:OPENSSL_DIR = (Split-Path $$opensslIncDir -Parent); \
$$env:OPENSSL_INCLUDE_DIR = $$opensslIncDir; \
if (-not $$opensslSslLibPath) { \
$$opensslSslLibPath = (Get-ChildItem -Path $$env:OPENSSL_DIR -Recurse -Include 'libssl*.lib','ssleay32*.lib' -File -ErrorAction SilentlyContinue | Select-Object -First 1).FullName; \
} \
if (-not $$opensslCryptoLibPath) { \
$$opensslCryptoLibPath = (Get-ChildItem -Path $$env:OPENSSL_DIR -Recurse -Include 'libcrypto*.lib','libeay32*.lib' -File -ErrorAction SilentlyContinue | Select-Object -First 1).FullName; \
} \
$$opensslLibPath = if ($$opensslSslLibPath) { $$opensslSslLibPath } elseif ($$opensslCryptoLibPath) { $$opensslCryptoLibPath } else { '' }; \
if ($$opensslLibPath) { \
$$env:OPENSSL_LIB_DIR = Split-Path $$opensslLibPath -Parent; \
} else { \
$$env:OPENSSL_LIB_DIR = Join-Path $$env:OPENSSL_DIR 'lib'; \
} \
if ($$opensslSslLibPath -and $$opensslCryptoLibPath) { \
$$opensslSslLibName = [System.IO.Path]::GetFileNameWithoutExtension($$opensslSslLibPath); \
$$opensslCryptoLibName = [System.IO.Path]::GetFileNameWithoutExtension($$opensslCryptoLibPath); \
$$env:OPENSSL_LIBS = \"$$opensslSslLibName`:`$$opensslCryptoLibName\"; \
} \
}; \
cmake --build build --config $(CMAKE_BUILD_TYPE); \
if ($$LASTEXITCODE -ne 0) { exit $$LASTEXITCODE } \
"

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.

😕 Again enormous gibberish without explanation.

Is it about:

It also makes the Windows OpenSSL external-project path explicit during static integration builds.

?

If so, then PLEASE keep your commits logically separate. I struggle so much to understand the purpose and meaning of all these changes...

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.

I suppose it's feasible to keep Windows OpenSSL external-project path-related changes in a separate commit, as they are orthogonal to other changes.

Comment thread Makefile
bash -c ' \
set -euo pipefail; \
dnf -y install make cmake gcc-c++ findutils rpm-build; \
dnf -y install make cmake gcc-c++ findutils rpm-build zlib-devel; \

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.

❓ I don't see how adding this is related to this commit.

Comment thread Makefile
Comment on lines 655 to +667
if [ -z "$$smoke_bin" ]; then \
echo "ERROR: smoke-test binary not found"; \
exit 1; \
fi; \
"$$smoke_bin" 127.0.0.1 \
"$$smoke_bin" 127.0.0.1; \
if [ "$(SCYLLA_SMOKE_BUILD_STATIC)" = "ON" ]; then \
smoke_static_bin=$$(find /usr -name "scylla-cpp-driver-smoke-test-static" -type f 2>/dev/null | head -1); \
if [ -z "$$smoke_static_bin" ]; then \
echo "ERROR: static smoke-test binary not found"; \
exit 1; \
fi; \
"$$smoke_static_bin" 127.0.0.1; \
fi \

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.

♻️ Instead of treating static build specially, I'd explicitly divide test targets into the dynamic and the static cases. This would be more explicit and intuitive.

Comment thread .gitignore
.vscode/
.zed
build/
build-static/

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.

🔧 This is added to .gitignore only in commit makefile: factor static build targets, but the first commit already mentions this path.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes static-linking regressions (issue #164) by ensuring the driver’s static build publishes its transitive link requirements to installed consumers (pkg-config), aligning smoke/package checks with installed artifacts, and removing duplicate integration-test stubs that caused symbol clashes.

Changes:

  • Publish static transitive dependencies via scylla-cpp-driver_static.pc and wire the smoke app to consume pkg-config --static metadata (including macOS framework flags).
  • Remove duplicate C++ “unimplemented” stubs that are already provided by the Rust integration testing layer.
  • Improve CI/build tooling for static linking (Windows OpenSSL env assembly, dedicated static smoke targets, and added static regression checks in workflows).

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/src/integration/CMakeLists.txt Adjusts link order for integration tests and adds libuv ExternalProject dependency handling.
src/testing_unimplemented.cpp Removes duplicate stub symbols to prevent duplicate-definition/link issues.
scylla-rust-wrapper/scylla-cpp-driver_static.pc.in Switches static pkg-config metadata to use computed Requires.private / Libs.private.
scylla-rust-wrapper/CMakeLists.txt Adds transitive link deps for the static imported target and populates pkg-config substitution variables.
packaging/smoke-test-app/Makefile Extends package test runner to optionally run static smoke binaries and cleans up static artifacts.
packaging/smoke-test-app/CMakeLists.txt Adds robust static pkg-config flag resolution/parsing to build a fully-static smoke binary.
Makefile Introduces dedicated static integration build targets, improves Windows OpenSSL env handling, and adds static smoke/package targets.
cmake/FindOPENSSL.cmake Expands Windows/MSVC OpenSSL search paths to cover arch/RT-mode subdirs.
cmake/ExternalProject-OpenSSL.cmake Exposes cache metadata indicating when OpenSSL is built via ExternalProject and its target name.
cmake/Dependencies.cmake Initializes OpenSSL ExternalProject indicator variables for consumers that inspect the cache.
.gitignore Ignores the new build-static/ directory.
.github/workflows/build-lint-and-test.yml Adds a static-link build regression step for issue #164.
.github/workflows/build-cpack-packages.yml Adds static smoke verification and static-link regression steps across package workflows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

wprzytula added a commit that referenced this pull request Jun 8, 2026
This PR extracts one commit from #438 in order to merge it without
further delay. It's authored by @dkropachev.
Original description:

> The Rust integration layer already provides these test-only symbols
when cpp_integration_testing is enabled. Drop the duplicate C++ stubs
from testing_unimplemented.cpp so static integration builds link against
a single definition.
@wprzytula wprzytula mentioned this pull request Jun 15, 2026
4 tasks
wprzytula added a commit that referenced this pull request Jun 15, 2026
### What's done

Place the driver target before `CASS_LIBS` in `target_link_libraries`
for integration tests. With static linking the linker resolves symbols
left-to-right, so the archive providing symbols must precede the
libraries that define them.

It's fascinating that the bug comes from the DataStax CPP Driver's build
system. They must have never tested static linkage with integration
tests.

### Verification

```sh
cmake\
-DCASS_BUILD_INTEGRATION_TESTS=ON \
-DCASS_USE_STATIC_LIBS=ON \
-B build \
&& (cd build && make)
```
now works. Before, it would fails with undefined references to OpenSSL
symbols.

### Further work

#438 apart of containing this fix, introduced **a lot** of changes and
static linkage verification using the smoke test app. I'm working on
making the changes more granular, better documented, and hence mergable.

Fixes: #164
wprzytula added a commit that referenced this pull request Jun 16, 2026
Fixes: #455

## Problem recap

#455 correctly observed that linking the static driver library included
in release 1.0.0 (1.0.1 is also impacted) against an older OpenSSL
fails, because the lib has undefined symbols that are only supplied by
OpenSSL 3.3/3.4/3.5 or newer. Considering our OpenSSL minimum
requirements is 3.0.2 (should be enough - this is present on Ubuntu
22.04, so quite an old one), this should be considered a bug in our
build/release CI.

There are three problems in particular:

#### Problem 1: We have built packages with **_too new_** OpenSSL
headers.

This led to including functions not available at 3.0.x as unresolved
symbols.

#### Problem 2: We haven't verified that the released packages link
against OpenSSL 3.0.x correctly.

#### Problem 3: We didn't put any build info manifest in the released
package.
This @vladzcloudius noted in #455 as the minimum to address the issue.

## Solution

### Problem 2: OpenSSL 3.0.2 linking verification

This PR introduces an OpenSSL verification Makefile recipe. Outline:
1. copy the already-built static archive and pkg-config metadata into a
sysroot;
2. alongside, put OpenSSL 3.0.2 headers and static libraries from a
pinned Launchpad deb;
    3. attempt to compile and link `examples/ssl/ssl.c`.
    
If the build environment was contaminated (e.g. by a newer OpenSSL with
IDEA or 3.3+ APIs), the archive will contain symbol references that
don't exist in OpenSSL 3.0 and the link will fail — catching the
regression from issue #455.
    
The verification runs in both PR CI (after `build-integration-test-bin`)
and packaging CI (after `test-package-deb`), since both produce the
static archive in `build/`.


### Problem 1: _too new_ OpenSSL in the building/packaging CI workflow

The plot twist is that one week after we released 1.0.1 with **no**
support for OpenSSL 3.0.x, once I freshly rebuilt the 1.0.1 package (in
the same CI workflow) and attempted linkage against OpenSSL 3.0.2 using
the new verification procedure, **it succeeded**. Investigation revealed
that the fresh lib has much different _cgus_ (compile gen units) -
different number and sizes. Most likely explanation: LTO in the Rust
toolchain improved during that week, fixing the problem in our
building/packaging CI.

If the problem happens to strike back, our verification step will
immediately catch it. We're thus guarded and safe.

### Problem 3: lack of build info in the package

It makes sense to generate plaintext build info manifest (`Key: Value`
lines) during build and put it in the built dev package. Exact contents
of this build info is subject to discussion; this PR introduces what
Opus came up with (and I believe it's a fine list of properties).

## PR contents in detail

### First 3 commits

They are extracted from #438. These are small fixes.

### Next 3 commits

Also extracted from #438.

1. Adds comments to existing logic in
`scylla-rust-wrapper/CMakeLists.txt`.
2. Registers transitive deps for the driver in the CMake dep resolution
subsystem, so that those who use the driver as a CMake dependency will
get driver's deps pulled in into the dependency graph, resulting in
correct linker invocation.
3. Publishes transitive deps in `scylladb_static.pc` (`pkg-config`
manifest). This supports a common (according to my research) way that
people configure their compiler & linker. More details in the commit
message.

### Next commit

Introduces the OpenSSL 3.0.2 compatibility verification, described
earlier.

### Last 2 commits

Introduce `BUILD_INFO` generation and include it in the generated `dev`
packages. This addresses the main request of #455.

<details><summary>`BUILD_INFO` contents when built on my
machine:</summary>
<p>
Build Information for scylla-cpp-driver v1.0.0-145-g541cb277

Platform
--------
OS:             Ubuntu 25.10
Architecture:   x86_64
Kernel:         6.17.0-35-generic
glibc:          2.42

Toolchain
---------
Rust:           rustc 1.96.0 (ac68faa20 2026-05-25)
Cargo:          cargo 1.96.0 (30a34c682 2026-05-25)
CMake:          cmake version 3.31.6
CC:             cc (Ubuntu 15.2.0-4ubuntu4) 15.2.0

OpenSSL (detected by openssl-sys at build time)
------------------------------------------------
Version:        3.5.0
Include path:   /usr/include
Disabled (osslconf): OPENSSL_NO_IDEA OPENSSL_NO_SSL3_METHOD

Build Configuration
-------------------
CMAKE_BUILD_TYPE:       Release
CMAKE_INSTALL_PREFIX:   /usr
CASS_BUILD_SHARED:      ON
CASS_BUILD_STATIC:      ON
LTO:                    true
Panic strategy:         abort

Static Library Compatibility Notes
----------------------------------
The static archive (libscylladb_static.a) requires consumers to
provide OpenSSL >= 3.0 at link time. The minimum OpenSSL version
is determined by the build-time detection performed by the
openssl-sys crate.

Consumers linking on systems with a different OpenSSL configuration
(e.g. different osslconf flags) may encounter undefined symbol errors
for conditionally-compiled functions.
</p>
</details>


<details><summary>`BUILD_INFO` contents when built in the CI:</summary>
<p>

Build Information for scylla-cpp-driver 6eff933

Platform
--------
OS:             Ubuntu 22.04.5 LTS
Architecture:   x86_64
Kernel:         6.8.0-1052-azure
glibc:          2.35
unknown

Toolchain
---------
Rust:           rustc 1.96.0 (ac68faa20 2026-05-25)
Cargo:          cargo 1.96.0 (30a34c682 2026-05-25)
CMake:          cmake version 3.31.6
CC:             cc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

OpenSSL (detected by openssl-sys at build time)
------------------------------------------------
Version:        3.0.2
Include path:   /usr/include
Disabled (osslconf): unknown (openssl-sys build output not found)

Build Configuration
-------------------
CMAKE_BUILD_TYPE:       Release
CMAKE_INSTALL_PREFIX:   /usr
CASS_BUILD_SHARED:      ON
CASS_BUILD_STATIC:      ON
LTO:                    true
Panic strategy:         abort

Static Library Compatibility Notes
----------------------------------
The static archive (libscylladb_static.a) requires consumers to
provide OpenSSL >= 3.0 at link time. The minimum OpenSSL version
is determined by the build-time detection performed by the
openssl-sys crate.

Consumers linking on systems with a different OpenSSL configuration
(e.g. different osslconf flags) may encounter undefined symbol errors
for conditionally-compiled functions.


</p>
</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make -DCASS_BUILD_INTEGRATION_TESTS=ON -DCASS_USE_STATIC_LIBS=ON work

4 participants