This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Where available, use _NSGetExecutablePath() to make $^X absolute.
authorNicholas Clark <nick@ccl4.org>
Wed, 21 Sep 2011 14:33:09 +0000 (15:33 +0100)
committerNicholas Clark <nick@ccl4.org>
Tue, 27 Sep 2011 20:25:05 +0000 (22:25 +0200)
In Configure, check whether _NSGetExecutablePath() can be used to find the
absolute pathname of the executable. If so, set usensgetexecutablepath in
config.sh and USE_NSGETEXECUTABLEPATH in config.h. If this is set, then use
this approach in S_set_caret_X() to canonicalise $^X as an absolute
path. This approach works on OS X, and possible on other platforms that
use dyld.

21 files changed:
Configure
Cross/config.sh-arm-linux
NetWare/config.wc
Porting/Glossary
Porting/config.sh
config_h.SH
configure.com
epoc/config.sh
perl.c
plan9/config_sh.sample
symbian/config.sh
t/op/magic.t
uconfig.h
uconfig.sh
uconfig64.sh
win32/config.ce
win32/config.gc
win32/config.gc64
win32/config.gc64nox
win32/config.vc
win32/config.vc64

index 691bd81..1f0dbef 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -1229,6 +1229,7 @@ nm_opt=''
 nm_so_opt=''
 runnm=''
 usenm=''
+usensgetexecutablepath=''
 useperlio=''
 usesocks=''
 d_oldpthreads=''
@@ -19462,6 +19463,106 @@ $rm_try
 set usekernprocpathname
 eval $setvar
 
+: Determine if we can use _NSGetExecutablePath to find executing program
+echo " "
+echo "Determining whether we can use _NSGetExecutablePath to find executing program..." >&4
+$cat >try.c <<'EOM'
+/* Intentionally a long probe as I'd like to sanity check that the exact
+   approach is going to work, as thinking it will work, but only having it
+   part working at runtime is worse than not having it.  */
+#include <mach-o/dyld.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <string.h>
+
+int
+main(int argc, char **argv) {
+    char buf[1];
+    uint32_t size = sizeof(buf);
+    int result;
+    char *buffer;
+    char *tidied;
+    char *argv_leaf = strrchr(argv[0], '/');
+    char *tidied_leaf;
+
+    if (!argv_leaf) {
+       fprintf(stderr, "Can't locate / in '%s'\n", argv[0]);
+       return 1;
+    }
+
+    _NSGetExecutablePath(buf, &size);
+    if (size > MAXPATHLEN * MAXPATHLEN) {
+       fprintf(stderr, "_NSGetExecutablePath size %u is too long for a path\n",
+               (unsigned int) size);
+       return 2;
+    }
+
+    buffer = malloc(size);
+    if (!buffer) {
+       perror("malloc");
+       return 3;
+    }
+
+    result = _NSGetExecutablePath(buffer, &size);
+    if (result != 0) {
+       fprintf(stderr, "_NSGetExecutablePath returned %i for a size of %u\n",
+               result, (unsigned int) size);
+       return 4;
+    }
+
+    tidied = realpath(buffer, NULL);
+    if (!tidied) {
+       perror("realpath");
+       return 5;
+    }
+
+    free(buffer);
+
+    if (*tidied != '/') {
+       fprintf(stderr, "Not an absolute path: '%s'\n", tidied);
+       return 6;
+    }
+
+    if (strstr(tidied, "/./")) {
+       fprintf(stderr, "Contains /./: '%s'\n", tidied);
+       return 7;
+    }
+
+    if (strstr(tidied, "/../")) {
+       fprintf(stderr, "Contains /../: '%s'\n", tidied);
+       return 8;
+    }
+
+    tidied_leaf = strrchr(tidied, '/');
+    if (strcmp(tidied_leaf, argv_leaf) != 0) {
+       fprintf(stderr, "Leafnames differ: '%s' vs '%s'\n", argv[0], tidied);
+       return 9;
+    }
+
+    free(tidied);
+
+    return 0;
+}
+EOM
+
+val=$undef
+set try
+if eval $compile_ok; then
+       if $run ./try; then
+               echo "You can use _NSGetExecutablePath to find the executing program." >&4
+               val="$define"
+       else
+               echo "Nope, _NSGetExecutablePath doesn't work here." >&4
+       fi
+else
+       echo "I'm unable to compile the test program." >&4
+       echo "I'll assume no _NSGetExecutablePath here." >&4
+fi
+$rm_try
+set usensgetexecutablepath
+eval $setvar
+
 : Check how to flush
 echo " "
 $cat >&4 <<EOM
