Browse Source

Linux: Added an option to lazily load libcurl symbols only when they are needed

tags/2021-05-28
hogliux 7 years ago
parent
commit
baa8bbf300
3 changed files with 133 additions and 36 deletions
  1. +12
    -0
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h
  2. +16
    -2
      modules/juce_core/juce_core.h
  3. +105
    -34
      modules/juce_core/native/juce_curl_Network.cpp

+ 12
- 0
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h View File

@@ -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
{


+ 16
- 2
modules/juce_core/juce_core.h View File

@@ -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


+ 105
- 34
modules/juce_core/native/juce_curl_Network.cpp View File

@@ -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…
Cancel
Save