Subject: bug#65340: further build failure on Android (Termux)

From: Bruno Haible <[email-masked]>
Date: Wed, 16 Aug 2023 12:34:02 +0200

After getting past bug#65319 and bug#65339,
the build of Emacs in the Termux app on Android 11 fails:

$ make
...
Dumping under the name emacs.pdmp
Dumping fingerprint: 231a76223bb9dd03b59400f731ac83c210b62f43015b9f12d53894ae244c6b77
Dump complete
Byte counts: header=100 hot=3947676 discardable=70896 cold=3671984
Reloc counts: hot=441711 discardable=4726
Adding name emacs-30.0.50.1

Error: permission-denied ("Adding new name" "Permission denied" "/data/data/com.termux/files/home/emacs/src/emacs" "/data/data/com.termux/files/home/emacs/src/emacs-30.0.50.1")
  mapbacktrace(#[1028 "\1\4\203\24\0\301\302!\210\300\4!\210\301\303!\210\202\35\0\301\304!\210\3\3B\262\1\211\2035\0\300\1@!\210\211A\211\262\2\2035\0\301\305!\210\202!\0\301\306!\207" [prin1 princ "  " "(" "  (" " " ")\n"] 7 "\n\n(fn EVALD FUNC ARGS FLAGS)"])
  debug-early-backtrace()
  debug-early(error (permission-denied "Adding new name" "Permission denied" "/data/data/com.termux/files/home/emacs/src/emacs" "/data/data/com.termux/files/home/emacs/src/emacs-30.0.50.1"))
  add-name-to-file("/data/data/com.termux/files/home/emacs/src/emacs" "/data/data/com.termux/files/home/emacs/src/emacs-30.0.50.1" t)
  (let ((name (format "emacs-%s.%d" emacs-version emacs-build-number)) (exe (if (eq system-type 'windows-nt) ".exe" ""))) (while (string-match "[^-+_.a-zA-Z0-9]+" name) (setq name (concat (downcase (substring name 0 (match-beginning 0))) "-" (substring name (match-end 0))))) (message "Adding name %s" (concat name exe)) (add-name-to-file (expand-file-name (concat "emacs" exe) invocation-directory) (expand-file-name (concat name exe) invocation-directory) t) (when (equal dump-mode "pdump") (message "Adding name %s" (concat name ".pdmp")) (add-name-to-file (expand-file-name "emacs.pdmp" invocation-directory) (expand-file-name (concat name ".pdmp") invocation-directory) t)))
  (if (not (or (eq system-type 'ms-dos) (eq system-type 'haiku) (featurep 'android) (member dump-mode '("pbootstrap" "bootstrap")))) (let ((name (format "emacs-%s.%d" emacs-version emacs-build-number)) (exe (if (eq system-type 'windows-nt) ".exe" ""))) (while (string-match "[^-+_.a-zA-Z0-9]+" name) (setq name (concat (downcase (substring name 0 (match-beginning 0))) "-" (substring name (match-end 0))))) (message "Adding name %s" (concat name exe)) (add-name-to-file (expand-file-name (concat "emacs" exe) invocation-directory) (expand-file-name (concat name exe) invocation-directory) t) (when (equal dump-mode "pdump") (message "Adding name %s" (concat name ".pdmp")) (add-name-to-file (expand-file-name "emacs.pdmp" invocation-directory) (expand-file-name (concat name ".pdmp") invocation-directory) t))))
  (let ((output (cond ((equal dump-mode "pdump") "emacs.pdmp") ((equal dump-mode "dump") "emacs") ((equal dump-mode "bootstrap") "emacs") ((equal dump-mode "pbootstrap") "bootstrap-emacs.pdmp") (t (error "Unrecognized dump mode %s" dump-mode))))) (when (and (featurep 'native-compile) (equal dump-mode "pdump")) (setq native-comp-enable-subr-trampolines t)) (message "Dumping under the name %s" output) (condition-case nil (delete-file output) (file-error nil)) (let (success) (unwind-protect (let ((tmp-dump-mode dump-mode) (dump-mode nil) (lexical-binding nil)) (if (member tmp-dump-mode '("pdump" "pbootstrap")) (dump-emacs-portable (expand-file-name output invocation-directory)) (dump-emacs output (if (eq system-type 'ms-dos) "temacs.exe" "temacs")) (message "%d pure bytes used" pure-bytes-used)) (setq success t)) (unless success (ignore-errors (delete-file output))))) (if (not (or (eq system-type 'ms-dos) (eq system-type 'haiku) (featurep 'android) (member dump-mode '("pbootstrap" "bootstrap")))) (let ((name (format "emacs-%s.%d" emacs-version emacs-build-number)) (exe (if (eq system-type 'windows-nt) ".exe" ""))) (while (string-match "[^-+_.a-zA-Z0-9]+" name) (setq name (concat (downcase (substring name 0 (match-beginning 0))) "-" (substring name (match-end 0))))) (message "Adding name %s" (concat name exe)) (add-name-to-file (expand-file-name (concat "emacs" exe) invocation-directory) (expand-file-name (concat name exe) invocation-directory) t) (when (equal dump-mode "pdump") (message "Adding name %s" (concat name ".pdmp")) (add-name-to-file (expand-file-name "emacs.pdmp" invocation-directory) (expand-file-name (concat name ".pdmp") invocation-directory) t)))) (kill-emacs))
  (if dump-mode (let ((output (cond ((equal dump-mode "pdump") "emacs.pdmp") ((equal dump-mode "dump") "emacs")Adding new name: Permission denied, /data/data/com.termux/files/home/emacs/src/emacs, /data/data/com.termux/files/home/emacs/src/emacs-30.0.50.1
 ((equal dump-mode "bootstrap") "emacs") ((equal dump-mode "pbootstrap") "bootstrap-emacs.pdmp") (t (error "Unrecognized dump mode %s" dump-mode))))) (when (and (featurep 'native-compile) (equal dump-mode "pdump")) (setq native-comp-enable-subr-trampolines t)) (message "Dumping under the name %s" output) (condition-case nil (delete-file output) (file-error nil)) (let (success) (unwind-protect (let ((tmp-dump-mode dump-mode) (dump-mode nil) (lexical-binding nil)) (if (member tmp-dump-mode '("pdump" "pbootstrap")) (dump-emacs-portable (expand-file-name output invocation-directory)) (dump-emacs output (if (eq system-type 'ms-dos) "temacs.exe" "temacs")) (message "%d pure bytes used" pure-bytes-used)) (setq success t)) (unless success (ignore-errors (delete-file output))))) (if (not (or (eq system-type 'ms-dos) (eq system-type 'haiku) (featurep 'android) (member dump-mode '("pbootstrap" "bootstrap")))) (let ((name (format "emacs-%s.%d" emacs-version emacs-build-number)) (exe (if (eq system-type 'windows-nt) ".exe" ""))) (while (string-match "[^-+_.a-zA-Z0-9]+" name) (setq name (concat (downcase (substring name 0 (match-beginning 0))) "-" (substring name (match-end 0))))) (message "Adding name %s" (concat name exe)) (add-name-to-file (expand-file-name (concat "emacs" exe) invocation-directory) (expand-file-name (concat name exe) invocation-directory) t) (when (equal dump-mode "pdump") (message "Adding name %s" (concat name ".pdmp")) (add-name-to-file (expand-file-name "emacs.pdmp" invocation-directory) (expand-file-name (concat name ".pdmp") invocation-directory) t)))) (kill-emacs)))
  (if (eq system-type 'android) (progn (when (not noninteractive) (let ((temp-dir (getenv "TEMP")) (dump-file-name (format "%semacs-%s.pdmp" (file-name-as-directory "~") pdumper-fingerprint)) (dump-temp-file-name (format "%s~emacs-%s.pdmp" (file-name-as-directory "~") pdumper-fingerprint))) (unless (pdumper-stats) (condition-case nil (progn (dump-emacs-portable dump-temp-file-name) (rename-file dump-temp-file-name dump-file-name) nil) (error nil)))))) (if dump-mode (let ((output (cond ((equal dump-mode "pdump") "emacs.pdmp") ((equal dump-mode "dump") "emacs") ((equal dump-mode "bootstrap") "emacs") ((equal dump-mode "pbootstrap") "bootstrap-emacs.pdmp") (t (error "Unrecognized dump mode %s" dump-mode))))) (when (and (featurep 'native-compile) (equal dump-mode "pdump")) (setq native-comp-enable-subr-trampolines t)) (message "Dumping under the name %s" output) (condition-case nil (delete-file output) (file-error nil)) (let (success) (unwind-protect (let ((tmp-dump-mode dump-mode) (dump-mode nil) (lexical-binding nil)) (if (member tmp-dump-mode '("pdump" "pbootstrap")) (dump-emacs-portable (expand-file-name output invocation-directory)) (dump-emacs output (if (eq system-type 'ms-dos) "temacs.exe" "temacs")) (message "%d pure bytes used" pure-bytes-used)) (setq success t)) (unless success (ignore-errors (delete-file output))))) (if (not (or (eq system-type 'ms-dos) (eq system-type 'haiku) (featurep 'android) (member dump-mode '("pbootstrap" "bootstrap")))) (let ((name (format "emacs-%s.%d" emacs-version emacs-build-number)) (exe (if (eq system-type 'windows-nt) ".exe" ""))) (while (string-match "[^-+_.a-zA-Z0-9]+" name) (setq name (concat (downcase (substring name 0 (match-beginning 0))) "-" (substring name (match-end 0))))) (message "Adding name %s" (concat name exe)) (add-name-to-file (expand-file-name (concat "emacs" exe) invocation-directory) (expand-file-name (concat name exe) invocation-directory) t) (when (equal dump-mode "pdump") (message "Adding name %s" (concat name ".pdmp")) (add-name-to-file (expand-file-name "emacs.pdmp" invocation-directory) (expand-file-name (concat name ".pdmp") invocation-directory) t)))) (kill-emacs))))
  load("loadup.el")
make[2]: *** [Makefile:682: emacs.pdmp] Error 255
make[2]: Leaving directory '/data/data/com.termux/files/home/emacs/src'
make[1]: *** [Makefile:554: src] Error 2
make[1]: Leaving directory '/data/data/com.termux/files/home/emacs'
make[1]: Entering directory '/data/data/com.termux/files/home/emacs'
***
*** "make all" failed with exit status 2.

The problem is that the function add-name-to-file attempts to create a
hard link. However, this is not allowed, not even at the shell level:

$ ln ~/hello.c ~/hello1.c
ln: failed to create hard link '/data/data/com.termux/files/home/hello1.c' => '/data/data/com.termux/files/home/hello.c': Permission denied

The Termux people use a symbolic link instead of a hard link:
https://github.com/termux/termux-packages/blob/master/packages/emacs/src-fileio.c.patch

Bruno