Skip to content

cmake: add CMake Config-based dependency detection#20814

Closed
vszakats wants to merge 36 commits intocurl:masterfrom
vszakats:cm-chain-config
Closed

cmake: add CMake Config-based dependency detection#20814
vszakats wants to merge 36 commits intocurl:masterfrom
vszakats:cm-chain-config

Conversation

@vszakats
Copy link
Copy Markdown
Member

@vszakats vszakats commented Mar 4, 2026

After limiting find_package()/find_dependency() calls to curl local
Find modules via the MODULES keyword, it became possible to detect
dependencies via CMake Configs from within those local Find modules, by
calling find_package() again with the CONFIG keyword. This patch
implements this. Then maps detection results to the result variables and
curl-specific imported targets the rest of the build expects.

Also honor recently introduced *_USE_STATIC_LIBS (experimental) flags
to map to the static target when requested.

This adds CMake Configs as an alternative to the existing pkg-config
and find_path()/find_library() auto-detection methods.

Enabled by default for MSVC, outside vcpkg and when not cross-building.
To enable for other cases, or override the default, you can use
-DCURL_USE_CMAKECONFIG=ON or OFF.

When enabled, Config detection happens after pkg-config and before
find_path()/find_library(). Using CMake's built-in options, you may
also manually point to the absolute directory holding Config files:

Libssh2_DIR, MbedTLS_DIR, NGHTTP2_DIR, NGHTTP3_DIR,
NGTCP2_DIR v1.19.0+ (with non-fork OpenSSL only), Zstd_DIR v1.4.5+

E.g. -DMbedTLS_DIR=/path/to/mbedtls/lib/cmake/MbedTLS

These dependencies typically need to be built with CMake to support
this.

Tagged as experimental.

Refs:
#20013 #19156 #19117
#20784 (comment)

Depends-on: fad1eba #20840
Follow-up to 91e06fd #20784
Follow-up to 26c39d8 #20015


