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