diff options
author | Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com> | 2016-09-02 13:57:20 +0200 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2016-09-08 13:36:32 +0200 |
commit | f763e2dc88d04430dd2524a529eef91a2e517e4e (patch) | |
tree | 32de31ff7ff76234d1c60c5432cb7e21b4b9c45d /winsup/cygwin/dlfcn.cc | |
parent | b37c3ed5e57e528adf73548882cf252a79c014dd (diff) | |
download | cygnal-f763e2dc88d04430dd2524a529eef91a2e517e4e.tar.gz cygnal-f763e2dc88d04430dd2524a529eef91a2e517e4e.tar.bz2 cygnal-f763e2dc88d04430dd2524a529eef91a2e517e4e.zip |
dlopen: on x/lib search x/bin if exe is in x/binnewlib-snapshot-20160923
On 09/02/2016 11:03 AM, Corinna Vinschen wrote:
> On Sep 2 10:46, Michael Haubenwallner wrote:
>> On 09/01/2016 03:32 PM, Corinna Vinschen wrote:
>>> 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.
>
> Looks good and you're right to do it this way since I just noticed
> that program_invocation_name may return a relative pathname.
Yep.
> Btw., in other calls which require the full POSIX path we use
> mount_table->conv_to_posix_path instead of cygwin_conv_path (see
> e. g. fillout_pinfo()). It's a bit faster. Maybe something for a
> followup patch.
No problem - attached.
This renders the original patch 4/4 valid again.
> Note for some later improvement: I really wonder why we don't store
> the absolute POSIX path of the current executable globally yet...
Same here.
Thanks!
/haubi/
>From f7255edd33cb4abe34f27188aab8dccdfa5dd2a0 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".
Diffstat (limited to 'winsup/cygwin/dlfcn.cc')
-rw-r--r-- | winsup/cygwin/dlfcn.cc | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index e592512ad..159d4fe88 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -20,6 +20,7 @@ details. */ #include "cygtls.h" #include "tls_pbuf.h" #include "ntdll.h" +#include "shared_info.h" #include "pathfinder.h" /* Dumb allocator using memory from tmp_pathbuf.w_get (). @@ -153,6 +154,31 @@ 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. */ + *exedirbuf = '\0'; + + wchar_t * wlastsep = wcpcpy (wpathbuf, global_progname); + /* like wcsrchr(L'\\'), but we know the wcslen already */ + while (--wlastsep > wpathbuf) + if (*wlastsep == L'\\') + break; + if (wlastsep <= wpathbuf) + return 0; + *wlastsep = L'\0'; + + if (mount_table->conv_to_posix_path (wpathbuf, exedirbuf, 0)) + return 0; + + return strlen (exedirbuf); +} + extern "C" void * dlopen (const char *name, int flags) { @@ -184,13 +210,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 { |