@@ -23558,6 +23659,7 @@ usemorebits='$usemorebits'
 usemultiplicity='$usemultiplicity'
 usemymalloc='$usemymalloc'
 usenm='$usenm'
+usensgetexecutablepath='$usensgetexecutablepath'
 useopcode='$useopcode'
 useperlio='$useperlio'
 useposix='$useposix'
index 78e8829..e611e35 100644 (file)
@@ -1032,6 +1032,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='define'
 useposix='true'
index 72118f4..6750b8c 100644 (file)
@@ -995,6 +995,7 @@ usemorebits='undef'
 usemultiplicity='define'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'
index 1ed4ef8..81c83a9 100644 (file)
@@ -5053,6 +5053,11 @@ usenm (usenm.U):
        This variable contains 'true' or 'false' depending whether the
        nm extraction is wanted or not.
 
+usensgetexecutablepath (usensgetexecutablepath.U):
+       This symbol, if defined, indicates that we can use _NSGetExecutablePath
+       and realpath to get a full path for the executable, and hence convert
+       $^X to an absolute path.
+
 useopcode (Extensions.U):
        This variable holds either 'true' or 'false' to indicate
        whether the Opcode extension should be used.  The sole
index 9244924..fce3187 100644 (file)
@@ -1054,6 +1054,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='define'
 useposix='true'
index 9281cdd..7b8d31e 100755 (executable)
@@ -2696,6 +2696,13 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
  */
 #$usekernprocpathname USE_KERN_PROC_PATHNAME           /**/
 
