This is the mail archive of the cygwin-cvs@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[newlib-cygwin] dlopen: on x/lib search x/bin if exe is in x/bin


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=f763e2dc88d04430dd2524a529eef91a2e517e4e

commit f763e2dc88d04430dd2524a529eef91a2e517e4e
Author: Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
Date:   Fri Sep 2 13:57:20 2016 +0200

    dlopen: on x/lib search x/bin if exe is in x/bin
    
    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".

Diff:
---
 winsup/cygwin/dlfcn.cc | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc
index e592512..159d4fe 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
 	{


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]