Makefile: add Perl runtime prefix support

Broaden the RUNTIME_PREFIX flag to configure Git's Perl scripts to locate the Git installation's Perl support libraries by resolving against the script's path, rather than hard-coding that path at build-time. Hard-coding at build time worked on previous RUNTIME_PREFIX configurations (i.e., Windows) because the Perl scripts were run within a virtual filesystem whose paths were consistent regardless of the location of the actual installation. This will no longer be the case for non-Windows RUNTIME_PREFIX users. When enabled, RUNTIME_PREFIX now requires Perl's system paths to be expressed relative to a common installation directory in the Makefile, and uses that relationship to locate support files based on the known starting point of the script being executed, much like RUNTIME_PREFIX does for the Git binary. This change enables Git's Perl scripts to work when their Git installation is relocated or moved to another system, even when they are not in a virtual filesystem environment. Signed-off-by: Dan Jacques <dnj@google.com> Thanks-to: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Thanks-to: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Dan Jacques committed Apr 10, 2018 at 11:05 UTC 07d90eadb50ee687a7313186b654975b0944a74e
3 files changed +107 -2
Makefile
+64 -1
@@ -441,6 +441,13 @@ all::
441 #
442 # When cross-compiling, define HOST_CPU as the canonical name of the CPU on
443 # which the built Git will run (for instance "x86_64").
444 +#
445 +# Define RUNTIME_PREFIX to configure Git to resolve its ancillary tooling and
446 +# support files relative to the location of the runtime binary, rather than
447 +# hard-coding them into the binary. Git installations built with RUNTIME_PREFIX
448 +# can be moved to arbitrary filesystem locations. RUNTIME_PREFIX also causes
449 +# Perl scripts to use a modified entry point header allowing them to resolve
450 +# support files at runtime.
451
452 GIT-VERSION-FILE: FORCE
453 @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -478,6 +485,8 @@ ARFLAGS = rcs
485 # mandir
486 # infodir
487 # htmldir
488 +# localedir
489 +# perllibdir
490 # This can help installing the suite in a relocatable way.
491
492 prefix = $(HOME)
@@ -502,7 +511,9 @@ bindir_relative = $(patsubst $(prefix)/%,%,$(bindir))
511 mandir_relative = $(patsubst $(prefix)/%,%,$(mandir))
512 infodir_relative = $(patsubst $(prefix)/%,%,$(infodir))
513 gitexecdir_relative = $(patsubst $(prefix)/%,%,$(gitexecdir))
514 +localedir_relative = $(patsubst $(prefix)/%,%,$(localedir))
515 htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
516 +perllibdir_relative = $(patsubst $(prefix)/%,%,$(perllibdir))
517
518 export prefix bindir sharedir sysconfdir gitwebdir perllibdir localedir
519
@@ -1751,11 +1762,13 @@ mandir_relative_SQ = $(subst ','\'',$(mandir_relative))
1762 infodir_relative_SQ = $(subst ','\'',$(infodir_relative))
1763 perllibdir_SQ = $(subst ','\'',$(perllibdir))
1764 localedir_SQ = $(subst ','\'',$(localedir))
1765 +localedir_relative_SQ = $(subst ','\'',$(localedir_relative))
1766 gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
1767 gitexecdir_relative_SQ = $(subst ','\'',$(gitexecdir_relative))
1768 template_dir_SQ = $(subst ','\'',$(template_dir))
1769 htmldir_relative_SQ = $(subst ','\'',$(htmldir_relative))
1770 prefix_SQ = $(subst ','\'',$(prefix))
1771 +perllibdir_relative_SQ = $(subst ','\'',$(perllibdir_relative))
1772 gitwebdir_SQ = $(subst ','\'',$(gitwebdir))
1773
1774 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
@@ -1766,6 +1779,31 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
1779 DIFF_SQ = $(subst ','\'',$(DIFF))
1780 PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
1781
1782 +# RUNTIME_PREFIX's resolution logic requires resource paths to be expressed
1783 +# relative to each other and share an installation path.
1784 +#
1785 +# This is a dependency in:
1786 +# - Git's binary RUNTIME_PREFIX logic in (see "exec_cmd.c").
1787 +# - The runtime prefix Perl header (see
1788 +# "perl/header_templates/runtime_prefix.template.pl").
1789 +ifdef RUNTIME_PREFIX
1790 +
1791 +ifneq ($(filter /%,$(firstword $(gitexecdir_relative))),)
1792 +$(error RUNTIME_PREFIX requires a relative gitexecdir, not: $(gitexecdir))
1793 +endif
1794 +
1795 +ifneq ($(filter /%,$(firstword $(localedir_relative))),)
1796 +$(error RUNTIME_PREFIX requires a relative localedir, not: $(localedir))
1797 +endif
1798 +
1799 +ifndef NO_PERL
1800 +ifneq ($(filter /%,$(firstword $(perllibdir_relative))),)
1801 +$(error RUNTIME_PREFIX requires a relative perllibdir, not: $(perllibdir))
1802 +endif
1803 +endif
1804 +
1805 +endif
1806 +
1807 # We must filter out any object files from $(GITLIBS),
1808 # as it is typically used like:
1809 #
@@ -1986,10 +2024,31 @@ git.res: git.rc GIT-VERSION-FILE
2024 # This makes sure we depend on the NO_PERL setting itself.
2025 $(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS
2026
2027 +# Used for substitution in Perl modules. Disabled when using RUNTIME_PREFIX
2028 +# since the locale directory is injected.
2029 +perl_localedir_SQ = $(localedir_SQ)
2030 +
2031 ifndef NO_PERL
2032 PERL_HEADER_TEMPLATE = perl/header_templates/fixed_prefix.template.pl
2033 PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ):$(perllibdir_SQ)
2034
2035 +PERL_DEFINES := $(PERL_PATH_SQ) $(PERLLIB_EXTRA_SQ) $(perllibdir_SQ)
2036 +PERL_DEFINES += $(RUNTIME_PREFIX)
2037 +
2038 +# Support Perl runtime prefix. In this mode, a different header is installed
2039 +# into Perl scripts.
2040 +ifdef RUNTIME_PREFIX
2041 +
2042 +PERL_HEADER_TEMPLATE = perl/header_templates/runtime_prefix.template.pl
2043 +
2044 +# Don't export a fixed $(localedir) path; it will be resolved by the Perl header
2045 +# at runtime.
2046 +perl_localedir_SQ =
2047 +
2048 +endif
2049 +
2050 +PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir)
2051 +
2052 $(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE
2053 $(QUIET_GEN)$(RM) $@ $@+ && \
2054 sed -e '1{' \
@@ -2002,6 +2061,7 @@ $(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE
2061 chmod +x $@+ && \
2062 mv $@+ $@
2063
2064 +PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES))
2065 GIT-PERL-DEFINES: FORCE
2066 @FLAGS='$(PERL_DEFINES)'; \
2067 if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
@@ -2017,6 +2077,9 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile
2077 sed -e 's=@@PATHSEP@@=$(pathsep)=g' \
2078 -e 's=@@INSTLIBDIR@@='$$INSTLIBDIR'=g' \
2079 -e 's=@@PERLLIBDIR@@='$(perllibdir_SQ)'=g' \
2080 + -e 's=@@PERLLIBDIR_REL@@=$(perllibdir_relative_SQ)=g' \
2081 + -e 's=@@GITEXECDIR_REL@@=$(gitexecdir_relative_SQ)=g' \
2082 + -e 's=@@LOCALEDIR_REL@@=$(localedir_relative_SQ)=g' \
2083 $< >$@+ && \
2084 mv $@+ $@
2085
@@ -2340,7 +2403,7 @@ endif
2403
2404 perl/build/lib/%.pm: perl/%.pm
2405 $(QUIET_GEN)mkdir -p $(dir $@) && \
2343 - sed -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
2406 + sed -e 's|@@LOCALEDIR@@|$(perl_localedir_SQ)|g' \
2407 -e 's|@@NO_PERL_CPAN_FALLBACKS@@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \
2408 < $< > $@
2409
perl/Git/I18N.pm
+1 -1
@@ -18,7 +18,7 @@ our @EXPORT_OK = @EXPORT;
18
19 sub __bootstrap_locale_messages {
20 our $TEXTDOMAIN = 'git';
21 - our $TEXTDOMAINDIR = $ENV{GIT_TEXTDOMAINDIR} || '@@LOCALEDIR@@';
21 + our $TEXTDOMAINDIR ||= $ENV{GIT_TEXTDOMAINDIR} || '@@LOCALEDIR@@';
22
23 require POSIX;
24 POSIX->import(qw(setlocale));
perl/header_templates/runtime_prefix.template.pl new
+42
@@ -0,0 +1,42 @@
1 +# BEGIN RUNTIME_PREFIX generated code.
2 +#
3 +# This finds our Git::* libraries relative to the script's runtime path.
4 +sub __git_system_path {
5 + my ($relpath) = @_;
6 + my $gitexecdir_relative = '@@GITEXECDIR_REL@@';
7 +
8 + # GIT_EXEC_PATH is supplied by `git` or the test suite.
9 + my $exec_path;
10 + if (exists $ENV{GIT_EXEC_PATH}) {
11 + $exec_path = $ENV{GIT_EXEC_PATH};
12 + } else {
13 + # This can happen if this script is being directly invoked instead of run
14 + # by "git".
15 + require FindBin;
16 + $exec_path = $FindBin::Bin;
17 + }
18 +
19 + # Trim off the relative gitexecdir path to get the system path.
20 + (my $prefix = $exec_path) =~ s/\Q$gitexecdir_relative\E$//;
21 +
22 + require File::Spec;
23 + return File::Spec->catdir($prefix, $relpath);
24 +}
25 +
26 +BEGIN {
27 + use lib split /@@PATHSEP@@/,
28 + (
29 + $ENV{GITPERLLIB} ||
30 + do {
31 + my $perllibdir = __git_system_path('@@PERLLIBDIR_REL@@');
32 + (-e $perllibdir) || die("Invalid system path ($relpath): $path");
33 + $perllibdir;
34 + }
35 + );
36 +
37 + # Export the system locale directory to the I18N module. The locale directory
38 + # is only installed if NO_GETTEXT is set.
39 + $Git::I18N::TEXTDOMAINDIR = __git_system_path('@@LOCALEDIR_REL@@');
40 +}
41 +
42 +# END RUNTIME_PREFIX generated code.