This is the mail archive of the
cygwin-patches
mailing list for the Cygwin project.
Re: [PATCH 3/4] dlopen: on x/lib search x/bin if exe is in x/bin
Hi Corinna,
On 09/01/2016 03:32 PM, Corinna Vinschen wrote:
> On Aug 31 20:07, Michael Haubenwallner wrote:
>> citing https://cygwin.com/ml/cygwin-developers/2016-08/msg00020.html
>>> Consider the file /usr/bin/cygz.dll:
>>> - dlopen (libz.so) success
>>> - dlopen (/usr/bin/libz.so) success
>>> - dlopen (/usr/lib/libz.so) fails
>>
>> * dlfcn.c (dlopen): For dlopen("x/lib/N"), when the application
>> executable is in "x/bin/", search for "x/bin/N" before "x/lib/N".
>> ---
>> winsup/cygwin/dlfcn.cc | 36 +++++++++++++++++++++++++++++++++++-
>> 1 file changed, 35 insertions(+), 1 deletion(-)
>>
>> diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc
>> index e592512..f8b8743 100644
>> --- a/winsup/cygwin/dlfcn.cc
>> +++ b/winsup/cygwin/dlfcn.cc
>> @@ -153,6 +153,25 @@ collect_basenames (pathfinder::basenamelist & basenames,
>> basenames.appendv (basename, baselen, ext, extlen, NULL);
>> }
>>
>> +/* Identify dir of current executable into exedirbuf using wpathbuf buffer.
>> + Return length of exedirbuf on success, or zero on error. */
>> +static int
>> +get_exedir (char * exedirbuf, wchar_t * wpathbuf)
>> +{
>> + /* Unless we have a special cygwin loader, there is no such thing like
>> + DT_RUNPATH on Windows we can use to search for dlls, except for the
>> + directory of the main executable. */
>> + GetModuleFileNameW (NULL, wpathbuf, NT_MAX_PATH);
>> + wchar_t * lastwsep = wcsrchr (wpathbuf, L'\\');
>> + if (!lastwsep)
>> + return 0;
>> + *lastwsep = L'\0';
>> + *exedirbuf = '\0';
>> + if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, wpathbuf, exedirbuf, NT_MAX_PATH))
>> + return 0;
>> + return strlen (exedirbuf);
>> +}
>
> You could just use the global variable program_invocation_name. If in
> doubt, use the Windows path global_progname and convert it to full POSIX
> via cygwin_conv_path.
Patch updated, using global_progname now.
>> extern "C" void *
>> dlopen (const char *name, int flags)
>> {
>> @@ -184,13 +203,28 @@ dlopen (const char *name, int flags)
>> /* handle for the named library */
>> path_conv real_filename;
>> wchar_t *wpath = tp.w_get ();
>> + char *cpath = tp.c_get ();
>>
>> pathfinder finder (allocator, basenames); /* eats basenames */
>>
>> if (have_dir)
>> {
>> + int dirlen = basename - 1 - name;
>> +
>> + /* if the specified dir is x/lib, and the current executable
>> + dir is x/bin, do the /lib -> /bin mapping, which is the
>> + same actually as adding the executable dir */
>> + if (dirlen >= 4 && !strncmp (name + dirlen - 4, "/lib", 4))
>> + {
>> + int exedirlen = get_exedir (cpath, wpath);
>> + if (exedirlen == dirlen &&
>> + !strncmp (cpath, name, dirlen - 4) &&
>> + !strcmp (cpath + dirlen - 4, "/bin"))
>> + finder.add_searchdir (cpath, exedirlen);
>> + }
>> +
>> /* search the specified dir */
>> - finder.add_searchdir (name, basename - 1 - name);
>> + finder.add_searchdir (name, dirlen);
>> }
>> else
>> {
>> --
>> 2.7.3
>
> Rest looks ok.
Thanks!
/haubi/
>From 01da8b76ec3a02137d1a3464a413512d953eaea7 Mon Sep 17 00:00:00 2001
From: Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
Date: Wed, 31 Aug 2016 18:05:11 +0200
Subject: [PATCH 3/4] dlopen: on x/lib search x/bin if exe is in x/bin
citing https://cygwin.com/ml/cygwin-developers/2016-08/msg00020.html
> Consider the file /usr/bin/cygz.dll:
> - dlopen (libz.so) success
> - dlopen (/usr/bin/libz.so) success
> - dlopen (/usr/lib/libz.so) fails
* dlfcn.c (dlopen): For dlopen("x/lib/N"), when the application
executable is in "x/bin/", search for "x/bin/N" before "x/lib/N".
---
winsup/cygwin/dlfcn.cc | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc
index e592512..3b07208 100644
--- a/winsup/cygwin/dlfcn.cc
+++ b/winsup/cygwin/dlfcn.cc
@@ -153,6 +153,25 @@ collect_basenames (pathfinder::basenamelist & basenames,
basenames.appendv (basename, baselen, ext, extlen, NULL);
}
+/* Identify dir of current executable into exedirbuf using wpathbuf buffer.
+ Return length of exedirbuf on success, or zero on error. */
+static int
+get_exedir (char * exedirbuf)
+{
+ /* Unless we have a special cygwin loader, there is no such thing like
+ DT_RUNPATH on Windows we can use to search for dlls, except for the
+ directory of the main executable. */
+ *exedirbuf = '\0';
+ if (cygwin_conv_path (CCP_WIN_W_TO_POSIX,
+ global_progname, exedirbuf, NT_MAX_PATH))
+ return 0;
+ char * lastsep = strrchr (exedirbuf, '/');
+ if (!lastsep)
+ return 0;
+ *lastsep = 0;
+ return lastsep - exedirbuf;
+}
+
extern "C" void *
dlopen (const char *name, int flags)
{
@@ -184,13 +203,28 @@ dlopen (const char *name, int flags)
/* handle for the named library */
path_conv real_filename;
wchar_t *wpath = tp.w_get ();
+ char *cpath = tp.c_get ();
pathfinder finder (allocator, basenames); /* eats basenames */
if (have_dir)
{
+ int dirlen = basename - 1 - name;
+
+ /* if the specified dir is x/lib, and the current executable
+ dir is x/bin, do the /lib -> /bin mapping, which is the
+ same actually as adding the executable dir */
+ if (dirlen >= 4 && !strncmp (name + dirlen - 4, "/lib", 4))
+ {
+ int exedirlen = get_exedir (cpath);
+ if (exedirlen == dirlen &&
+ !strncmp (cpath, name, dirlen - 4) &&
+ !strcmp (cpath + dirlen - 4, "/bin"))
+ finder.add_searchdir (cpath, exedirlen);
+ }
+
/* search the specified dir */
- finder.add_searchdir (name, basename - 1 - name);
+ finder.add_searchdir (name, dirlen);
}
else
{
--
2.8.3