+/* USE_NSGETEXECUTABLEPATH:
+ *     This symbol, if defined, indicates that we can use _NSGetExecutablePath
+ *     and realpath to get a full path for the executable, and hence convert
+ *     $^X to an absolute path.
+ */
+#$usensgetexecutablepath USE_NSGETEXECUTABLEPATH               /**/
+
 /* Fpos_t:
  *     This symbol holds the type used to declare file positions in libc.
  *     It can be fpos_t, long, uint, etc... It may be necessary to include
index a58f77e..5da5973 100644 (file)
@@ -6718,6 +6718,7 @@ $ WC "useieee='" + useieee + "'"                    ! VMS-specific
 $ WC "useithreads='" + useithreads + "'"
 $ WC "usekernelthreads='" + usekernelthreads + "'"     ! VMS-specific
 $ WC "usekernprocpathname='undef'"
+$ WC "usensgetexecutablepath='undef'"
 $ WC "uselargefiles='" + uselargefiles + "'"
 $ WC "uselongdouble='" + uselongdouble + "'"
 $ WC "usemorebits='" + usemorebits + "'"
index b71d62e..c805890 100644 (file)
@@ -991,6 +991,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm=''
+usensgetexecutablepath='undef'
 useopcode=''
 useperlio='undef'
 useposix=''
diff --git a/perl.c b/perl.c
index 5d2159d..4285834 100644 (file)
--- a/perl.c
+++ b/perl.c
 #  include <sys/sysctl.h>
 #endif
 
+#ifdef USE_NSGETEXECUTABLEPATH
+#  include <mach-o/dyld.h>
+#endif
+
 #ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
 #  ifdef I_SYSUIO
 #    include <sys/uio.h>
@@ -1414,6 +1418,26 @@ S_set_caret_X(pTHX) {
                return;
            }
        }
+#  elif defined(USE_NSGETEXECUTABLEPATH)
+       char buf[1];
+       uint32_t size = sizeof(buf);
+       int result;
+
+       _NSGetExecutablePath(buf, &size);
+       if (size < MAXPATHLEN * MAXPATHLEN) {
+           sv_grow(caret_x, size);
+           if (_NSGetExecutablePath(SvPVX(caret_x), &size) == 0) {
+               char *const tidied = realpath(SvPVX(caret_x), NULL);
+               if (tidied) {
+                   sv_setpv(caret_x, tidied);
+                   free(tidied);
+               } else {
+                   SvPOK_only(caret_x);
+                   SvCUR_set(caret_x, size);
+               }
+               return;
+           }
+       }
 #  elif defined(HAS_PROCSELFEXE)
        char buf[MAXPATHLEN];
        int len = readlink(PROCSELFEXE_PATH, buf, sizeof(buf) - 1);
index b87320d..bd5da2f 100644 (file)
@@ -1003,6 +1003,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='y'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='define'
 useposix='true'
index c72d8c3..a62577b 100644 (file)
@@ -818,6 +818,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='define'
 useposix='true'
index 5569154..8c2c508 100644 (file)
@@ -230,7 +230,8 @@ $$ = $pid; # Tests below use $$
 
 # $^X and $0
 {
-    my $is_abs = $Config{d_procselfexe} || $Config{usekernprocpathname};
+    my $is_abs = $Config{d_procselfexe} || $Config{usekernprocpathname}
+      || $Config{usensgetexecutablepath};
     if ($^O eq 'qnx') {
        chomp($wd = `/usr/bin/fullpath -t`);
     }
index c5f19f7..c379902 100644 (file)
--- a/uconfig.h
+++ b/uconfig.h
  */
 /*#define USE_KERN_PROC_PATHNAME               / **/
 
+/* USE_NSGETEXECUTABLEPATH:
+ *     This symbol, if defined, indicates that we can use _NSGetExecutablePath
+ *     and realpath to get a full path for the executable, and hence convert
+ *     $^X to an absolute path.
+ */
+/*#define USE_NSGETEXECUTABLEPATH              / **/
+
 /* Fpos_t:
  *     This symbol holds the type used to declare file positions in libc.
  *     It can be fpos_t, long, uint, etc... It may be necessary to include
 #endif
 
 /* Generated from:
- * e6513dfa5f1449ab9266aee521d6d5908873d1dc68bf4f049316ebc4921732e1 config_h.SH
- * e940950d07a2be0354d6ae7e4316ec8465ed581607bbb958d8bfda024b9941fe uconfig.sh
+ * 5b5dacbb00f53ae9b440c79cf6d5c8bbf80a7adfa1db3f3814aa77dc6f461fa7 config_h.SH
+ * b5e74633486412bbc4d2a1c3847f3e85b10a86e96fb5d1efb7b8bc885956d746 uconfig.sh
  * ex: set ro: */
index ee84d35..e7692dc 100644 (file)
@@ -785,6 +785,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'
index e3346e7..1ae544f 100644 (file)
@@ -786,6 +786,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'
index 8028928..62d2123 100644 (file)
@@ -985,6 +985,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='~USE_PERLIO~'
 useposix='true'
index ff6eb6f..cb963fb 100644 (file)
@@ -1028,6 +1028,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'
index e46b55a..7e06e2a 100644 (file)
@@ -1029,6 +1029,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'
index 82226e9..92ef05f 100644 (file)
@@ -1029,6 +1029,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'
index f578057..379a125 100644 (file)
@@ -1028,6 +1028,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'
index 86b4040..d429f20 100644 (file)
@@ -1028,6 +1028,7 @@ usemorebits='undef'
 usemultiplicity='undef'
 usemymalloc='n'
 usenm='false'
+usensgetexecutablepath='undef'
 useopcode='true'
 useperlio='undef'
 useposix='true'