Repository navigation
Fix and cover the windows-static-ssl feature (curl+OpenSSL on Windows) - #666
Open
ns-ylambert wants to merge 5 commits into
Open
ns-ylambert wants to merge 5 commits into
ns-ylambert wants to merge 5 commits into
Conversation
This was referenced Oct 1, 2026
ns-ylambert
force-pushed
the
fix-windows-static-ssl
branch
from
October 2, 2026 08:02
c44bfe5 to
7a9a060
Compare
The `windows-static-ssl` feature (curl+OpenSSL on Windows via vcpkg) has never been exercised in CI since it was introduced in sagebind#466 (2022-09-30): no matrix entry enables it. Add a `win64-static-ssl` matrix entry: - `vcpkg.json` pins `openssl@3.6.4#1` via manifest-mode `overrides`, so silent port bumps from runner-image refreshes don't bleed in. - `vcpkg install --triplet=x64-windows-static-md --x-install-root=...` redirects the manifest-mode install to the classic tree, where curl-sys's `find_package("openssl")` locates it via `VCPKG_ROOT` (aliased from runner- preset `VCPKG_INSTALLATION_ROOT`, which vcpkg-rs doesn't consult directly). - `ci/run.sh` branches on `STATIC_SSL=windows` to set `--features windows-static-ssl --no-default-features` and skip the `rustls` compile-check. - `systest/Cargo.toml` proxies `windows-static-ssl` to `curl-sys`. Existing matrix entries are unaffected. CI run takes an extra ~5–7 min for vcpkg to compile OpenSSL from source (no binary caching yet). This entry compiles cleanly only after the follow-up fixes in this series.
Without caching, the `win64-static-ssl` matrix entry rebuilds OpenSSL from
source on every CI run. vcpkg has built-in binary caching that stores compiled
ports keyed by port + triplet + config + transitive-dep hash. Pair its `files`
backend (writing to a local directory) with `actions/cache` to persist that
directory across CI runs.
Cache key composition:
- `matrix.target` (e.g. x86_64-pc-windows-msvc).
- `hashFiles('vcpkg.json')`: invalidates on dep-list edits or override
version bumps.
- `$ImageVersion`: invalidates on `windows-latest` runner-image refreshes,
which are the source of MSVC / Windows SDK / CMake / vcpkg-tool version
bumps that shift vcpkg's ABI hash. Without this input, an image refresh
would leave the outer key stable while vcpkg's inner cache missed on the
new ABI, silently rebuilding on every run without re-persisting.
Expected runtime:
- Cold cache (first run on main, `vcpkg.json` edit, or runner-image refresh):
~5-7 min (compile + upload).
- Warm cache (typical PR run): <30 sec (restore only).
Cache footprint: ~50 MB per vcpkg build; bounded by GHA's 10 GB per-repo budget
and 7-day inactivity eviction.
`vcpkg::Config::find_package("openssl")` returns a `Library` whose
`include_paths` field carries the vcpkg-provided include directory.
The `windows-static-ssl` branch currently calls `.ok()` on that result,
keeping only the side-effect of `find_package` (`cargo:rustc-link-search=`
+ `cargo:rustc-link-lib=` metadata) and discarding the `Library`. As a
result, `cl`'s command line never receives `-I` include paths, and the C
compile of `openssl.c` (and every crypto helper that transitively includes
`openssl/opensslv.h`) fails with:
fatal error C1083: Cannot open include file: 'openssl/opensslv.h'
Consume the returned `Library` and push each of its `include_paths` into
`cc-rs`'s include list. The `rustc-link-search` / `rustc-link-lib` metadata
is still emitted internally by `find_package`, so linking is unaffected.
Latent since inception. `windows-static-ssl` was introduced in upstream
PR sagebind#466 (2022-09-30, commit b62fa94) with this exact `.ok()` pattern.
Upstream CI (`ci/run.sh`) never exercises the feature and no issues mention
`opensslv.h` or `C1083`, so the gap has stayed uncaught upstream. It would
only "work" for users whose environment already has vcpkg's include directory
on the `INCLUDE` env var via an external mechanism (Developer Command Prompt
setup etc.); this fix makes it work from a clean `cargo build`.
The `windows-static-ssl` branch's OpenSSL discovery is hard-coded to
`vcpkg::Config::new().find_package("openssl").ok()` — no `OPENSSL_DIR`
probe, no include/lib fallback. Users who already have an OpenSSL build
tree available (matched to `openssl-sys`'s standard env-lookup convention)
must install a redundant vcpkg copy just to satisfy this crate.
Probe `<TARGET>_OPENSSL_DIR` first, then plain `OPENSSL_DIR`, matching
openssl-sys's `build/main.rs::env` convention. When either is set, push
`<dir>/include` onto cc-rs's include list and emit
`cargo:rustc-link-search=native=<dir>/lib` + `cargo:rustc-link-lib=libssl`
+ `cargo:rustc-link-lib=libcrypto`. Fall back to the existing vcpkg
openssl probe otherwise. `rerun-if-env-changed` is emitted for both names
either way so the build is invalidated when the env changes.
The two features are mutually exclusive TLS backends for libcurl. One selects
Schannel (via the `ssl` cargo feature on Windows), the other selects OpenSSL
(via `windows-static-ssl`). Upstream's `build.rs` else-if chain checks
`windows-static-ssl` before `ssl`, so with both enabled, the OpenSSL branch
wins and the Schannel branch's setup is dropped on the floor.
The compound fails deterministically upstream with `cl` error:
fatal error C1083: Cannot open include file: 'openssl/opensslv.h'
But the compound stays nonsensical: `ssl` (Schannel) and `windows-static-ssl`
(OpenSSL) can never coexist at the C level. Further OpenSSL discovery does not
fix the compound and the failure mode simply shifts to a different obscure
`cc-rs` / link error.
Add a `compile_error!` in the wrapper crate's `lib.rs` gated on
`all(feature = "ssl", feature = "windows-static-ssl", not(doc))`. It fires when
`rustc` compiles the wrapper crate with both features enabled and replaces the
deep `cc-rs` / link error with a clear one-line diagnostic. No effect on
individual-feature builds: `ssl` or `windows-static-ssl` compile alone cleanly.
The guard sits at the wrapper level because `cargo doc` pre-compiles deps with
`rustc`, which doesn't set `cfg(doc)`: only the top-level crate that `rustdoc`
processes gets the flag.
Under `cargo doc --all-features` the guard is suppressed via `cfg(doc)` so
`rustdoc` sees the union of feature-conditional items across every TLS backend.
`build.rs`'s else-if picks `rustls` first when all three backend features
coexist, so the C build itself remains coherent and docs generation succeeds.
ns-ylambert
force-pushed
the
fix-windows-static-ssl
branch
from
October 12, 2026 18:01
7a9a060 to
d9f3aaa
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds CI coverage for the
windows-static-sslfeature (curl+OpenSSL on Windows via vcpkg) and fixes the latent build regressions that only surface once CI actually exercises the feature.windows-static-sslwas introduced in #466 (2022-09-30) but has never been covered by any matrix entry, so a chain of straightforwardbuild.rsproblems (missing include paths, noOPENSSL_DIRdiscovery) went uncaught since inception.What lands
Four commits, two concerns:
CI coverage (2 commits)
ci: cover windows-static-ssl feature on x86_64-pc-windows-msvc: newwin64-static-sslmatrix entry, manifest-modevcpkg.jsonpinningopenssl@3.6.4#1viabuiltin-baseline+overrides,ci/run.shbranching onSTATIC_SSL=windows,systest/Cargo.tomlfeature proxy.ci: cache vcpkg OpenSSL build via files backend + actions/cache: persistent vcpkg binary cache keyed by (target ×vcpkg.jsonstate × runner image version). Warm cache <30s; cold ~5–7 min.curl-sys/build.rsfixes (2 commits)curl-sys: thread vcpkg include paths into cc-rs on windows-static-ssl: consumefind_package("openssl")'sinclude_pathsand push them onto cc-rs's include list. Without this,clfails withC1083: Cannot open include file: 'openssl/opensslv.h'. Also linksuser32, required by OpenSSL's static libs (OPENSSL_showfatal → MessageBoxA).curl-sys: consult OPENSSL_DIR in the windows-static-ssl branch: env-based OpenSSL discovery (<TARGET>_OPENSSL_DIRthenOPENSSL_DIR), matching openssl-sys's convention. Falls back to the existing vcpkg probe.Not in this PR
Wrapper crate level:
ssl,windows-static-sslfeature combination should be rejected at rustc-compile time with a clearcompile_error!diagnostic (gated onnot(doc)socargo doc --all-featuresstill succeeds). Compound is nonsensical:ssl(Schannel) andwindows-static-ssl(OpenSSL) are mutually exclusive TLS backends at the C level. Nevertheless, theelse ifchain incurl-sys/build.rsalready prioritizeswindows-static-ssloverssl, so the guard could be spurious against other crates forcingcurl/sslvia its own dep declaration, making a conflict unavoidable ifwindows-static-sslis the chosen backend.Verification
Full CI matrix green including the new
win64-static-sslentry running the end-to-end test suite (compile + execute + doctests) against curl+OpenSSL statically linked onwindows-latest. No changes to existing matrix entries' behavior (STATIC_SSLis unset for them; the newci/run.shbranch is inert).Compile-check matrix
cargo check --target x86_64-pc-windows-msvc, standalone build. Rows affected by this PR.mainstatic-curl,windows-static-sslstatic-curl,windows-static-ssl,protocol-ftpstatic-curl,windows-static-ssl,http2static-curl,windows-static-ssl,protocol-ftp,ntlmstatic-curl,windows-static-ssl,ntlmstatic-curl,windows-static-ssl,ntlm,http2static-curl,windows-static-ssl,spnego,ntlmstatic-curl,ssl,windows-static-ssl(compound)¹ CI mode = what
ci/run.shdoes with this combination underSTATIC_SSL=windows.test-executeruns the test binaries,test-compileis--no-run,—means this combo isn't directly exercised by CI but compiles when checked locally.² Orthogonal, fixed with #667.
³ The compound compiles cleanly now. OpenSSL discovery succeeds where it previously failed, so the compound no longer dies at
C1083. What it compiles into is governed by theelse ifchain incurl-sys/build.rs:windows-static-sslwins, the build is curl+OpenSSL, and thessl(Schannel) branch's setup is silently skipped. Onmain, the compound was never machine-rejected as such. Whether that silent skip should instead be an explicitcompile_error!is deliberately out of scope here; see "Not in this PR".Runtime behavior:
ci/run.shsetsCFLAGS=-DCURL_CA_NATIVEfor thewindows-static-sslmatrix entry so curl+OpenSSL consults the Windows native trust store at handshake time. Without it, cert-verifying HTTPS calls in the doctests fail withunable to get local issuer certificateeven though the build compiles.CURL_CA_NATIVEis scoped to CI rather than baked intocurl-sys/build.rsso library consumers retain full control over CA trust configuration (CURLOPT_CAINFO,CURLSSLOPT_NATIVE_CA, or their ownCFLAGS).Related
windows-static-sslfeature, with no CI matrix entry ever catching the latent regressions. This PR is the follow-up that makes it actually usable end-to-end, and adds CI coverage."unable to get local issuer certificate"on FreeBSD 14.3 with curl-sys 0.4.84 (also affected Cargo on FreeBSD per rust-lang/cargo#16357). Same runtime error class as what this PR'sCFLAGS=-DCURL_CA_NATIVECI change fixes forwindows-static-ssl: curl+OpenSSL built without a runtime CA source. Our fix is scoped to thewindows-static-sslCI entry and doesn't touch the FreeBSD path, but the mechanism is identical; extendingCURL_CA_NATIVEto other OpenSSL branches could be a follow-up.Bisect note
The CI-coverage commit lands before the
curl-sys/build.rsfixes, so at that intermediate commitwin64-static-sslstill fails (C1083). Presented as one series for review because each subsequent commit fixes exactly one visible symptom, which reads naturally. If bisect cleanliness is preferred, the CI-coverage commit can be reordered last.