https://github.com/curl/curl/pull/20814/files?w=1

  • whether/how to control priority? (honor CMAKE's PREFER_CONFIG option?)
  • rebase on cmake: resolve imported targets recursively when generating libcurl.pc #20840.
  • switch default to OFF, initially. Maybe default ON on Windows?
  • always switch off for cmake-vs-configure CI job. Configs may and
    do detect deps at different locations than pkg-config does in configure.
    Making the test fail.
  • make a list of deps that support this (and since which versions)?
    nghttp2, nghttp3, ngtcp2 1.19.0+ (partial), MbedTLS, libssh2, ?
    (also ZLIB, but curl uses the CMake Find module.)
  • add for the rest
  • test locally?
  • test in CI?

This may also be a way to add support to curl Find modules for using
cmake Configs (in addition to existing pkg-config and raw/manual
detection). Which in turn may help with static builds. When using
MODULE, it's guaranteed to hit curl's Find module first without using
Configs, then the Find module may possibly use a find_package()
limited to Configs, effectively "chaining" them. Then the curl logic
needs to create aliases to map the found targets to the CURL::
namespaced ones, and possibly do other things to make those targets
compatible with the rest of the build. I have made minimal tests, so
it's mostly theory at this point.

@vszakats vszakats marked this pull request as draft March 4, 2026 11:39
@github-actions github-actions bot added the tests label Mar 5, 2026
@vszakats vszakats changed the title [WIP] zstd: CMake Config detection proof-of-concept / experiment cmake: add CMake Config-based dependency detection Mar 5, 2026
@vszakats vszakats added the feature-window A merge of this requires an open feature window label Mar 5, 2026
@vszakats vszakats force-pushed the cm-chain-config branch 2 times, most recently from 70a8283 to 316eab6 Compare March 5, 2026 19:05
@github-actions github-actions bot added the CI Continuous Integration label Mar 5, 2026
vszakats added a commit to vszakats/curl that referenced this pull request Mar 6, 2026
To allow simplifying the binutils ld hack, by chaining the original
imported target to curl's local duplicate target. Also to allow linking
to dependencies' native imported targes via their CMake Configs, which
may similarly be chained by default.

Fixing (seen on Linux with simplified binutils hack via curl#20839):
```
 Requires:
 Requires.private: libzstd openssl zlib
 Libs: -L${libdir} -lcurl
-Libs.private:  -lcrypto -lssl -lz -lzstd
+Libs.private:  -lOpenSSL::Crypto -lZLIB::ZLIB -lcrypto -lssl -lz -lzstd
 Cflags: -I${includedir}
 Cflags.private: -DCURL_STATICLIB
Error: Process completed with exit code
```
Ref: https://github.com/curl/curl/actions/runs/22768301699/job/66041980258?pr=20839

Cherry-picked from curl#20814
Cherry-picked from curl#20839
@vszakats vszakats force-pushed the cm-chain-config branch 2 times, most recently from 2cc2dd7 to f9313c3 Compare March 6, 2026 23:47
@vszakats vszakats marked this pull request as ready for review March 7, 2026 09:38
vszakats added a commit that referenced this pull request Mar 16, 2026
To allow simplifying the binutils ld hack, by chaining the original
imported target to curl's local duplicate target. Also to allow linking
to dependencies' native imported targets via their CMake Configs, which
will always be hooked up to a `CURL::` interface, and may also be
chained upstream.

Fixing (seen on Linux with simplified binutils hack via #20839):
```
 Requires:
 Requires.private: libzstd openssl zlib
 Libs: -L${libdir} -lcurl
-Libs.private:  -lcrypto -lssl -lz -lzstd
+Libs.private:  -lOpenSSL::Crypto -lZLIB::ZLIB -lcrypto -lssl -lz -lzstd
 Cflags: -I${includedir}
 Cflags.private: -DCURL_STATICLIB
Error: Process completed with exit code
```
Ref: https://github.com/curl/curl/actions/runs/22768301699/job/66041980258?pr=20839

Note this makes it possible to run into an infinite loop because CMake
allows cyclic dependencies. It isn't added by curl's CMake script nor by
any dependencies as defined by default, but may happen in theory with
custom-created targets. In such case CMake automatically stops with
an error at 1000 iterations. I find it overkill to add custom protection
for it.

Cherry-picked from #20814
Cherry-picked from #20839

Closes #20840
vszakats added 11 commits March 21, 2026 16:50
- [ ] how to control priority? (honor CMAKE's PREFER_CONFIG option?)
- [ ] switch default to OFF, initially.
- [ ] make a list of deps that support this (and since which versions)
- [ ] add for the rest
- [ ] test locally?
- [ ] test in CI?

This may also be a way to add support to curl Find modules for using
cmake Configs (in addition to existing `pkg-config` and raw/manual
detection). Which in turn may help with static builds. When using
MODULE, it's guaranteed to hit curl's Find module first without using
Configs, then the Find module may possibly use a `find_package()`
limited to Configs, effectively "chaining" them. Then the curl logic
needs to create aliases to map the found targets to the `CURL::`
namespaced ones, and possibly do other things to make those targets
compatible with the rest of the build. I have made minimal tests, so
it's mostly theory at this point.

curl#20784 (comment)

Refs:
curl#20013
curl#19117
curl#19156
Not quite sure why Zstd detection is attempted twice:

Linux / find_package() OpenSSL with old cmake (3.19.8):
```
-- Found Zstd: /usr/include (found version "1.5.5")
-- Found Libpsl (via pkg-config): /usr/include (found version "0.21.2")
CMake Error at bld-curl/_pkg/lib/cmake/CURL/FindZstd.cmake:77 (add_library):
  add_library cannot create ALIAS target "CURL::zstd" because target
-- Found Zstd (via CMake Config):  (found version "")
  "zstd::libzstd" does not already exist.
Call Stack (most recent call first):
  /home/runner/cmake-3.19.8-Linux-aarch64/share/cmake-3.19/Modules/CMakeFindDependencyMacro.cmake:47 (find_package)
  bld-curl/_pkg/lib/cmake/CURL/CURLConfig.cmake:173 (find_dependency)
  CMakeLists.txt:44 (find_package)
```
https://github.com/curl/curl/actions/runs/22667740285/job/65703660395?pr=20814
QUIET avoid these lines when a Config isn't found:
```
-- Could NOT find nghttp2 (missing: nghttp2_DIR)
```
vszakats added 18 commits March 21, 2026 16:50
This reverts commit 3850173.
CMake Config-based detection makes the results incomparable to
configure, because the latter doesn't support this method, and CMake
Config may end up with slighty different detection result even for the
very same package. (as seen in Homebrew, where pkg-config finds zstd at
a different alias of the same location, than CMake Config.)

pkg-config:
```
libdir: /opt/homebrew/opt/zstd/lib
lib: zstd
```

CMake Config:
```
lib: /opt/homebrew/lib/libzstd.1.5.7.dylib
```
(extracted libdir is dropped from .pc output because its a system libdir)
This reverts commit 8386fa7cff243baa1ab0b1df66677dd4ffd10398.
This comes with:
a) a risk that it breaks something if it not working correctly.
   e.g. the Config is detected, but unusable. This can happen if
   the curl Find module forgot to account for a target not present
   in certain dep versions, but wanting to use it later on.
   This may shadow an otherwise correct pkg-config or manual
   detection and turn the detection into a failure.
   It may also be possible a Config removes something that existed,
   with similar effect, but unpredictable.
   In such case the option may be forced off.
b) a higher chance of using a CMake Config, which if working
   correctly, offers a better control over shared/static selection,
   and may possibly have a fresher, accurate set of setting than
   pkg-config or manual detection could have.

With current CMAKECONFIG / PKGCONFIG defaults both option are not
enabled at the same time by default. vcpkg uses pkg-config by default,
non-Windows uses pkg-config (on conditions), on Windows, mingw uses
pkg-config, and MSVC uses CMake Config.

If we get reports of issues with of this setup, here are some ways
to improve it:

- introduce a joint option `CURL_FIND_METHOD=<list>` where list
  may contain none, one or both of `pkgconf` and `cmake` in the
  desired order, and detection is attempted accordingly.
  libcurl config can inherit this. Downside is somewhat verbose
  code in each Find module. (or breaking it out to a helper .cmake
  source and also distribute it.)

- introduce per dep option CURL_<DEP>_DISABLE_CMAKECONFIG, e.g.
  `CURL_ZSTD_DISABLE_CMAKECONFIG` which can override and disable
  CMake Config detection for ZSTD. Inheriting this by libcurl config
  doesn't seem practical, though maybe it's okay, since it more
  of a local fire-fighting tool.

- reverse the order (pkgconfg -> cmake) and then honor
  `CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON` to prioritize cmake. Reusing
  a CMAKE setting may catch some by suprise. and it'd also break
  inheriting this property in the generated libcurl Config.
This reverts commit d8d2bbdf19790a6536c23a0c499b2509b5ab1a33.
This reverts commit f3cd9bf.

Backtrack. Move it up if this is requested. Likely Configs are
preferred when pkg-config is disabled.
@vszakats vszakats closed this in 8fce3e1 Mar 21, 2026
@vszakats vszakats deleted the cm-chain-config branch March 21, 2026 17:53
vszakats added a commit to vszakats/curl that referenced this pull request Mar 25, 2026
…fSSL

For wolfSSL it requires v5.2.1+, and with 5.9.0+ it's also supported
when wolfSSL was built with autotools.

Follow-up to 8fce3e1 curl#20814
vszakats added a commit to vszakats/curl that referenced this pull request Mar 25, 2026
…fSSL

For wolfSSL it requires v5.2.1+, and with 5.9.0+ it's also supported
when wolfSSL was built with autotools.

Follow-up to 8fce3e1 curl#20814
vszakats added a commit that referenced this pull request Mar 26, 2026
For wolfSSL it requires v5.2.1+, and with 5.9.0+ it's also supported when
wolfSSL was built with autotools.

Follow-up to 8fce3e1 #20814

Closes #21098
@vszakats
Copy link
Copy Markdown
Member Author

/cc @bmarques1995 @uilianries You may be interested in this new
capability, currently in curl master, and planned to be released with
curl 8.20.0. Feel free to let me know if it works (or not) for you.

@uilianries
Copy link
Copy Markdown

@vszakats Thank you for pinging! That's great news!

@bmarques1995
Copy link
Copy Markdown

/cc @bmarques1995 @uilianries You may be interested in this new capability, currently in curl master, and planned to be released with curl 8.20.0. Feel free to let me know if it works (or not) for you.

Yeah, I'm interested in a feature like this. It's far away easier to compile on windows, even on linux with cmake.

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

Labels

build CI Continuous Integration cmake feature-window A merge of this requires an open feature window tests

Development

Successfully merging this pull request may close these issues.

3 participants