mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Linux: Added an option to lazily load libcurl symbols only when they are needed
This commit is contained in:
parent
383528ec6e
commit
baa8bbf300
3 changed files with 133 additions and 36 deletions
|
|
@ -468,6 +468,10 @@ private:
|
|||
packages.add ("gtk+-x11-3.0");
|
||||
}
|
||||
|
||||
// don't add libcurl if curl symbols are loaded at runtime
|
||||
if (! isLoadCurlSymbolsLazilyEnabled())
|
||||
packages.add ("libcurl");
|
||||
|
||||
packages.removeDuplicates (false);
|
||||
|
||||
return packages;
|
||||
|
|
@ -608,6 +612,14 @@ private:
|
|||
&& project.isConfigFlagEnabled ("JUCE_WEB_BROWSER", true));
|
||||
}
|
||||
|
||||
bool isLoadCurlSymbolsLazilyEnabled() const
|
||||
{
|
||||
static String juceCoreModule ("juce_core");
|
||||
|
||||
return (project.getModules().isModuleEnabled (juceCoreModule)
|
||||
&& project.isConfigFlagEnabled ("JUCE_LOAD_CURL_SYMBOLS_LAZILY", false));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void writeDefineFlags (OutputStream& out, const MakeBuildConfiguration& config) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
OSXFrameworks: Cocoa IOKit
|
||||
iOSFrameworks: Foundation
|
||||
linuxLibs: rt dl pthread
|
||||
linuxPackages: libcurl
|
||||
mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm
|
||||
|
||||
END_JUCE_MODULE_DECLARATION
|
||||
|
|
@ -138,7 +137,22 @@
|
|||
If you disable this then https/ssl support will not be available on linux.
|
||||
*/
|
||||
#ifndef JUCE_USE_CURL
|
||||
#define JUCE_USE_CURL 0
|
||||
#if JUCE_LINUX
|
||||
#define JUCE_USE_CURL 1
|
||||
#else
|
||||
#define JUCE_USE_CURL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_LOAD_CURL_SYMBOLS_LAZILY
|
||||
If enabled, JUCE will load libcurl lazily when required (for example, when WebInputStream
|
||||
is used). Enabling this flag may also help with library dependency erros as linking
|
||||
libcurl at compile-time may instruct the linker to hard depend on a specific version
|
||||
of libcurl. It's also useful if you want to limit the amount of JUCE dependencies and
|
||||
you are not using WebInputStream or the URL classes.
|
||||
*/
|
||||
#ifndef JUCE_LOAD_CURL_SYMBOLS_LAZILY
|
||||
#define JUCE_LOAD_CURL_SYMBOLS_LAZILY 0
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,74 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
struct CURLSymbols
|
||||
{
|
||||
CURL* (*curl_easy_init) (void);
|
||||
CURLcode (*curl_easy_setopt) (CURL *curl, CURLoption option, ...);
|
||||
void (*curl_easy_cleanup) (CURL *curl);
|
||||
CURLcode (*curl_easy_getinfo) (CURL *curl, CURLINFO info, ...);
|
||||
CURLMcode (*curl_multi_add_handle) (CURLM *multi_handle, CURL *curl_handle);
|
||||
CURLMcode (*curl_multi_cleanup) (CURLM *multi_handle);
|
||||
CURLMcode (*curl_multi_fdset) (CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd);
|
||||
CURLMsg* (*curl_multi_info_read) (CURLM *multi_handle, int *msgs_in_queue);
|
||||
CURLM* (*curl_multi_init) (void);
|
||||
CURLMcode (*curl_multi_perform) (CURLM *multi_handle, int *running_handles);
|
||||
CURLMcode (*curl_multi_remove_handle) (CURLM *multi_handle, CURL *curl_handle);
|
||||
CURLMcode (*curl_multi_timeout) (CURLM *multi_handle, long *milliseconds);
|
||||
struct curl_slist* (*curl_slist_append) (struct curl_slist *, const char *);
|
||||
void (*curl_slist_free_all) (struct curl_slist *);
|
||||
curl_version_info_data* (*curl_version_info) (CURLversion);
|
||||
|
||||
static std::unique_ptr<CURLSymbols> create()
|
||||
{
|
||||
std::unique_ptr<CURLSymbols> symbols (new CURLSymbols);
|
||||
|
||||
#if JUCE_LOAD_CURL_SYMBOLS_LAZILY
|
||||
#define JUCE_INIT_CURL_SYMBOL(name) if (! symbols->loadSymbol (symbols->name, #name)) return nullptr;
|
||||
#else
|
||||
#define JUCE_INIT_CURL_SYMBOL(name) symbols->name = ::name;
|
||||
#endif
|
||||
|
||||
JUCE_INIT_CURL_SYMBOL (curl_easy_init)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_easy_setopt)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_easy_cleanup)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_easy_getinfo)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_add_handle)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_cleanup)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_fdset)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_info_read)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_init)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_perform)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_remove_handle)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_multi_timeout)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_slist_append)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_slist_free_all)
|
||||
JUCE_INIT_CURL_SYMBOL (curl_version_info)
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
||||
private:
|
||||
CURLSymbols() = default;
|
||||
|
||||
#if JUCE_LOAD_CURL_SYMBOLS_LAZILY
|
||||
static DynamicLibrary& getLibcurl()
|
||||
{
|
||||
static DynamicLibrary libcurl { "libcurl.so" };
|
||||
return libcurl;
|
||||
}
|
||||
|
||||
template <typename FuncPtr>
|
||||
bool loadSymbol (FuncPtr& dst, const char* name)
|
||||
{
|
||||
dst = reinterpret_cast<FuncPtr> (getLibcurl().getFunction (name));
|
||||
return (dst != nullptr);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream::Pimpl
|
||||
{
|
||||
public:
|
||||
|
|
@ -30,14 +98,16 @@ public:
|
|||
: owner (ownerStream), url (urlToCopy), isPost (shouldUsePost),
|
||||
httpRequest (isPost ? "POST" : "GET")
|
||||
{
|
||||
multi = curl_multi_init();
|
||||
jassert (symbols); // Unable to load libcurl!
|
||||
|
||||
multi = symbols->curl_multi_init();
|
||||
|
||||
if (multi != nullptr)
|
||||
{
|
||||
curl = curl_easy_init();
|
||||
curl = symbols->curl_easy_init();
|
||||
|
||||
if (curl != nullptr)
|
||||
if (curl_multi_add_handle (multi, curl) == CURLM_OK)
|
||||
if (symbols->curl_multi_add_handle (multi, curl) == CURLM_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -103,21 +173,21 @@ public:
|
|||
|
||||
if (curl != nullptr)
|
||||
{
|
||||
curl_multi_remove_handle (multi, curl);
|
||||
symbols->curl_multi_remove_handle (multi, curl);
|
||||
|
||||
if (headerList != nullptr)
|
||||
{
|
||||
curl_slist_free_all (headerList);
|
||||
symbols->curl_slist_free_all (headerList);
|
||||
headerList = nullptr;
|
||||
}
|
||||
|
||||
curl_easy_cleanup (curl);
|
||||
symbols->curl_easy_cleanup (curl);
|
||||
curl = nullptr;
|
||||
}
|
||||
|
||||
if (multi != nullptr)
|
||||
{
|
||||
curl_multi_cleanup (multi);
|
||||
symbols->curl_multi_cleanup (multi);
|
||||
multi = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +202,7 @@ public:
|
|||
{
|
||||
auto address = url.toString (! isPost);
|
||||
|
||||
curl_version_info_data* data = curl_version_info (CURLVERSION_NOW);
|
||||
curl_version_info_data* data = symbols->curl_version_info (CURLVERSION_NOW);
|
||||
jassert (data != nullptr);
|
||||
|
||||
if (! requestHeaders.endsWithChar ('\n'))
|
||||
|
|
@ -146,22 +216,22 @@ public:
|
|||
|
||||
auto userAgent = String ("curl/") + data->version;
|
||||
|
||||
if (curl_easy_setopt (curl, CURLOPT_URL, address.toRawUTF8()) == CURLE_OK
|
||||
&& curl_easy_setopt (curl, CURLOPT_WRITEDATA, this) == CURLE_OK
|
||||
&& curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, StaticCurlWrite) == CURLE_OK
|
||||
&& curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1) == CURLE_OK
|
||||
&& curl_easy_setopt (curl, CURLOPT_MAXREDIRS, static_cast<long> (maxRedirects)) == CURLE_OK
|
||||
&& curl_easy_setopt (curl, CURLOPT_USERAGENT, userAgent.toRawUTF8()) == CURLE_OK
|
||||
&& curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, (maxRedirects > 0 ? 1 : 0)) == CURLE_OK)
|
||||
if (symbols->curl_easy_setopt (curl, CURLOPT_URL, address.toRawUTF8()) == CURLE_OK
|
||||
&& symbols->curl_easy_setopt (curl, CURLOPT_WRITEDATA, this) == CURLE_OK
|
||||
&& symbols->curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, StaticCurlWrite) == CURLE_OK
|
||||
&& symbols->curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1) == CURLE_OK
|
||||
&& symbols->curl_easy_setopt (curl, CURLOPT_MAXREDIRS, static_cast<long> (maxRedirects)) == CURLE_OK
|
||||
&& symbols->curl_easy_setopt (curl, CURLOPT_USERAGENT, userAgent.toRawUTF8()) == CURLE_OK
|
||||
&& symbols->curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, (maxRedirects > 0 ? 1 : 0)) == CURLE_OK)
|
||||
{
|
||||
if (isPost)
|
||||
{
|
||||
if (curl_easy_setopt (curl, CURLOPT_READDATA, this) != CURLE_OK
|
||||
|| curl_easy_setopt (curl, CURLOPT_READFUNCTION, StaticCurlRead) != CURLE_OK)
|
||||
if (symbols->curl_easy_setopt (curl, CURLOPT_READDATA, this) != CURLE_OK
|
||||
|| symbols->curl_easy_setopt (curl, CURLOPT_READFUNCTION, StaticCurlRead) != CURLE_OK)
|
||||
return false;
|
||||
|
||||
if (curl_easy_setopt (curl, CURLOPT_POST, 1) != CURLE_OK
|
||||
|| curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t> (headersAndPostData.getSize())) != CURLE_OK)
|
||||
if (symbols->curl_easy_setopt (curl, CURLOPT_POST, 1) != CURLE_OK
|
||||
|| symbols->curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t> (headersAndPostData.getSize())) != CURLE_OK)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -169,20 +239,20 @@ public:
|
|||
bool hasSpecialRequestCmd = isPost ? (httpRequest != "POST") : (httpRequest != "GET");
|
||||
|
||||
if (hasSpecialRequestCmd)
|
||||
if (curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, httpRequest.toRawUTF8()) != CURLE_OK)
|
||||
if (symbols->curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, httpRequest.toRawUTF8()) != CURLE_OK)
|
||||
return false;
|
||||
|
||||
if (curl_easy_setopt (curl, CURLOPT_HEADERDATA, this) != CURLE_OK
|
||||
|| curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, StaticCurlHeader) != CURLE_OK)
|
||||
if (symbols->curl_easy_setopt (curl, CURLOPT_HEADERDATA, this) != CURLE_OK
|
||||
|| symbols->curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, StaticCurlHeader) != CURLE_OK)
|
||||
return false;
|
||||
|
||||
if (timeOutMs > 0)
|
||||
{
|
||||
auto timeOutSecs = ((long) timeOutMs + 999) / 1000;
|
||||
|
||||
if (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, timeOutSecs) != CURLE_OK
|
||||
|| curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, 100) != CURLE_OK
|
||||
|| curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, timeOutSecs) != CURLE_OK)
|
||||
if (symbols->curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, timeOutSecs) != CURLE_OK
|
||||
|| symbols->curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, 100) != CURLE_OK
|
||||
|| symbols->curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, timeOutSecs) != CURLE_OK)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -212,10 +282,10 @@ public:
|
|||
|
||||
// fromLines will always return at least one line if the string is not empty
|
||||
jassert (headerLines.size() > 0);
|
||||
headerList = curl_slist_append (headerList, headerLines [0].toRawUTF8());
|
||||
headerList = symbols->curl_slist_append (headerList, headerLines [0].toRawUTF8());
|
||||
|
||||
for (int i = 1; (i < headerLines.size() && headerList != nullptr); ++i)
|
||||
headerList = curl_slist_append (headerList, headerLines [i].toRawUTF8());
|
||||
headerList = symbols->curl_slist_append (headerList, headerLines [i].toRawUTF8());
|
||||
|
||||
if (headerList == nullptr)
|
||||
{
|
||||
|
|
@ -223,7 +293,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headerList) != CURLE_OK)
|
||||
if (symbols->curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headerList) != CURLE_OK)
|
||||
{
|
||||
cleanup();
|
||||
return false;
|
||||
|
|
@ -272,12 +342,12 @@ public:
|
|||
return false;
|
||||
|
||||
long responseCode;
|
||||
if (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &responseCode) == CURLE_OK)
|
||||
if (symbols->curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &responseCode) == CURLE_OK)
|
||||
statusCode = static_cast<int> (responseCode);
|
||||
|
||||
// get content length size
|
||||
double curlLength;
|
||||
if (curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curlLength) == CURLE_OK)
|
||||
if (symbols->curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curlLength) == CURLE_OK)
|
||||
contentLength = static_cast<int64> (curlLength);
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +365,7 @@ public:
|
|||
{
|
||||
int cnt = 0;
|
||||
|
||||
if (CURLMsg* msg = curl_multi_info_read (multi, &cnt))
|
||||
if (CURLMsg* msg = symbols->curl_multi_info_read (multi, &cnt))
|
||||
{
|
||||
if (msg->msg == CURLMSG_DONE && msg->easy_handle == curl)
|
||||
{
|
||||
|
|
@ -328,7 +398,7 @@ public:
|
|||
if (multi == nullptr)
|
||||
return;
|
||||
|
||||
if ((lastError = (int) curl_multi_timeout (multi, &curl_timeo)) != CURLM_OK)
|
||||
if ((lastError = (int) symbols->curl_multi_timeout (multi, &curl_timeo)) != CURLM_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +420,7 @@ public:
|
|||
if (multi == nullptr)
|
||||
return;
|
||||
|
||||
if ((lastError = (int) curl_multi_fdset (multi, &fdread, &fdwrite, &fdexcep, &maxfd)) != CURLM_OK)
|
||||
if ((lastError = (int) symbols->curl_multi_fdset (multi, &fdread, &fdwrite, &fdexcep, &maxfd)) != CURLM_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +444,7 @@ public:
|
|||
{
|
||||
const ScopedLock lock (cleanupLock);
|
||||
|
||||
while ((curlRet = (int) curl_multi_perform (multi, &still_running)) == CURLM_CALL_MULTI_PERFORM)
|
||||
while ((curlRet = (int) symbols->curl_multi_perform (multi, &still_running)) == CURLM_CALL_MULTI_PERFORM)
|
||||
{}
|
||||
}
|
||||
|
||||
|
|
@ -510,6 +580,7 @@ public:
|
|||
//==============================================================================
|
||||
WebInputStream& owner;
|
||||
const URL url;
|
||||
std::unique_ptr<CURLSymbols> symbols { CURLSymbols::create() };
|
||||
|
||||
//==============================================================================
|
||||
// curl stuff
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue