|
46 | 46 | //! There is a large number of releases for libcurl, all with different sets of
|
47 | 47 | //! capabilities. Robust programs may wish to inspect `Version::get()` to test
|
48 | 48 | //! what features are implemented in the linked build of libcurl at runtime.
|
| 49 | +//! |
| 50 | +//! # Initialization |
| 51 | +//! |
| 52 | +//! The underlying libcurl library must be initialized before use and has |
| 53 | +//! certain requirements on how this is done. Check the documentation for |
| 54 | +//! [`init`] for more details. |
49 | 55 |
|
50 | 56 | #![deny(missing_docs, missing_debug_implementations)]
|
51 | 57 | #![doc(html_root_url = "https://docs.rs/curl/0.4")]
|
@@ -78,34 +84,63 @@ mod panic;
|
78 | 84 |
|
79 | 85 | /// Initializes the underlying libcurl library.
|
80 | 86 | ///
|
81 |
| -/// It's not required to call this before the library is used, but it's |
82 |
| -/// recommended to do so as soon as the program starts. |
| 87 | +/// The underlying libcurl library must be initialized before use, and must be |
| 88 | +/// done so on the main thread before any other threads are created by the |
| 89 | +/// program. This crate will do this for you automatically in the following |
| 90 | +/// scenarios: |
| 91 | +/// |
| 92 | +/// - Creating a new [`Easy`][easy::Easy] or [`Multi`][multi::Multi] handle |
| 93 | +/// - At program startup on Windows, macOS, Linux, Android, or FreeBSD systems |
| 94 | +/// |
| 95 | +/// This should be sufficient for most applications and scenarios, but in any |
| 96 | +/// other case, it is strongly recommended that you call this function manually |
| 97 | +/// as soon as your program starts. |
| 98 | +/// |
| 99 | +/// Calling this function more than once is harmless and has no effect. |
| 100 | +#[inline] |
83 | 101 | pub fn init() {
|
| 102 | + /// Used to prevent concurrent or duplicate initialization. |
84 | 103 | static INIT: Once = Once::new();
|
85 |
| - INIT.call_once(|| { |
86 |
| - platform_init(); |
87 |
| - unsafe { |
88 |
| - assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0); |
89 |
| - } |
90 |
| - |
91 |
| - // Note that we explicitly don't schedule a call to |
92 |
| - // `curl_global_cleanup`. The documentation for that function says |
93 |
| - // |
94 |
| - // > You must not call it when any other thread in the program (i.e. a |
95 |
| - // > thread sharing the same memory) is running. This doesn't just mean |
96 |
| - // > no other thread that is using libcurl. |
97 |
| - // |
98 |
| - // We can't ever be sure of that, so unfortunately we can't call the |
99 |
| - // function. |
100 |
| - }); |
101 |
| - |
102 |
| - #[cfg(need_openssl_init)] |
103 |
| - fn platform_init() { |
104 |
| - openssl_sys::init(); |
| 104 | + |
| 105 | + /// An exported constructor function. On supported platforms, this will be |
| 106 | + /// invoked automatically before the program's `main` is called. |
| 107 | + #[cfg_attr( |
| 108 | + any(target_os = "linux", target_os = "freebsd", target_os = "android"), |
| 109 | + link_section = ".init_array" |
| 110 | + )] |
| 111 | + #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")] |
| 112 | + #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")] |
| 113 | + static INIT_CTOR: extern "C" fn() = init_inner; |
| 114 | + |
| 115 | + /// This is the body of our constructor function. |
| 116 | + #[cfg_attr( |
| 117 | + any(target_os = "linux", target_os = "android"), |
| 118 | + link_section = ".text.startup" |
| 119 | + )] |
| 120 | + extern "C" fn init_inner() { |
| 121 | + INIT.call_once(|| { |
| 122 | + #[cfg(need_openssl_init)] |
| 123 | + openssl_sys::init(); |
| 124 | + |
| 125 | + unsafe { |
| 126 | + assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0); |
| 127 | + } |
| 128 | + |
| 129 | + // Note that we explicitly don't schedule a call to |
| 130 | + // `curl_global_cleanup`. The documentation for that function says |
| 131 | + // |
| 132 | + // > You must not call it when any other thread in the program (i.e. |
| 133 | + // > a thread sharing the same memory) is running. This doesn't just |
| 134 | + // > mean no other thread that is using libcurl. |
| 135 | + // |
| 136 | + // We can't ever be sure of that, so unfortunately we can't call the |
| 137 | + // function. |
| 138 | + }); |
105 | 139 | }
|
106 | 140 |
|
107 |
| - #[cfg(not(need_openssl_init))] |
108 |
| - fn platform_init() {} |
| 141 | + // We invoke our init function through our static to ensure the symbol isn't |
| 142 | + // optimized away by a bug: https://github.com/rust-lang/rust/issues/47384 |
| 143 | + INIT_CTOR(); |
109 | 144 | }
|
110 | 145 |
|
111 | 146 | unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> {
|
|
0 commit comments