Skip to content

Commit

Permalink
http: support lazy-loading libcurl also on Windows
Browse files Browse the repository at this point in the history
This implements the Windows-specific support code, because everything is
slightly different on Windows, even loading shared libraries.

Note: I specifically do _not_ use the code from
`compat/win32/lazyload.h` here because that code is optimized for
loading individual functions from various system DLLs, while we
specifically want to load _many_ functions from _one_ DLL here, and
distinctly not a system DLL (we expect libcurl to be located outside
`C:\Windows\system32`, something `INIT_PROC_ADDR` refuses to work with).
Also, the `curl_easy_getinfo()`/`curl_easy_setopt()` functions are
declared as vararg functions, which `lazyload.h` cannot handle. Finally,
we are about to optionally override the exact file name that is to be
loaded, which is a goal contrary to `lazyload.h`'s design.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
dscho committed Oct 3, 2024
1 parent 630c9ff commit f0ba8a2
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1651,7 +1651,11 @@ else
# The `CURL_STATICLIB` constant must be defined to avoid seeing the functions
# declared as DLL imports
CURL_CFLAGS = -DCURL_STATICLIB
ifneq ($(uname_S),MINGW)
ifneq ($(uname_S),Windows)
CURL_LIBCURL = -ldl
endif
endif
else
ifndef CURL_LDFLAGS
CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS)
Expand Down
52 changes: 52 additions & 0 deletions compat/lazyload-curl.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "../git-compat-util.h"
#include "../git-curl-compat.h"
#ifndef WIN32
#include <dlfcn.h>
#endif

/*
* The ABI version of libcurl is encoded in its shared libraries' file names.
Expand All @@ -11,6 +13,7 @@

typedef void (*func_t)(void);

#ifndef WIN32
#ifdef __APPLE__
#define LIBCURL_FILE_NAME(base) base "." LIBCURL_ABI_VERSION ".dylib"
#else
Expand All @@ -35,6 +38,55 @@ static func_t load_function(void *handle, const char *name)
*(void **)&f = dlsym(handle, name);
return f;
}
#else
#define LIBCURL_FILE_NAME(base) base "-" LIBCURL_ABI_VERSION ".dll"

static void *load_library(const char *name)
{
size_t name_size = strlen(name) + 1;
const char *path = getenv("PATH");
char dll_path[MAX_PATH];

while (path && *path) {
const char *sep = strchrnul(path, ';');
size_t len = sep - path;

if (len && len + name_size < sizeof(dll_path)) {
memcpy(dll_path, path, len);
dll_path[len] = '/';
memcpy(dll_path + len + 1, name, name_size);

if (!access(dll_path, R_OK)) {
wchar_t wpath[MAX_PATH];
int wlen = MultiByteToWideChar(CP_UTF8, 0, dll_path, -1, wpath, ARRAY_SIZE(wpath));
void *res = wlen ? (void *)LoadLibraryExW(wpath, NULL, 0) : NULL;
if (!res) {
DWORD err = GetLastError();
char buf[1024];

if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, LANG_NEUTRAL,
buf, sizeof(buf) - 1, NULL))
xsnprintf(buf, sizeof(buf), "last error: %ld", err);
error("LoadLibraryExW() failed with: %s", buf);
}
return res;
}
}

path = *sep ? sep + 1 : NULL;
}

return NULL;
}

static func_t load_function(void *handle, const char *name)
{
return (func_t)GetProcAddress((HANDLE)handle, name);
}
#endif

typedef struct curl_version_info_data *(*curl_version_info_type)(CURLversion version);
static curl_version_info_type curl_version_info_func;
Expand Down

0 comments on commit f0ba8a2

Please sign in to comment.