Subject: Re: bug#37527: [PATCH] Install C source code for for debugging help

From: Paul Eggert <[email-masked]>
Date: Tue, 21 Jan 2020 01:13:53 -0800

On 1/20/20 11:12 AM, Stefan Kangas wrote:
> What is the status of this, given that the emacs-27 is now cut?

Thanks for reminding me of this problem. The stuff in INSTALL is not quite right 
- at least, it didn't work for me in Ubuntu 18.04.3 (which is Debian based) due 
to some problem in my sources.list (which I hadn't messed with, so I guess 
Ubuntu must differ from Debian here). In contrast, INSTALL is overly complicated 
for Fedora 31 since it gives a bunch of confusing instructions for sources and 
debuginfo whereas all I needed to do was 'dnf debuginfo-install emacs' to get 
all that stuff done.

More generally, even if we fix these INSTALL problems, INSTALL won't work for 
other GNU/Linux distributions, or for non-GNU distributions for that matter. Nor 
will it work when people install Emacs themselves. And the INSTALL instructions 
  will continue to be complicated and awkward, and will likely need to be 
maintained as Debian and Red Hat evolve.

So we still need something better. I rebased and tweaked the proposed patch 
(including a revamp of the INSTALL section to try to address some of the 
abovementioned problems) and am attaching the updated version.
From 74cb99b9c826d81e8d2349b6e6b9c112af306e54 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 20 Jan 2020 23:37:24 -0800
Subject: [PATCH] Install C source code for C-h f etc.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Without this change, on typical GNU/Linux distributions
like Debian, the first button of ‘C-h f car RET’ does not work
because the source code for ‘car’ is not installed (Bug#37527).
Fix this by installing the (compressed) C source code alongside
the (compressed) Lisp source code that is already installed.
This adds about 3 MB (about 2%) to the size of the installed files
on my platform.
* Makefile.in (install_srcdir, enable_install_srcdir): New macros.
(epaths-force): Substitute PATH_SOURCE.
(install-srcdir): New rule, that installs a copy of the C source
code if enable_install_srcdir says to.
(install-arch-indep): Depend on it.
* configure.ac (install_srcdir): New var.
Add support for --disable-install-srcdir (to disable installation
of source) and for --enable-install-srcdir='.' (to have Emacs
refer to its source dir).
* lisp/emacs-lisp/find-func.el (find-function-C-source):
Also look for gzipped source files.
* src/emacs.c (init_cmdargs): Set source-directory to
be the same as installation-directory when
running with an uninstalled Emacs.
* src/epaths.in (PATH_SOURCE): New macro.
* src/lread.c: Include dosname.h, for IS_ABSOLUTE_FILE_NAME.
(syms_of_lread): When initializing source-directory, use
PATH_SOURCE as-is if it is absolute; otherwise, use it relative to
PATH_DUMPLOADSEARCH/.. as before.
---
 INSTALL                      | 65 ++++++++++++++++++------------------
 Makefile.in                  | 32 ++++++++++++++++--
 configure.ac                 | 19 +++++++++++
 etc/NEWS                     |  6 ++++
 lisp/emacs-lisp/find-func.el |  5 ++-
 src/emacs.c                  |  2 ++
 src/epaths.in                |  3 ++
 src/lread.c                  | 11 +++---
 8 files changed, 104 insertions(+), 39 deletions(-)

diff --git a/INSTALL b/INSTALL
index 2d257f9ce6..cb12e4a17a 100644
--- a/INSTALL
+++ b/INSTALL
@@ -214,41 +214,42 @@ like 'apt-get build-dep emacs' (on older systems, replace 'emacs' with
 eg 'emacs25').  On Red Hat-based systems, the corresponding command is
 'dnf builddep emacs' (on older systems, use 'yum-builddep' instead).
 
+
+DEBUGGING AN INSTALLED EMACS
+
+* Installed Emacs source code
+
+Emacs installs a compressed copy of much of its source code, to make
+it easy for users to read the source code of Emacs via commands like
+M-x describe-function (C-h f) to display the definition of a function.
+This compressed copy ordinarily includes both the Elisp source code
+that Emacs is mostly written in, as well as the C source code for the
+core Emacs executable.
+
 * GNU/Linux source and debug packages
 
 Many GNU/Linux systems provide separate packages containing the
-sources and debug symbols of Emacs.  They are useful if you want to
-check the source code of Emacs primitive functions or debug Emacs on
-the C level.
-
-The names of the packages that you need vary according to the
-GNU/Linux distribution that you use.  On Debian-based systems, you can
-install a source package of Emacs with a command like 'apt-get source
-emacs' (on older systems, replace 'emacs' with eg 'emacs25').  The
-target directory for unpacking the source tree is the current
-directory.  On Red Hat-based systems, the corresponding command is
-'dnf install emacs-debugsource', with target directory /usr/src/debug
-(this requires to add the *-debuginfo repositories first, via 'dnf
-config-manager --set-enabled fedora-debuginfo updates-debuginfo').
-
-Once you have installed the source package, for example at
-/path/to/emacs-26.1, add the following line to your startup file:
-
-     (setq find-function-C-source-directory
-           "/path/to/emacs-26.1/src")
-
-The installation directory of the Emacs source package will contain
-the exact package name and version number Emacs is installed on your
-system.  If a new Emacs package is installed, the source package must
-be reinstalled as well, and the setting in your startup file must be
-updated.
-
-Emacs debugging symbols are distributed by a debug package.  It does
-not exist for every released Emacs package, this depends on the
-distribution.  On Debian-based systems, you can install a debug
-package of Emacs with a command like 'apt-get install emacs-dbg' (on
-older systems, replace 'emacs' with eg 'emacs25').  On Red Hat-based
-systems, the corresponding command is 'dnf debuginfo-install emacs'.
+sources and debug symbols of Emacs.  They can help you debug the
+installed Emacs on the C level.  The procedures for installing these
+packages depend on the GNU/Linux system that you use.
+
+Emacs debugging symbols are distributed by a debug package if one
+exists for your system.  On Debian-based systems, you can
+install a debug package of Emacs with a command like 'apt-get install
+emacs-dbg' (on older systems, replace 'emacs' with e.g. 'emacs25').
+On Red Hat-based systems, the corresponding command is 'dnf
+debuginfo-install emacs'; this may require adding the *-debuginfo
+repositories first, via 'dnf config-manager --set-enabled
+fedora-debuginfo updates-debuginfo'.
+
+Some systems also have an Emacs source package that is also helpful
+when debugging the installed Emacs.  To unpack an Emacs source package
+into the current directory on Debian-based systems, you can use a
+command like 'apt-get source emacs' (on older systems, replace 'emacs'
+with e.g. 'emacs25'); you may first need to add the appropriate
+'source' URIs to your sources.list.  On Red Hat-based systems,
+installing the debugging symbols automatically installs the
+corresponding source package in the appropriate location.

 DETAILED BUILDING AND INSTALLATION:
diff --git a/Makefile.in b/Makefile.in
index 2c82c49fba..cadc5dac97 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -266,6 +266,10 @@ etcdir=
 # once.
 archlibdir=@archlibdir@
 
+# Where to put installed source code, and whether to install it at all.
+install_srcdir=@install_srcdir@
+enable_install_srcdir=@enable_install_srcdir@
+
 # Where to put the etc/DOC file.
 etcdocdir=@etcdocdir@
 
@@ -374,6 +378,7 @@ epaths-force:
 	  -e 's;\(#.*PATH_BITMAPS\).*$$;\1 "${bitmapdir}";'		\
 	  -e 's;\(#.*PATH_X_DEFAULTS\).*$$;\1 "${x_default_search_path}";' \
 	  -e 's;\(#.*PATH_GAME\).*$$;\1 $(PATH_GAME);'			\
+	  -e 's;\(#.*PATH_SOURCE\).*$$;\1 "${install_srcdir}";'	\
 	  -e 's;\(#.*PATH_DOC\).*$$;\1 "${etcdocdir}";') &&		\
 	${srcdir}/build-aux/move-if-change epaths.h.$$$$ src/epaths.h
 
@@ -461,7 +466,7 @@ $(srcdir)/configure:
 # ==================== Installation ====================
 
 .PHONY: install install-arch-dep install-arch-indep install-etcdoc install-info
-.PHONY: install-man install-etc install-strip install-$(NTDIR)
+.PHONY: install-man install-srcdir install-etc install-strip install-$(NTDIR)
 .PHONY: uninstall uninstall-$(NTDIR)
 
 ## If we let lib-src do its own installation, that means we
@@ -568,7 +573,8 @@ set_installuser=
 ## work correctly, and therefore no idea when tar can be replaced.
 ## See also these comments from 2004 about cp -r working fine:
 ## https://lists.gnu.org/r/autoconf-patches/2004-11/msg00005.html
-install-arch-indep: lisp install-info install-man ${INSTALL_ARCH_INDEP_EXTRA}
+install-arch-indep: lisp install-info install-man install-srcdir \
+  $(INSTALL_ARCH_INDEP_EXTRA)
 	umask 022 && $(MKDIR_P) "$(DESTDIR)$(includedir)"
 	$(INSTALL_DATA) src/emacs-module.h "$(DESTDIR)$(includedir)/emacs-module.h"
 	-set ${COPYDESTS} ; \
@@ -700,6 +706,28 @@ install-man:
 	  ${GZIP_PROG} -9n "$(DESTDIR)${man1dir}/$${dest}" || true; \
 	done
 
+install-srcdir:
+ifneq ($(enable_install_srcdir),no)
+	-unset CDPATH; \
+	umask 022; $(MKDIR_P) "$(DESTDIR)$(install_srcdir)/src" && \
+	exp_sourcesrcdir=`cd "$(DESTDIR)$(install_srcdir)/src" && /bin/pwd` && \
+	[ "`cd $(srcdir)/src && /bin/pwd`" = "$$exp_sourcesrcdir" ] || { \
+	  $(set_installuser); \
+	  printf 'Copying compressed C sources to %s ...\n' \
+		 "$(DESTDIR)$(install_srcdir)/src"; \
+	  for file in `cd $(srcdir) && echo src/*.[cm]`; do \
+	    installed_file="$(DESTDIR)$(install_srcdir)/$$file" && \
+	    $(INSTALL_DATA) "$$file" "$$installed_file" && \
+	    [ -z "$(GZIP_PROG)" ] || { \
+	      rm -f "$$installed_file.gz" && \
+	      $(GZIP_PROG) -9n "$$installed_file" && \
+	      installed_file=$$installed_file.gz; \
+	    } || exit; \
+	    chown $$installuser "$$installed_file" || true; \
+	  done; \
+	}
+endif
+
 ## Install those items from etc/ that need to end up elsewhere.
 
 ## If you prefer, choose "emacs22" at installation time.
diff --git a/configure.ac b/configure.ac
index d7b4d0352c..b4de343371 100644
--- a/configure.ac
+++ b/configure.ac
@@ -194,6 +194,7 @@
 lisppath='${locallisppath}:${standardlisppath}'
 etcdir='${datadir}/emacs/${version}/etc'
 archlibdir='${libexecdir}/emacs/${version}/${configuration}'
+install_srcdir='${datadir}/emacs/${version}'
 etcdocdir='${datadir}/emacs/${version}/etc'
 gamedir='${localstatedir}/games/emacs'
 
@@ -540,6 +541,21 @@ AC_DEFUN
   locallisppath=${enableval} locallisppathset=yes
 fi)
 
