From a44242fe5217f75f11d212f3de9d7a08ee7e2c92 Mon Sep 17 00:00:00 2001 From: Polyvios Tsirimpas Date: Wed, 1 Apr 2026 19:13:52 +0300 Subject: [PATCH 1/4] Add c-ares feature for static libcurl builds --- Cargo.toml | 1 + README.md | 1 + curl-sys/Cargo.toml | 1 + curl-sys/build.rs | 134 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 128 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fc46a6e66..58fac82d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ static-ssl = ["curl-sys/static-ssl"] windows-static-ssl = ["static-curl", "curl-sys/windows-static-ssl"] force-system-lib-on-osx = ['curl-sys/force-system-lib-on-osx'] protocol-ftp = ["curl-sys/protocol-ftp"] +c-ares = ["curl-sys/c-ares"] zlib-ng-compat = ["curl-sys/zlib-ng-compat", "static-curl"] upkeep_7_62_0 = ["curl-sys/upkeep_7_62_0"] poll_7_68_0 = ["curl-sys/poll_7_68_0"] diff --git a/README.md b/README.md index d0911bea9..a74cba402 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ with various Cargo features: - `static-curl`: Use a bundled libcurl version and statically link to it. Disabled by default. - `apple-sectrust`: Use Apple SecTrust for certificate verification with bundled libcurl and OpenSSL on Apple platforms. Implies `ssl` and `static-curl`. Disabled by default. - `static-ssl`: Use a bundled OpenSSL version and statically link to it. Only applies on platforms that use OpenSSL. Disabled by default. +- `c-ares`: Build libcurl with c-ares DNS support. Useful with `static-curl` if you need c-ares-only options such as `CURLOPT_DNS_SERVERS`. Requires c-ares development files discoverable by `pkg-config` (or `vcpkg` on MSVC Windows). Disabled by default. - `spnego`: Enable SPNEGO support. Disabled by default. - `upkeep_7_62_0`: Enable curl_easy_upkeep() support, introduced in curl 7.62.0. Disabled by default. - `poll_7_68_0`: Enable curl_multi_poll()/curl_multi_wakeup() support, requires curl 7.68.0 or later. Disabled by default. diff --git a/curl-sys/Cargo.toml b/curl-sys/Cargo.toml index b6663832c..6936b89d4 100644 --- a/curl-sys/Cargo.toml +++ b/curl-sys/Cargo.toml @@ -56,6 +56,7 @@ static-ssl = ["openssl-sys/vendored"] spnego = [] force-system-lib-on-osx = [] protocol-ftp = [] +c-ares = [] zlib-ng-compat = ["libz-sys/zlib-ng", "static-curl"] upkeep_7_62_0 = [] poll_7_68_0 = [] diff --git a/curl-sys/build.rs b/curl-sys/build.rs index 7d028d410..9f4a712b5 100644 --- a/curl-sys/build.rs +++ b/curl-sys/build.rs @@ -45,6 +45,8 @@ fn main() { ); let target = env::var("TARGET").unwrap(); let windows = target.contains("windows"); + let needs_http2 = cfg!(feature = "http2"); + let needs_cares = cfg!(feature = "c-ares"); if cfg!(feature = "mesalink") { println!("cargo:warning=MesaLink support has been removed as of curl 7.82.0, will use default TLS backend instead."); @@ -61,7 +63,10 @@ fn main() { if !cfg!(feature = "static-curl") { // OSX ships libcurl by default, so we just use that version // so long as it has the right features enabled. - if target.contains("apple") && (!cfg!(feature = "http2") || curl_config_reports_http2()) { + if target.contains("apple") + && (!needs_http2 || curl_config_reports_http2()) + && (!needs_cares || curl_config_reports_cares()) + { return println!("cargo:rustc-flags=-l curl"); } @@ -70,7 +75,7 @@ fn main() { if try_vcpkg() { return; } - } else if try_pkg_config() { + } else if try_pkg_config(needs_http2, needs_cares) { return; } } @@ -161,7 +166,6 @@ fn main() { .define("HAVE_BOOL_T", None) .define("HAVE_STDBOOL_H", None) .define("HAVE_STDINT_H", None) - .define("USE_RESOLV_THREADED", None) .file("curl/lib/altsvc.c") .file("curl/lib/api.c") .file("curl/lib/bufq.c") @@ -303,6 +307,17 @@ fn main() { .define("HAVE_GETSOCKNAME", None) .warnings(false); + // One asynchronous resolver: c-ares when asked for, otherwise curl's + // threaded resolver. + if needs_cares { + cfg.define("USE_ARES", None) + .define("USE_RESOLV_ARES", None) + .file("curl/lib/vdns/asyn-ares.c"); + configure_cares(&mut cfg, windows); + } else { + cfg.define("USE_RESOLV_THREADED", None); + } + if cfg!(feature = "ntlm") { cfg.file("curl/lib/curl_endian.c") .file("curl/lib/curl_gethostname.c") @@ -587,10 +602,10 @@ fn try_vcpkg() -> bool { false } -fn try_pkg_config() -> bool { - let mut cfg = pkg_config::Config::new(); - cfg.cargo_metadata(false); - let lib = match cfg.probe("libcurl") { +fn try_pkg_config(needs_http2: bool, needs_cares: bool) -> bool { + let mut pkgcfg = pkg_config::Config::new(); + pkgcfg.cargo_metadata(false); + let lib = match pkgcfg.probe("libcurl") { Ok(lib) => lib, Err(e) => { println!( @@ -604,13 +619,23 @@ fn try_pkg_config() -> bool { // Not all system builds of libcurl have http2 features enabled, so if we've // got a http2-requested build then we may fall back to a build from source. - if cfg!(feature = "http2") && !curl_config_reports_http2() { + if needs_http2 && !curl_config_reports_http2() { + return false; + } + + // c-ares support is required for CURLOPT_DNS_SERVERS and related APIs. + // If we cannot confirm the system libcurl was configured with c-ares, + // fall back to compiling libcurl from source. + if needs_cares + && !pkg_config_reports_cares(&lib) + && !curl_config_reports_cares() + { return false; } // Re-find the library to print cargo's metadata, then print some extra // metadata as well. - cfg.cargo_metadata(true).probe("libcurl").unwrap(); + pkgcfg.cargo_metadata(true).probe("libcurl").unwrap(); for path in lib.include_paths.iter() { println!("cargo:include={}", path.display()); } @@ -641,3 +666,94 @@ fn curl_config_reports_http2() -> bool { true } + +fn pkg_config_reports_cares(lib: &pkg_config::Library) -> bool { + if lib.libs.iter().any(|name| name.contains("cares")) { + return true; + } + + println!( + "failed to find c-ares in pkg-config metadata for libcurl, \ + validating with curl-config" + ); + false +} + +fn curl_config_reports_cares() -> bool { + let output = Command::new("curl-config").arg("--configure").output(); + let output = match output { + Ok(out) => out, + Err(e) => { + println!("failed to run curl-config ({}), building from source", e); + return false; + } + }; + if !output.status.success() { + println!("curl-config failed: {}", output.status); + return false; + } + let stdout = String::from_utf8_lossy(&output.stdout); + if !stdout.contains("--enable-ares") && !stdout.contains("--with-ares") { + println!( + "failed to find c-ares enabled in pkg-config-found libcurl, \ + building from source" + ); + return false; + } + + true +} + +fn configure_cares(cfg: &mut cc::Build, windows: bool) { + if windows { + if try_vcpkg_cares(cfg) { + return; + } + } else if try_pkg_config_cares(cfg) { + return; + } + + panic!( + "c-ares support requires a discoverable c-ares installation (via vcpkg \ + on Windows or pkg-config on non-Windows platforms)" + ); +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg_cares(_cfg: &mut cc::Build) -> bool { + false +} + +#[cfg(target_env = "msvc")] +fn try_vcpkg_cares(cfg: &mut cc::Build) -> bool { + let lib = match vcpkg::Config::new().emit_includes(true).probe("c-ares") { + Ok(lib) => lib, + Err(e) => { + println!("vcpkg could not find c-ares: {}", e); + return false; + } + }; + + for include in lib.include_paths { + cfg.include(include); + } + true +} + +fn try_pkg_config_cares(cfg: &mut cc::Build) -> bool { + for package in ["libcares", "c-ares"] { + match pkg_config::Config::new().probe(package) { + Ok(lib) => { + for include in lib.include_paths { + cfg.include(include); + } + return true; + } + Err(e) => { + println!("pkg-config could not find {}: {}", package, e); + } + } + } + + false +} From 7f0b81cd83a707578fee51be9fa81aea391f1efe Mon Sep 17 00:00:00 2001 From: Polyvios Tsirimpas Date: Wed, 1 Apr 2026 19:17:54 +0300 Subject: [PATCH 2/4] lint --- curl-sys/build.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/curl-sys/build.rs b/curl-sys/build.rs index 9f4a712b5..32cc5546d 100644 --- a/curl-sys/build.rs +++ b/curl-sys/build.rs @@ -626,10 +626,7 @@ fn try_pkg_config(needs_http2: bool, needs_cares: bool) -> bool { // c-ares support is required for CURLOPT_DNS_SERVERS and related APIs. // If we cannot confirm the system libcurl was configured with c-ares, // fall back to compiling libcurl from source. - if needs_cares - && !pkg_config_reports_cares(&lib) - && !curl_config_reports_cares() - { + if needs_cares && !pkg_config_reports_cares(&lib) && !curl_config_reports_cares() { return false; } From 06dcfc793ca0ee6a1f77753a3d03cb5851c1e8e2 Mon Sep 17 00:00:00 2001 From: Polyvios Tsirimpas Date: Wed, 1 Apr 2026 19:32:15 +0300 Subject: [PATCH 3/4] fix docs --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 680d47194..a759abbc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -121,7 +121,7 @@ jobs: - name: Install dependencies run: | sudo apt update - sudo apt install libkrb5-dev + sudo apt install libkrb5-dev libc-ares-dev - name: Build documentation run: cargo doc --no-deps --all-features - name: Publish documentation From 75aacb2cd7ad99648946e590370c22baccd09d39 Mon Sep 17 00:00:00 2001 From: Polyvios Tsirimpas Date: Thu, 2 Apr 2026 10:19:35 +0300 Subject: [PATCH 4/4] fail if system doesnt have cares and non static build --- README.md | 2 +- curl-sys/build.rs | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a74cba402..f099c75f2 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ with various Cargo features: - `static-curl`: Use a bundled libcurl version and statically link to it. Disabled by default. - `apple-sectrust`: Use Apple SecTrust for certificate verification with bundled libcurl and OpenSSL on Apple platforms. Implies `ssl` and `static-curl`. Disabled by default. - `static-ssl`: Use a bundled OpenSSL version and statically link to it. Only applies on platforms that use OpenSSL. Disabled by default. -- `c-ares`: Build libcurl with c-ares DNS support. Useful with `static-curl` if you need c-ares-only options such as `CURLOPT_DNS_SERVERS`. Requires c-ares development files discoverable by `pkg-config` (or `vcpkg` on MSVC Windows). Disabled by default. +- `c-ares`: Enable c-ares DNS support. This enables c-ares checks for both system and vendored builds. With `static-curl`, vendored libcurl is built with c-ares (requires c-ares development files discoverable by `pkg-config` or `vcpkg` on MSVC Windows). Without `static-curl`, a system libcurl with c-ares support is required. Disabled by default. - `spnego`: Enable SPNEGO support. Disabled by default. - `upkeep_7_62_0`: Enable curl_easy_upkeep() support, introduced in curl 7.62.0. Disabled by default. - `poll_7_68_0`: Enable curl_multi_poll()/curl_multi_wakeup() support, requires curl 7.68.0 or later. Disabled by default. diff --git a/curl-sys/build.rs b/curl-sys/build.rs index 32cc5546d..22b193c07 100644 --- a/curl-sys/build.rs +++ b/curl-sys/build.rs @@ -72,12 +72,19 @@ fn main() { // Next, fall back and try to use pkg-config if its available. if windows { - if try_vcpkg() { + if try_vcpkg(needs_http2, needs_cares) { return; } } else if try_pkg_config(needs_http2, needs_cares) { return; } + + if needs_cares { + panic!( + "feature `c-ares` without `static-curl` requires a system \ + libcurl with c-ares support (or enable `static-curl`)" + ); + } } if !Path::new("curl/.git").exists() { @@ -545,12 +552,12 @@ fn main() { } #[cfg(not(target_env = "msvc"))] -fn try_vcpkg() -> bool { +fn try_vcpkg(_needs_http2: bool, _needs_cares: bool) -> bool { false } #[cfg(target_env = "msvc")] -fn try_vcpkg() -> bool { +fn try_vcpkg(_needs_http2: bool, needs_cares: bool) -> bool { // the import library for the dll is called libcurl_imp let mut successful_probe_details = match vcpkg::Config::new() .lib_names("libcurl_imp", "libcurl") @@ -597,6 +604,14 @@ fn try_vcpkg() -> bool { println!("cargo:rustc-link-lib=gdi32"); println!("cargo:rustc-link-lib=user32"); println!("cargo:rustc-link-lib=wldap32"); + + if needs_cares { + if let Err(e) = vcpkg::probe_package("c-ares") { + println!("vcpkg could not find c-ares for system libcurl: {}", e); + return false; + } + } + return true; } false