summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile128
-rw-r--r--cache.h1
-rw-r--r--common-main.c4
-rw-r--r--compat/mingw.c5
-rw-r--r--config.mak.uname9
-rw-r--r--exec-cmd.c258
-rw-r--r--exec-cmd.h4
-rw-r--r--gettext.c8
-rw-r--r--git.c2
-rw-r--r--perl/Git/I18N.pm2
-rw-r--r--perl/header_templates/fixed_prefix.template.pl1
-rw-r--r--perl/header_templates/runtime_prefix.template.pl42
-rwxr-xr-xt/t0061-run-command.sh2
14 files changed, 412 insertions, 55 deletions
diff --git a/.gitignore b/.gitignore
index 2d0450c262..8d9a458555 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
/GIT-LDFLAGS
/GIT-PREFIX
/GIT-PERL-DEFINES
+/GIT-PERL-HEADER
/GIT-PYTHON-VARS
/GIT-SCRIPT-DEFINES
/GIT-USER-AGENT
diff --git a/Makefile b/Makefile
index b345d0eaa9..46a215dc89 100644
--- a/Makefile
+++ b/Makefile
@@ -441,6 +441,29 @@ all::
#
# When cross-compiling, define HOST_CPU as the canonical name of the CPU on
# which the built Git will run (for instance "x86_64").
+#
+# Define RUNTIME_PREFIX to configure Git to resolve its ancillary tooling and
+# support files relative to the location of the runtime binary, rather than
+# hard-coding them into the binary. Git installations built with RUNTIME_PREFIX
+# can be moved to arbitrary filesystem locations. RUNTIME_PREFIX also causes
+# Perl scripts to use a modified entry point header allowing them to resolve
+# support files at runtime.
+#
+# When using RUNTIME_PREFIX, define HAVE_BSD_KERN_PROC_SYSCTL if your platform
+# supports the KERN_PROC BSD sysctl function.
+#
+# When using RUNTIME_PREFIX, define PROCFS_EXECUTABLE_PATH if your platform
+# mounts a "procfs" filesystem capable of resolving the path of the current
+# executable. If defined, this must be the canonical path for the "procfs"
+# current executable path.
+#
+# When using RUNTIME_PREFIX, define HAVE_NS_GET_EXECUTABLE_PATH if your platform
+# supports calling _NSGetExecutablePath to retrieve the path of the running
+# executable.
+#
+# When using RUNTIME_PREFIX, define HAVE_WPGMPTR if your platform offers
+# the global variable _wpgmptr containing the absolute path of the current
+# executable (this is the case on Windows).
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -478,6 +501,8 @@ ARFLAGS = rcs
# mandir
# infodir
# htmldir
+# localedir
+# perllibdir
# This can help installing the suite in a relocatable way.
prefix = $(HOME)
@@ -502,7 +527,9 @@ bindir_relative = $(patsubst $(prefix)/%,%,$(bindir))
mandir_relative = $(patsubst $(prefix)/%,%,$(mandir))
infodir_relative = $(patsubst $(prefix)/%,%,$(infodir))
gitexecdir_relative = $(patsubst $(prefix)/%,%,$(gitexecdir))
+localedir_relative = $(patsubst $(prefix)/%,%,$(localedir))
htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
+perllibdir_relative = $(patsubst $(prefix)/%,%,$(perllibdir))
export prefix bindir sharedir sysconfdir gitwebdir perllibdir localedir
@@ -1670,10 +1697,27 @@ ifdef HAVE_BSD_SYSCTL
BASIC_CFLAGS += -DHAVE_BSD_SYSCTL
endif
+ifdef HAVE_BSD_KERN_PROC_SYSCTL
+ BASIC_CFLAGS += -DHAVE_BSD_KERN_PROC_SYSCTL
+endif
+
ifdef HAVE_GETDELIM
BASIC_CFLAGS += -DHAVE_GETDELIM
endif
+ifneq ($(PROCFS_EXECUTABLE_PATH),)
+ procfs_executable_path_SQ = $(subst ','\'',$(PROCFS_EXECUTABLE_PATH))
+ BASIC_CFLAGS += '-DPROCFS_EXECUTABLE_PATH="$(procfs_executable_path_SQ)"'
+endif
+
+ifdef HAVE_NS_GET_EXECUTABLE_PATH
+ BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH
+endif
+
+ifdef HAVE_WPGMPTR
+ BASIC_CFLAGS += -DHAVE_WPGMPTR
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK = NoThanks
endif
@@ -1758,11 +1802,13 @@ mandir_relative_SQ = $(subst ','\'',$(mandir_relative))
infodir_relative_SQ = $(subst ','\'',$(infodir_relative))
perllibdir_SQ = $(subst ','\'',$(perllibdir))
localedir_SQ = $(subst ','\'',$(localedir))
+localedir_relative_SQ = $(subst ','\'',$(localedir_relative))
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
gitexecdir_relative_SQ = $(subst ','\'',$(gitexecdir_relative))
template_dir_SQ = $(subst ','\'',$(template_dir))
htmldir_relative_SQ = $(subst ','\'',$(htmldir_relative))
prefix_SQ = $(subst ','\'',$(prefix))
+perllibdir_relative_SQ = $(subst ','\'',$(perllibdir_relative))
gitwebdir_SQ = $(subst ','\'',$(gitwebdir))
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
@@ -1773,6 +1819,31 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
DIFF_SQ = $(subst ','\'',$(DIFF))
PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
+# RUNTIME_PREFIX's resolution logic requires resource paths to be expressed
+# relative to each other and share an installation path.
+#
+# This is a dependency in:
+# - Git's binary RUNTIME_PREFIX logic in (see "exec_cmd.c").
+# - The runtime prefix Perl header (see
+# "perl/header_templates/runtime_prefix.template.pl").
+ifdef RUNTIME_PREFIX
+
+ifneq ($(filter /%,$(firstword $(gitexecdir_relative))),)
+$(error RUNTIME_PREFIX requires a relative gitexecdir, not: $(gitexecdir))
+endif
+
+ifneq ($(filter /%,$(firstword $(localedir_relative))),)
+$(error RUNTIME_PREFIX requires a relative localedir, not: $(localedir))
+endif
+
+ifndef NO_PERL
+ifneq ($(filter /%,$(firstword $(perllibdir_relative))),)
+$(error RUNTIME_PREFIX requires a relative perllibdir, not: $(perllibdir))
+endif
+endif
+
+endif
+
# We must filter out any object files from $(GITLIBS),
# as it is typically used like:
#
@@ -1993,27 +2064,44 @@ git.res: git.rc GIT-VERSION-FILE
# This makes sure we depend on the NO_PERL setting itself.
$(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS
-ifndef NO_PERL
-$(SCRIPT_PERL_GEN):
+# Used for substitution in Perl modules. Disabled when using RUNTIME_PREFIX
+# since the locale directory is injected.
+perl_localedir_SQ = $(localedir_SQ)
+ifndef NO_PERL
+PERL_HEADER_TEMPLATE = perl/header_templates/fixed_prefix.template.pl
PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ):$(perllibdir_SQ)
-$(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-VERSION-FILE
+
+PERL_DEFINES := $(PERL_PATH_SQ) $(PERLLIB_EXTRA_SQ) $(perllibdir_SQ)
+PERL_DEFINES += $(RUNTIME_PREFIX)
+
+# Support Perl runtime prefix. In this mode, a different header is installed
+# into Perl scripts.
+ifdef RUNTIME_PREFIX
+
+PERL_HEADER_TEMPLATE = perl/header_templates/runtime_prefix.template.pl
+
+# Don't export a fixed $(localedir) path; it will be resolved by the Perl header
+# at runtime.
+perl_localedir_SQ =
+
+endif
+
+PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir)
+
+$(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
- INSTLIBDIR='$(perllibdir_SQ)' && \
- INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
- INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
sed -e '1{' \
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
- -e ' h' \
- -e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "'"$$INSTLIBDIR"'"));=' \
- -e ' H' \
- -e ' x' \
+ -e ' rGIT-PERL-HEADER' \
+ -e ' G' \
-e '}' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
$< >$@+ && \
chmod +x $@+ && \
mv $@+ $@
+PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES))
GIT-PERL-DEFINES: FORCE
@FLAGS='$(PERL_DEFINES)'; \
if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
@@ -2021,6 +2109,19 @@ GIT-PERL-DEFINES: FORCE
echo "$$FLAGS" >$@; \
fi
+GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile
+ $(QUIET_GEN)$(RM) $@ && \
+ INSTLIBDIR='$(perllibdir_SQ)' && \
+ INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
+ INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
+ sed -e 's=@@PATHSEP@@=$(pathsep)=g' \
+ -e "s=@@INSTLIBDIR@@=$$INSTLIBDIR=g" \
+ -e 's=@@PERLLIBDIR_REL@@=$(perllibdir_relative_SQ)=g' \
+ -e 's=@@GITEXECDIR_REL@@=$(gitexecdir_relative_SQ)=g' \
+ -e 's=@@LOCALEDIR_REL@@=$(localedir_relative_SQ)=g' \
+ $< >$@+ && \
+ mv $@+ $@
+
.PHONY: perllibdir
perllibdir:
@echo '$(perllibdir_SQ)'
@@ -2168,6 +2269,7 @@ endif
exec-cmd.sp exec-cmd.s exec-cmd.o: GIT-PREFIX
exec-cmd.sp exec-cmd.s exec-cmd.o: EXTRA_CPPFLAGS = \
'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
+ '-DGIT_LOCALE_PATH="$(localedir_relative_SQ)"' \
'-DBINDIR="$(bindir_relative_SQ)"' \
'-DPREFIX="$(prefix_SQ)"'
@@ -2185,7 +2287,7 @@ attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
gettext.sp gettext.s gettext.o: GIT-PREFIX
gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
- -DGIT_LOCALE_PATH='"$(localedir_SQ)"'
+ -DGIT_LOCALE_PATH='"$(localedir_relative_SQ)"'
http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SPARSE_FLAGS += \
-DCURL_DISABLE_TYPECHECK
@@ -2345,7 +2447,7 @@ endif
perl/build/lib/%.pm: perl/%.pm
$(QUIET_GEN)mkdir -p $(dir $@) && \
- sed -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
+ sed -e 's|@@LOCALEDIR@@|$(perl_localedir_SQ)|g' \
-e 's|@@NO_PERL_CPAN_FALLBACKS@@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \
< $< > $@
@@ -2803,7 +2905,7 @@ ifndef NO_TCLTK
endif
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
$(RM) GIT-USER-AGENT GIT-PREFIX
- $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PYTHON-VARS
+ $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
.PHONY: all install profile-clean clean strip
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --git a/cache.h b/cache.h
index 77b7acebb6..6f14cfbb6f 100644
--- a/cache.h
+++ b/cache.h
@@ -428,6 +428,7 @@ static inline enum object_type object_type(unsigned int mode)
#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
+#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
/*
* Environment variable used in handshaking the wire protocol.
diff --git a/common-main.c b/common-main.c
index b989e136b5..3728f66b4c 100644
--- a/common-main.c
+++ b/common-main.c
@@ -32,14 +32,14 @@ int main(int argc, const char **argv)
*/
sanitize_stdfds();
+ git_resolve_executable_dir(argv[0]);
+
git_setup_gettext();
initialize_the_repository();
attr_start();
- git_extract_argv0_path(argv[0]);
-
restore_sigpipe_to_default();
return cmd_main(argc, argv);
diff --git a/compat/mingw.c b/compat/mingw.c
index a67872babf..6ded1c859f 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2221,7 +2221,7 @@ void mingw_startup(void)
die_startup();
/* determine size of argv and environ conversion buffer */
- maxlen = wcslen(_wpgmptr);
+ maxlen = wcslen(wargv[0]);
for (i = 1; i < argc; i++)
maxlen = max(maxlen, wcslen(wargv[i]));
for (i = 0; wenv[i]; i++)
@@ -2241,8 +2241,7 @@ void mingw_startup(void)
buffer = malloc_startup(maxlen);
/* convert command line arguments and environment to UTF-8 */
- __argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
- for (i = 1; i < argc; i++)
+ for (i = 0; i < argc; i++)
__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
for (i = 0; wenv[i]; i++)
environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);
diff --git a/config.mak.uname b/config.mak.uname
index 6a1d0de0cc..a6e734c5d4 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -37,6 +37,7 @@ ifeq ($(uname_S),Linux)
HAVE_GETDELIM = YesPlease
SANE_TEXT_GREP=-a
FREAD_READS_DIRECTORIES = UnfortunatelyYes
+ PROCFS_EXECUTABLE_PATH = /proc/self/exe
endif
ifeq ($(uname_S),GNU/kFreeBSD)
HAVE_ALLOCA_H = YesPlease
@@ -111,6 +112,7 @@ ifeq ($(uname_S),Darwin)
BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
HAVE_BSD_SYSCTL = YesPlease
FREAD_READS_DIRECTORIES = UnfortunatelyYes
+ HAVE_NS_GET_EXECUTABLE_PATH = YesPlease
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@@ -205,6 +207,7 @@ ifeq ($(uname_S),FreeBSD)
HAVE_PATHS_H = YesPlease
GMTIME_UNRELIABLE_ERRORS = UnfortunatelyYes
HAVE_BSD_SYSCTL = YesPlease
+ HAVE_BSD_KERN_PROC_SYSCTL = YesPlease
PAGER_ENV = LESS=FRX LV=-c MORE=FRX
FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
@@ -217,6 +220,8 @@ ifeq ($(uname_S),OpenBSD)
BASIC_LDFLAGS += -L/usr/local/lib
HAVE_PATHS_H = YesPlease
HAVE_BSD_SYSCTL = YesPlease
+ HAVE_BSD_KERN_PROC_SYSCTL = YesPlease
+ PROCFS_EXECUTABLE_PATH = /proc/curproc/file
endif
ifeq ($(uname_S),MirBSD)
NO_STRCASESTR = YesPlease
@@ -235,6 +240,8 @@ ifeq ($(uname_S),NetBSD)
USE_ST_TIMESPEC = YesPlease
HAVE_PATHS_H = YesPlease
HAVE_BSD_SYSCTL = YesPlease
+ HAVE_BSD_KERN_PROC_SYSCTL = YesPlease
+ PROCFS_EXECUTABLE_PATH = /proc/curproc/exe
endif
ifeq ($(uname_S),AIX)
DEFAULT_PAGER = more
@@ -350,6 +357,7 @@ ifeq ($(uname_S),Windows)
SNPRINTF_RETURNS_BOGUS = YesPlease
NO_SVN_TESTS = YesPlease
RUNTIME_PREFIX = YesPlease
+ HAVE_WPGMPTR = YesWeDo
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease
@@ -499,6 +507,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_SVN_TESTS = YesPlease
NO_PERL_MAKEMAKER = YesPlease
RUNTIME_PREFIX = YesPlease
+ HAVE_WPGMPTR = YesWeDo
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease
diff --git a/exec-cmd.c b/exec-cmd.c
index 8a8261746a..3b0a039083 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -2,24 +2,52 @@
#include "exec-cmd.h"
#include "quote.h"
#include "argv-array.h"
-#define MAX_ARGS 32
-static const char *argv_exec_path;
+#if defined(RUNTIME_PREFIX)
+
+#if defined(HAVE_NS_GET_EXECUTABLE_PATH)
+#include <mach-o/dyld.h>
+#endif
+
+#if defined(HAVE_BSD_KERN_PROC_SYSCTL)
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+#endif /* RUNTIME_PREFIX */
+
+#define MAX_ARGS 32
+
+static const char *system_prefix(void);
#ifdef RUNTIME_PREFIX
-static const char *argv0_path;
+
+/**
+ * When using a runtime prefix, Git dynamically resolves paths relative to its
+ * executable.
+ *
+ * The method for determining the path of the executable is highly
+ * platform-specific.
+ */
+
+/**
+ * Path to the current Git executable. Resolved on startup by
+ * 'git_resolve_executable_dir'.
+ */
+static const char *executable_dirname;
static const char *system_prefix(void)
{
static const char *prefix;
- assert(argv0_path);
- assert(is_absolute_path(argv0_path));
+ assert(executable_dirname);
+ assert(is_absolute_path(executable_dirname));
if (!prefix &&
- !(prefix = strip_path_suffix(argv0_path, GIT_EXEC_PATH)) &&
- !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
- !(prefix = strip_path_suffix(argv0_path, "git"))) {
+ !(prefix = strip_path_suffix(executable_dirname, GIT_EXEC_PATH)) &&
+ !(prefix = strip_path_suffix(executable_dirname, BINDIR)) &&
+ !(prefix = strip_path_suffix(executable_dirname, "git"))) {
prefix = PREFIX;
trace_printf("RUNTIME_PREFIX requested, "
"but prefix computation failed. "
@@ -28,27 +56,201 @@ static const char *system_prefix(void)
return prefix;
}
-void git_extract_argv0_path(const char *argv0)
+/*
+ * Resolves the executable path from argv[0], only if it is absolute.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_from_argv0(struct strbuf *buf, const char *argv0)
{
const char *slash;
if (!argv0 || !*argv0)
- return;
+ return -1;
slash = find_last_dir_sep(argv0);
+ if (slash) {
+ trace_printf("trace: resolved executable path from argv0: %s\n",
+ argv0);
+ strbuf_add_absolute_path(buf, argv0);
+ return 0;
+ }
+ return -1;
+}
+
+#ifdef PROCFS_EXECUTABLE_PATH
+/*
+ * Resolves the executable path by examining a procfs symlink.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_procfs(struct strbuf *buf)
+{
+ if (strbuf_realpath(buf, PROCFS_EXECUTABLE_PATH, 0)) {
+ trace_printf(
+ "trace: resolved executable path from procfs: %s\n",
+ buf->buf);
+ return 0;
+ }
+ return -1;
+}
+#endif /* PROCFS_EXECUTABLE_PATH */
+
+#ifdef HAVE_BSD_KERN_PROC_SYSCTL
+/*
+ * Resolves the executable path using KERN_PROC_PATHNAME BSD sysctl.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_bsd_sysctl(struct strbuf *buf)
+{
+ int mib[4];
+ char path[MAXPATHLEN];
+ size_t cb = sizeof(path);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+ if (!sysctl(mib, 4, path, &cb, NULL, 0)) {
+ trace_printf(
+ "trace: resolved executable path from sysctl: %s\n",
+ path);
+ strbuf_addstr(buf, path);
+ return 0;
+ }
+ return -1;
+}
+#endif /* HAVE_BSD_KERN_PROC_SYSCTL */
+
+#ifdef HAVE_NS_GET_EXECUTABLE_PATH
+/*
+ * Resolves the executable path by querying Darwin application stack.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_darwin(struct strbuf *buf)
+{
+ char path[PATH_MAX];
+ uint32_t size = sizeof(path);
+ if (!_NSGetExecutablePath(path, &size)) {
+ trace_printf(
+ "trace: resolved executable path from Darwin stack: %s\n",
+ path);
+ strbuf_addstr(buf, path);
+ return 0;
+ }
+ return -1;
+}
+#endif /* HAVE_NS_GET_EXECUTABLE_PATH */
+
+#ifdef HAVE_WPGMPTR
+/*
+ * Resolves the executable path by using the global variable _wpgmptr.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_wpgmptr(struct strbuf *buf)
+{
+ int len = wcslen(_wpgmptr) * 3 + 1;
+ strbuf_grow(buf, len);
+ len = xwcstoutf(buf->buf, _wpgmptr, len);
+ if (len < 0)
+ return -1;
+ buf->len += len;
+ return 0;
+}
+#endif /* HAVE_WPGMPTR */
+
+/*
+ * Resolves the absolute path of the current executable.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path(struct strbuf *buf, const char *argv0)
+{
+ /*
+ * Identifying the executable path is operating system specific.
+ * Selectively employ all available methods in order of preference,
+ * preferring highly-available authoritative methods over
+ * selectively-available or non-authoritative methods.
+ *
+ * All cases fall back on resolving against argv[0] if there isn't a
+ * better functional method. However, note that argv[0] can be
+ * used-supplied on many operating systems, and is not authoritative
+ * in those cases.
+ *
+ * Each of these functions returns 0 on success, so evaluation will stop
+ * after the first successful method.
+ */
+ if (
+#ifdef HAVE_BSD_KERN_PROC_SYSCTL
+ git_get_exec_path_bsd_sysctl(buf) &&
+#endif /* HAVE_BSD_KERN_PROC_SYSCTL */
+
+#ifdef HAVE_NS_GET_EXECUTABLE_PATH
+ git_get_exec_path_darwin(buf) &&
+#endif /* HAVE_NS_GET_EXECUTABLE_PATH */
+
+#ifdef PROCFS_EXECUTABLE_PATH
+ git_get_exec_path_procfs(buf) &&
+#endif /* PROCFS_EXECUTABLE_PATH */
+
+#ifdef HAVE_WPGMPTR
+ git_get_exec_path_wpgmptr(buf) &&
+#endif /* HAVE_WPGMPTR */
+
+ git_get_exec_path_from_argv0(buf, argv0)) {
+ return -1;
+ }
+
+ if (strbuf_normalize_path(buf)) {
+ trace_printf("trace: could not normalize path: %s\n", buf->buf);
+ return -1;
+ }
+
+ return 0;
+}
+void git_resolve_executable_dir(const char *argv0)
+{
+ struct strbuf buf = STRBUF_INIT;
+ char *resolved;
+ const char *slash;
+
+ if (git_get_exec_path(&buf, argv0)) {
+ trace_printf(
+ "trace: could not determine executable path from: %s\n",
+ argv0);
+ strbuf_release(&buf);
+ return;
+ }
+
+ resolved = strbuf_detach(&buf, NULL);
+ slash = find_last_dir_sep(resolved);
if (slash)
- argv0_path = xstrndup(argv0, slash - argv0);
+ resolved[slash - resolved] = '\0';
+
+ executable_dirname = resolved;
+ trace_printf("trace: resolved executable dir: %s\n",
+ executable_dirname);
}
#else
+/*
+ * When not using a runtime prefix, Git uses a hard-coded path.
+ */
static const char *system_prefix(void)
{
return PREFIX;
}
-void git_extract_argv0_path(const char *argv0)
+/*
+ * This is called during initialization, but No work needs to be done here when
+ * runtime prefix is not being used.
+ */
+void git_resolve_executable_dir(const char *argv0)
{
}
@@ -65,32 +267,28 @@ char *system_path(const char *path)
return strbuf_detach(&d, NULL);
}
-void git_set_argv_exec_path(const char *exec_path)
+static const char *exec_path_value;
+
+void git_set_exec_path(const char *exec_path)
{
- argv_exec_path = exec_path;
+ exec_path_value = exec_path;
/*
* Propagate this setting to external programs.
*/
setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
}
-
-/* Returns the highest-priority, location to look for git programs. */
+/* Returns the highest-priority location to look for git programs. */
const char *git_exec_path(void)
{
- static char *cached_exec_path;
-
- if (argv_exec_path)
- return argv_exec_path;
-
- if (!cached_exec_path) {
+ if (!exec_path_value) {
const char *env = getenv(EXEC_PATH_ENVIRONMENT);
if (env && *env)
- cached_exec_path = xstrdup(env);
+ exec_path_value = xstrdup(env);
else
- cached_exec_path = system_path(GIT_EXEC_PATH);
+ exec_path_value = system_path(GIT_EXEC_PATH);
}
- return cached_exec_path;
+ return exec_path_value;
}
static void add_path(struct strbuf *out, const char *path)
@@ -103,10 +301,12 @@ static void add_path(struct strbuf *out, const char *path)
void setup_path(void)
{
+ const char *exec_path = git_exec_path();
const char *old_path = getenv("PATH");
struct strbuf new_path = STRBUF_INIT;
- add_path(&new_path, git_exec_path());
+ git_set_exec_path(exec_path);
+ add_path(&new_path, exec_path);
if (old_path)
strbuf_addstr(&new_path, old_path);
@@ -125,7 +325,8 @@ const char **prepare_git_cmd(struct argv_array *out, const char **argv)
return out->argv;
}
-int execv_git_cmd(const char **argv) {
+int execv_git_cmd(const char **argv)
+{
struct argv_array nargv = ARGV_ARRAY_INIT;
prepare_git_cmd(&nargv, argv);
@@ -140,8 +341,7 @@ int execv_git_cmd(const char **argv) {
return -1;
}
-
-int execl_git_cmd(const char *cmd,...)
+int execl_git_cmd(const char *cmd, ...)
{
int argc;
const char *argv[MAX_ARGS + 1];
diff --git a/exec-cmd.h b/exec-cmd.h
index ff0b48048a..2522453cda 100644
--- a/exec-cmd.h
+++ b/exec-cmd.h
@@ -3,8 +3,8 @@
struct argv_array;
-extern void git_set_argv_exec_path(const char *exec_path);
-extern void git_extract_argv0_path(const char *path);
+extern void git_set_exec_path(const char *exec_path);
+extern void git_resolve_executable_dir(const char *path);
extern const char *git_exec_path(void);
extern void setup_path(void);
extern const char **prepare_git_cmd(struct argv_array *out, const char **argv);
diff --git a/gettext.c b/gettext.c
index db727ea020..baba28343c 100644
--- a/gettext.c
+++ b/gettext.c
@@ -2,7 +2,8 @@
* Copyright (c) 2010 Ævar Arnfjörð Bjarmason
*/
-#include "git-compat-util.h"
+#include "cache.h"
+#include "exec-cmd.h"
#include "gettext.h"
#include "strbuf.h"
#include "utf8.h"
@@ -157,10 +158,11 @@ static void init_gettext_charset(const char *domain)
void git_setup_gettext(void)
{
- const char *podir = getenv("GIT_TEXTDOMAINDIR");
+ const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
if (!podir)
- podir = GIT_LOCALE_PATH;
+ podir = system_path(GIT_LOCALE_PATH);
+
bindtextdomain("git", podir);
setlocale(LC_MESSAGES, "");
setlocale(LC_TIME, "");
diff --git a/git.c b/git.c
index 158f2cbdb1..70798f6837 100644
--- a/git.c
+++ b/git.c
@@ -83,7 +83,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*/
if (skip_prefix(cmd, "--exec-path", &cmd)) {
if (*cmd == '=')
- git_set_argv_exec_path(cmd + 1);
+ git_set_exec_path(cmd + 1);
else {
puts(git_exec_path());
exit(0);
diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm
index dba96fff0a..bfb4fb67a1 100644
--- a/perl/Git/I18N.pm
+++ b/perl/Git/I18N.pm
@@ -18,7 +18,7 @@ our @EXPORT_OK = @EXPORT;
sub __bootstrap_locale_messages {
our $TEXTDOMAIN = 'git';
- our $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '@@LOCALEDIR@@';
+ our $TEXTDOMAINDIR ||= $ENV{GIT_TEXTDOMAINDIR} || '@@LOCALEDIR@@';
require POSIX;
POSIX->import(qw(setlocale));
diff --git a/perl/header_templates/fixed_prefix.template.pl b/perl/header_templates/fixed_prefix.template.pl
new file mode 100644
index 0000000000..857b4391a4
--- /dev/null
+++ b/perl/header_templates/fixed_prefix.template.pl
@@ -0,0 +1 @@
+use lib (split(/@@PATHSEP@@/, $ENV{GITPERLLIB} || '@@INSTLIBDIR@@'));
diff --git a/perl/header_templates/runtime_prefix.template.pl b/perl/header_templates/runtime_prefix.template.pl
new file mode 100644
index 0000000000..9d28b3d863
--- /dev/null
+++ b/perl/header_templates/runtime_prefix.template.pl
@@ -0,0 +1,42 @@
+# BEGIN RUNTIME_PREFIX generated code.
+#
+# This finds our Git::* libraries relative to the script's runtime path.
+sub __git_system_path {
+ my ($relpath) = @_;
+ my $gitexecdir_relative = '@@GITEXECDIR_REL@@';
+
+ # GIT_EXEC_PATH is supplied by `git` or the test suite.
+ my $exec_path;
+ if (exists $ENV{GIT_EXEC_PATH}) {
+ $exec_path = $ENV{GIT_EXEC_PATH};
+ } else {
+ # This can happen if this script is being directly invoked instead of run
+ # by "git".
+ require FindBin;
+ $exec_path = $FindBin::Bin;
+ }
+
+ # Trim off the relative gitexecdir path to get the system path.
+ (my $prefix = $exec_path) =~ s/\Q$gitexecdir_relative\E$//;
+
+ require File::Spec;
+ return File::Spec->catdir($prefix, $relpath);
+}
+
+BEGIN {
+ use lib split /@@PATHSEP@@/,
+ (
+ $ENV{GITPERLLIB} ||
+ do {
+ my $perllibdir = __git_system_path('@@PERLLIBDIR_REL@@');
+ (-e $perllibdir) || die("Invalid system path ($relpath): $path");
+ $perllibdir;
+ }
+ );
+
+ # Export the system locale directory to the I18N module. The locale directory
+ # is only installed if NO_GETTEXT is set.
+ $Git::I18N::TEXTDOMAINDIR = __git_system_path('@@LOCALEDIR_REL@@');
+}
+
+# END RUNTIME_PREFIX generated code.
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index d03149be9f..c887ed5b45 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -145,7 +145,7 @@ test_trace () {
expect="$1"
shift
GIT_TRACE=1 test-tool run-command "$@" run-command true 2>&1 >/dev/null | \
- sed 's/.* run_command: //' >actual &&
+ sed -e 's/.* run_command: //' -e '/trace: .*/d' >actual &&
echo "$expect true" >expect &&
test_cmp expect actual
}