+AC_ARG_ENABLE([install-srcdir],
+  [AS_HELP_STRING([--disable-install-srcdir],
+     [do not install low-level Emacs source code useful for debugging.
+      Use --enable-install-srcdir='.' to have Emacs refer to the
+      source directory it was configured from.])],
+  [],
+  [enable_install_srcdir=yes])
+case $enable_install_srcdir in
+  yes | no) ;;
+  .) install_srcdir=`cd "$srcdir" && /bin/pwd` ||
+       AC_MSG_ERROR([cannot get srcdir name])
+     enable_install_srcdir=no;;
+  *) AC_MSG_ERROR([invalid install-srcdir]);;
+esac
+
 AC_ARG_ENABLE(checking,
 [AS_HELP_STRING([--enable-checking@<:@=LIST@:>@],
 		[enable expensive checks.  With LIST,
@@ -2048,6 +2064,7 @@ AC_DEFUN
      dnl This one isn't really used, only archlibdir is.
      libexecdir="\${ns_appbindir}/libexec"
      archlibdir="\${ns_appbindir}/libexec"
+     install_srcdir="\${ns_appresdir}"
      etcdocdir="\${ns_appresdir}/etc"
      etcdir="\${ns_appresdir}/etc"
      dnl FIXME maybe set datarootdir instead.
@@ -5230,6 +5247,8 @@ AC_DEFUN
 AC_SUBST(x_default_search_path)
 AC_SUBST(etcdir)
 AC_SUBST(archlibdir)
+AC_SUBST([enable_install_srcdir])
+AC_SUBST([install_srcdir])
 AC_SUBST(etcdocdir)
 AC_SUBST(bitmapdir)
 AC_SUBST(gamedir)
diff --git a/etc/NEWS b/etc/NEWS
index 7f1f50759e..dde72dea53 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -42,6 +42,12 @@ and 'ftcr' otherwise.  You can determine this by checking
 ** The ftx font backend driver has been removed.
 It was declared obsolete in Emacs 27.1.
 
+---
+** Emacs now installs a copy of its C source code, used for debugging help.
+For example, pressing the first button in the *Help* buffer generated
+by 'C-h f car RET' now takes you to a copy of the C-language
+implementation of the function 'car'.
+
 
 * Startup Changes in Emacs 28.1
 
diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el
index 167ead3ce0..631ecac73f 100644
--- a/lisp/emacs-lisp/find-func.el
+++ b/lisp/emacs-lisp/find-func.el
@@ -245,7 +245,10 @@ find-function-C-source
   (let ((dir (or find-function-C-source-directory
                  (read-directory-name "Emacs C source dir: " nil nil t))))
     (setq file (expand-file-name file dir))
-    (if (file-readable-p file)
+    (if (or (file-readable-p file)
+	    (let ((file-gz (concat file ".gz")))
+	      (and (file-readable-p file-gz)
+		   (setq file file-gz))))
         (if (null find-function-C-source-directory)
             (setq find-function-C-source-directory dir))
       (error "The C source file %s is not available"
diff --git a/src/emacs.c b/src/emacs.c
index c5a760d29f..d847e888b9 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -522,6 +522,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
 	      if (!NILP (etc_exists))
 		{
                   Vinstallation_directory = Ffile_name_as_directory (dir);
+		  Vsource_directory = Vinstallation_directory;
 		  break;
 		}
 	    }
@@ -547,6 +548,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
 		{
 		  tem = Fexpand_file_name (build_string (".."), dir);
                   Vinstallation_directory = Ffile_name_as_directory (tem);
+		  Vsource_directory = Vinstallation_directory;
 		  break;
 		}
 	    }
diff --git a/src/epaths.in b/src/epaths.in
index 3cadd160ec..b1d20508d5 100644
--- a/src/epaths.in
+++ b/src/epaths.in
@@ -73,5 +73,8 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 /* Where Emacs should store game score files.  */
 #define PATH_GAME "/usr/local/var/games/emacs"
 
+/* Where Emacs should look for installed sources.  */
+#define PATH_SOURCE "/usr/local/share/emacs"
+
 /* Where Emacs should look for the application default file. */
 #define PATH_X_DEFAULTS "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S"
diff --git a/src/lread.c b/src/lread.c
index 69dd73912b..05afef7ada 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -44,6 +44,7 @@ #define DEFINE_SYMBOLS
 #include "blockinput.h"
 #include "pdumper.h"
 #include <c-ctype.h>
+#include <dosname.h>
 #include <vla.h>
 
 #ifdef MSDOS
@@ -4991,11 +4992,13 @@ syms_of_lread (void)
   load_convert_to_unibyte = 0;
 
   DEFVAR_LISP ("source-directory", Vsource_directory,
-	       doc: /* Directory in which Emacs sources were found when Emacs was built.
-You cannot count on them to still be there!  */);
+	       doc: /* Directory where Emacs sources are looked for.  */);
   Vsource_directory
-    = Fexpand_file_name (build_string ("../"),
-			 Fcar (decode_env_path (0, PATH_DUMPLOADSEARCH, 0)));
+    = (IS_ABSOLUTE_FILE_NAME (PATH_SOURCE)
+       ? build_string (PATH_SOURCE)
+       : Fexpand_file_name (build_string ("../" PATH_SOURCE),
+			    Fcar (decode_env_path (0, PATH_DUMPLOADSEARCH,
+						   false))));
 
   DEFVAR_LISP ("preloaded-file-list", Vpreloaded_file_list,
 	       doc: /* List of files that were preloaded (when dumping Emacs).  */);
-- 
2.17.1