Skip to content

Commit 3336704

Browse files
committed
http: support lazy-loading libcurl also on Windows
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>
1 parent 08bd02f commit 3336704

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -1658,7 +1658,11 @@ else
16581658
# The `CURL_STATICLIB` constant must be defined to avoid seeing the functions
16591659
# declared as DLL imports
16601660
CURL_CFLAGS = -DCURL_STATICLIB
1661+
ifneq ($(uname_S),MINGW)
1662+
ifneq ($(uname_S),Windows)
16611663
CURL_LIBCURL = -ldl
1664+
endif
1665+
endif
16621666
else
16631667
ifndef CURL_LDFLAGS
16641668
CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS)

compat/lazyload-curl.c

+52
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "../git-compat-util.h"
22
#include "../git-curl-compat.h"
3+
#ifndef WIN32
34
#include <dlfcn.h>
5+
#endif
46

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

1214
typedef void (*func_t)(void);
1315

16+
#ifndef WIN32
1417
#ifdef __APPLE__
1518
#define LIBCURL_FILE_NAME(base) base "." LIBCURL_ABI_VERSION ".dylib"
1619
#else
@@ -35,6 +38,55 @@ static func_t load_function(void *handle, const char *name)
3538
*(void **)&f = dlsym(handle, name);
3639
return f;
3740
}
41+
#else
42+
#define LIBCURL_FILE_NAME(base) base "-" LIBCURL_ABI_VERSION ".dll"
43+
44+
static void *load_library(const char *name)
45+
{
46+
size_t name_size = strlen(name) + 1;
47+
const char *path = getenv("PATH");
48+
char dll_path[MAX_PATH];
49+
50+
while (path && *path) {
51+
const char *sep = strchrnul(path, ';');
52+
size_t len = sep - path;
53+
54+
if (len && len + name_size < sizeof(dll_path)) {
55+
memcpy(dll_path, path, len);
56+
dll_path[len] = '/';
57+
memcpy(dll_path + len + 1, name, name_size);
58+
59+
if (!access(dll_path, R_OK)) {
60+
wchar_t wpath[MAX_PATH];
61+
int wlen = MultiByteToWideChar(CP_UTF8, 0, dll_path, -1, wpath, ARRAY_SIZE(wpath));
62+
void *res = wlen ? (void *)LoadLibraryExW(wpath, NULL, 0) : NULL;
63+
if (!res) {
64+
DWORD err = GetLastError();
65+
char buf[1024];
66+
67+
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
68+
FORMAT_MESSAGE_ARGUMENT_ARRAY |
69+
FORMAT_MESSAGE_IGNORE_INSERTS,
70+
NULL, err, LANG_NEUTRAL,
71+
buf, sizeof(buf) - 1, NULL))
72+
xsnprintf(buf, sizeof(buf), "last error: %ld", err);
73+
error("LoadLibraryExW() failed with: %s", buf);
74+
}
75+
return res;
76+
}
77+
}
78+
79+
path = *sep ? sep + 1 : NULL;
80+
}
81+
82+
return NULL;
83+
}
84+
85+
static func_t load_function(void *handle, const char *name)
86+
{
87+
return (func_t)GetProcAddress((HANDLE)handle, name);
88+
}
89+
#endif
3890

3991
typedef struct curl_version_info_data *(*curl_version_info_type)(CURLversion version);
4092
static curl_version_info_type curl_version_info_func;

0 commit comments

Comments
 (0)