emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Ihor Radchenko <yantar92@posteo.net>
To: Max Nikulin <manikulin@gmail.com>
Cc: emacs-orgmode@gnu.org
Subject: [PATCH v3] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el))
Date: Mon, 03 Apr 2023 08:46:05 +0000	[thread overview]
Message-ID: <87jzytbbg2.fsf@localhost> (raw)
In-Reply-To: <87wn2ujk27.fsf@localhost>

[-- Attachment #1: Type: text/plain, Size: 692 bytes --]

Ihor Radchenko <yantar92@posteo.net> writes:

>> It would be easier to review if this patch was split into 2 parts:
>> - add compat.el dependency (unused)
>> - replace functions to ones from compat.el
>
> Sure, but after spending half an hour trying to decouple this part, I
> gave up and decided to leave it as is. And there is nothing fancy in
> adding compat dependency in 2/3 patch anyway. Just one (require 'compat
> nil t), two macro definitions adviced by compat manual (copy-paste from
> compat code), and adding compat to EPACKAGES in makefiles.

After more fiddling with interactive rebase, I managed to split the
patch further.

See the attached.
Hope it is easier to review now.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Upgrade-Org-build-system-to-handle-third-party-depen.patch --]
[-- Type: text/x-patch, Size: 6381 bytes --]

From 313f2b6acdf67f29f4f5f671e8278bb3e566cabf Mon Sep 17 00:00:00 2001
Message-Id: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sat, 1 Apr 2023 12:00:48 +0200
Subject: [PATCH 1/7] Upgrade Org build system to handle third-party
 dependencies

* mk/default.mk (pkgdir): New variable holding the location of
third-party packages to be downloaded if necessary during compilation.
(EFLAGS): New variable holding extra flags to be passed to Emacs
executable when running make.
(EPACKAGES): List of packages to be installed (unless already present
in the `load-path') during compilation.
(package-install):
(INSTALL_PACKAGES): New command to download and install missing packages.
(BATCH): Update, setting default package location to pkgdir.
* mk/targets.mk (uppkg): New target to download install missing
packages.
(check test):
(compile compile-dirty): Use the new uppkg target.
(cleanpkg): New target cleaning up the downloaded packages.
(cleanall): Use the new target.
(.PHONY):
(CONF_BASE):
(CONF_DEST):
(CONF_CALL): Update according to the new variables and targets.
* .gitignore: Ignore the downloaded packages.

This commit paves the way towards third-party built-time dependencies
for Org.  In particular, towards including compat.el dependency.

According to EPACKAGES, we can auto-download necessary packages,
unless they are manually specified via -L switches in EFLAGS.

Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost
---
 .gitignore    |  1 +
 mk/default.mk | 24 +++++++++++++++++++++++-
 mk/targets.mk | 24 ++++++++++++++++--------
 3 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4bb81c359..0d9c5b297 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@ local*.mk
 .gitattributes
 mk/x11idle
 ChangeLog
+pkg-deps/
 
 # Files generated during `make packages/org` in a clone of `elpa.git`.
 
diff --git a/mk/default.mk b/mk/default.mk
index fa46661e8..997b22b66 100644
--- a/mk/default.mk
+++ b/mk/default.mk
@@ -31,6 +31,15 @@ GIT_BRANCH =
 TMPDIR ?= /tmp
 testdir = $(TMPDIR)/tmp-orgtest
 
+# Where to store Org dependencies
+pkgdir = $(shell pwd)/pkg-deps
+
+# Extra flags to be passed to Emacs
+EFLAGS ?=
+
+# Third-party packages to install when running make
+EPACKAGES ?=
+
 # Configuration for testing
 # Verbose ERT summary by default for Emacs-28 and above.
 # To override:
@@ -72,12 +81,22 @@ REPRO_ARGS ?=
 req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))'
 lst-ob-lang = ($(ob-lang) . t)
 req-extra   = --eval '(require '"'"'$(req))'
+package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))'
 BTEST_RE   ?= \\(org\\|ob\\|ox\\)
 BTEST_LOAD  = \
 	--eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \
 	--eval '(add-to-list '"'"'load-path (concat default-directory "testing"))'
 BTEST_INIT  = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST)
 
+ifeq (,$(EPACKAGES))
+INSTALL_PACKAGES =
+else
+INSTALL_PACKAGES = \
+	$(BATCH) \
+        --eval '(package-refresh-contents)' \
+        $(foreach package,$(EPACKAGES),$(package-install))
+endif
+
 BTEST = $(BATCH) $(BTEST_INIT) \
 	  -l org-batch-test-init \
 	  --eval '(setq \
@@ -120,7 +139,10 @@ EMACSQ  = $(EMACS)  -Q
 
 # Using emacs in batch mode.
 BATCH	= $(EMACSQ) -batch \
-	  --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)'
+	  $(EFLAGS) \
+	  --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \
+          --eval '(make-directory "$(pkgdir)" t)' \
+	  --eval '(setq package-user-dir "$(pkgdir)")' --eval '(package-initialize)'
 
 # Emacs must be started in toplevel directory
 BATCHO	= $(BATCH) \
diff --git a/mk/targets.mk b/mk/targets.mk
index 0bd293d68..ab8b830bb 100644
--- a/mk/targets.mk
+++ b/mk/targets.mk
@@ -27,21 +27,21 @@ ifneq ($(GITSTATUS),)
   GITVERSION := $(GITVERSION:.dirty=).dirty
 endif
 
-.PHONY:	all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \
+.PHONY:	all oldorg update update2 up0 up1 up2 uppkg single $(SUBDIRS) \
 	check test install $(INSTSUB) \
 	info html pdf card refcard doc docs \
 	autoloads cleanall clean $(CLEANDIRS:%=clean%) \
 	clean-install cleanelc cleandirs \
-	cleanlisp cleandoc cleandocs cleantest \
+	cleanlisp cleandoc cleandocs cleantest cleanpkg \
 	compile compile-dirty uncompiled \
 	config config-test config-exe config-all config-eol config-version \
 	vanilla repro
 
-CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC
-CONF_DEST = lispdir infodir datadir testdir
+CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC EPACKAGES
+CONF_DEST = lispdir infodir datadir testdir pkgdir
 CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE
 CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO
-CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION
+CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH INSTALL_PACKAGES BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION
 config-eol:: EOL = \#
 config-eol:: config-all
 config config-all::
@@ -86,7 +86,7 @@ local.mk:
 
 all compile::
 	$(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;)
-compile compile-dirty::
+compile compile-dirty:: uppkg
 	$(MAKE) -C lisp $@
 all clean-install::
 	$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;)
@@ -94,7 +94,7 @@ all clean-install::
 vanilla:
 	-@$(NOBATCH) &
 
-check test::	compile
+check test::	uppkg compile
 check test test-dirty::
 	-$(MKDIR) $(testdir)
 	TMPDIR=$(testdir) $(BTEST)
@@ -102,6 +102,11 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f
 	$(MAKE) cleantest
 endif
 
+uppkg::
+	-$(MKDIR) -p $(pkgdir)
+	-$(FIND) $(pkgdir) \(  -name \*.elc \) -exec $(RM) {} +
+	$(INSTALL_PACKAGES)
+
 up0 up1 up2::
 	git checkout $(GIT_BRANCH)
 	git remote update
@@ -134,7 +139,7 @@ cleandirs:
 
 clean:	cleanlisp cleandoc
 
-cleanall: cleandirs cleantest
+cleanall: cleandirs cleantest cleanpkg
 	-$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} +
 	-$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} +
 
@@ -159,3 +164,6 @@ cleantest:
 	  $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \
 	  $(RMR) $(testdir) ; \
 	}
+
+cleanpkg:
+	-$(RMR) $(pkgdir)
-- 
2.40.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-org-compat-Enable-compat.el.patch --]
[-- Type: text/x-patch, Size: 3395 bytes --]

From 68fb497e93d717df60d26c1e1fb5547e9f972cac Mon Sep 17 00:00:00 2001
Message-Id: <68fb497e93d717df60d26c1e1fb5547e9f972cac.1680511418.git.yantar92@posteo.net>
In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Mon, 3 Apr 2023 10:40:00 +0200
Subject: [PATCH 2/7] org-compat: Enable compat.el

* lisp/org-compat.el (compat): Load Compat library, when available.
(org-compat-function):
(org-compat-call): Add compatibility macros available even when Compat
is not available (Org is a part of Emacs).
* lisp/org.el: Add Compat to package-requires.
---
 lisp/org-compat.el | 42 ++++++++++++++++++++++++++++++++++++++++++
 lisp/org.el        |  2 +-
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index c47a4e8c2..e5b22d623 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -94,6 +94,48 @@ (defvar org-table-tab-recognizes-table.el)
 (defvar org-table1-hline-regexp)
 (defvar org-fold-core-style)
 
+\f
+;;; compat.el
+
+;; Do not throw an error when not available - assume latest Emacs
+;; version (built-in Org).
+(require 'compat nil 'noerror)
+
+;; Provide compatibility macros when we are a part of Emacs.
+;; See https://elpa.gnu.org/packages/doc/compat.html#Usage
+
+(defmacro org-compat-function (fun)
+  "Return compatibility function symbol for FUN.
+
+If the Emacs version provides a sufficiently recent version of
+FUN, the symbol FUN is returned itself.  Otherwise the macro
+returns the symbol of a compatibility function which supports the
+behavior and calling convention of the current stable Emacs
+version.  For example Compat 29.1 will provide compatibility
+functions which implement the behavior and calling convention of
+Emacs 29.1.
+
+See also `org-compat-call' to directly call compatibility functions."
+  (let ((compat (intern (format "compat--%s" fun))))
+    `#',(if (fboundp compat) compat fun)))
+
+(defmacro org-compat-call (fun &rest args)
+  "Call compatibility function or macro FUN with ARGS.
+
+A good example function is `plist-get' which was extended with an
+additional predicate argument in Emacs 29.1.  The compatibility
+function, which supports this additional argument, can be
+obtained via (compat-function plist-get) and called
+via (compat-call plist-get plist prop predicate).  It is not
+possible to directly call (plist-get plist prop predicate) on
+Emacs older than 29.1, since the original `plist-get' function
+does not yet support the predicate argument.  Note that the
+Compat library never overrides existing functions.
+
+See also `org-compat-function' to lookup compatibility functions."
+  (let ((compat (intern (format "compat--%s" fun))))
+    `(,(if (fboundp compat) compat fun) ,@args)))
+
 \f
 ;;; Emacs < 29 compatibility
 
diff --git a/lisp/org.el b/lisp/org.el
index 10ade32dd..5e52608ca 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding:
 ;; Maintainer: Bastien Guerry <bzg@gnu.org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; URL: https://orgmode.org
-;; Package-Requires: ((emacs "26.1"))
+;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1"))
 
 ;; Version: 9.7-pre
 
-- 
2.40.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Use-compat.el-library-instead-of-ad-hoc-compatibilit.patch --]
[-- Type: text/x-patch, Size: 33408 bytes --]

From 88888d4bc18da596a68698082789bc9ba3eb9ff3 Mon Sep 17 00:00:00 2001
Message-Id: <88888d4bc18da596a68698082789bc9ba3eb9ff3.1680511419.git.yantar92@posteo.net>
In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Mon, 3 Apr 2023 10:41:50 +0200
Subject: [PATCH 3/7] Use compat.el library instead of ad-hoc compatibility
 function set

* mk/default.mk (EPACKAGES): Demand compat library during compile time.
* lisp/org.el (org-fill-paragraph):
* lisp/org-compat.el: Obsolete org-* compatibility functions that are
already available in compat.el: `org-file-has-changed-p',
`org-string-equal-ignore-case', `org-file-name-concat',
`org-directory-empty-p', `org-string-clean-whitespace',
`org-format-prompt', `org-xor', `org-string-distance',
`org-buffer-hash'.
* lisp/ob-core.el (org-babel-results-keyword): Use functions provided
by compat.el.
(org-babel-insert-result):
* lisp/oc-basic.el (org-cite-basic--parse-bibliography):
* lisp/oc.el (org-cite-adjust-note):
* lisp/ol-gnus.el (org-gnus-group-link):
(org-gnus-article-link):
(org-gnus-store-link):
* lisp/ol.el:
(org-store-link):
* lisp/org-attach.el:
* lisp/org-capture.el:
(org-capture-fill-template):
* lisp/org-fold-core.el (org-fold-core-next-visibility-change):
* lisp/org-lint.el:
* lisp/org-persist.el (org-persist-directory):
(org-persist-read:file):
(org-persist-read:url):
(org-persist--load-index):
(org-persist-write:file):
(org-persist-write:index):
(org-persist--merge-index-with-disk):
(org-persist-read):
(org-persist-write):
(org-persist-write-all):
(org-persist--gc-persist-file):
(org-persist-gc):
* lisp/org-refile.el (org-refile-get-location):
* lisp/ox.el (org-export-resolve-radio-link):
* testing/lisp/test-ol.el (test-org-link/toggle-link-display):
* testing/lisp/test-org-capture.el (test-org-capture/abort):

Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost
---
 lisp/ob-core.el                  |  10 +-
 lisp/oc-basic.el                 |   6 +-
 lisp/oc.el                       |   2 +-
 lisp/ol-gnus.el                  |   8 +-
 lisp/ol.el                       |   4 +-
 lisp/org-attach.el               |   2 +-
 lisp/org-capture.el              |   8 +-
 lisp/org-compat.el               | 180 ++++---------------------------
 lisp/org-fold-core.el            |   2 +-
 lisp/org-lint.el                 |   2 +-
 lisp/org-persist.el              |  38 +++----
 lisp/org-refile.el               |   2 +-
 lisp/org.el                      |   4 +-
 lisp/ox.el                       |   6 +-
 mk/default.mk                    |   2 +-
 testing/lisp/test-ol.el          |  10 +-
 testing/lisp/test-org-capture.el |   2 +-
 17 files changed, 75 insertions(+), 213 deletions(-)

diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index 471887a3a..4ef1f2084 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -145,7 +145,7 @@ (defcustom org-babel-results-keyword "RESULTS"
   :type 'string
   :safe (lambda (v)
 	  (and (stringp v)
-	       (org-string-equal-ignore-case "RESULTS" v))))
+	       (string-equal-ignore-case "RESULTS" v))))
 
 (defcustom org-babel-noweb-wrap-start "<<"
   "String used to begin a noweb reference in a code block.
@@ -927,7 +927,7 @@ (defun org-babel-check-src-block ()
 				   (match-string 4))))))
       (dolist (name names)
 	(when (and (not (string= header name))
-		   (<= (org-string-distance header name) too-close)
+		   (<= (string-distance header name) too-close)
 		   (not (member header names)))
 	  (error "Supplied header \"%S\" is suspiciously close to \"%S\""
 		 header name))))
@@ -2518,7 +2518,7 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex
 		       ;; Escape contents from "export" wrap.  Wrap
 		       ;; inline results within an export snippet with
 		       ;; appropriate value.
-		       ((org-string-equal-ignore-case type "export")
+		       ((string-equal-ignore-case type "export")
 			(let ((backend (pcase split
 					 (`(,_) "none")
 					 (`(,_ ,b . ,_) b))))
@@ -2529,14 +2529,14 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex
 					   backend) "@@)}}}")))
 		       ;; Escape contents from "example" wrap.  Mark
 		       ;; inline results as verbatim.
-		       ((org-string-equal-ignore-case type "example")
+		       ((string-equal-ignore-case type "example")
 			(funcall wrap
 				 opening-line closing-line
 				 nil nil
 				 "{{{results(=" "=)}}}"))
 		       ;; Escape contents from "src" wrap.  Mark
 		       ;; inline results as inline source code.
-		       ((org-string-equal-ignore-case type "src")
+		       ((string-equal-ignore-case type "src")
 			(let ((inline-open
 			       (pcase split
 				 (`(,_)
diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el
index 12b627e71..1c86f344a 100644
--- a/lisp/oc-basic.el
+++ b/lisp/oc-basic.el
@@ -274,11 +274,11 @@ (defun org-cite-basic--parse-bibliography (&optional info)
       (dolist (file (org-cite-list-bibliography-files))
         (when (file-readable-p file)
           (with-temp-buffer
-            (when (or (org-file-has-changed-p file)
+            (when (or (file-has-changed-p file)
                       (not (gethash file org-cite-basic--file-id-cache)))
               (insert-file-contents file)
               (set-visited-file-name file t)
-              (puthash file (org-buffer-hash) org-cite-basic--file-id-cache))
+              (puthash file (buffer-hash) org-cite-basic--file-id-cache))
             (condition-case nil
                 (unwind-protect
 	            (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache)))
@@ -488,7 +488,7 @@ (defun org-cite-basic--close-keys (key keys)
   "List cite keys close to KEY in terms of string distance."
   (seq-filter (lambda (k)
                 (>= org-cite-basic-max-key-distance
-                    (org-string-distance k key)))
+                   (string-distance k key)))
               keys))
 
 (defun org-cite-basic--set-keymap (beg end suggestions)
diff --git a/lisp/oc.el b/lisp/oc.el
index dde6f3a32..f39ae848b 100644
--- a/lisp/oc.el
+++ b/lisp/oc.el
@@ -1029,7 +1029,7 @@ (defun org-cite-adjust-note (citation info &optional rule punct)
                              (match-string 3 previous)))))
       ;; Bail you when there is no quote and either no punctuation, or
       ;; punctuation on both sides.
-      (when (or quote (org-xor punct final-punct))
+      (when (or quote (xor punct final-punct))
         ;; Phase 1: handle punctuation rule.
         (pcase rule
           ((guard (not quote)) nil)
diff --git a/lisp/ol-gnus.el b/lisp/ol-gnus.el
index 7c07ce045..e121cfba3 100644
--- a/lisp/ol-gnus.el
+++ b/lisp/ol-gnus.el
@@ -98,8 +98,8 @@ (defun org-gnus-group-link (group)
 `org-gnus-prefer-web-links' is reversed."
   (let ((unprefixed-group (replace-regexp-in-string "^[^:]+:" "" group)))
     (if (and (string-prefix-p "nntp" group) ;; Only for nntp groups
-	     (org-xor current-prefix-arg
-		      org-gnus-prefer-web-links))
+	     (xor current-prefix-arg
+		  org-gnus-prefer-web-links))
 	(concat "https://groups.google.com/group/" unprefixed-group)
       (concat "gnus:" group))))
 
@@ -116,7 +116,7 @@ (defun org-gnus-article-link (group newsgroups message-id x-no-archive)
 
 If `org-store-link' was called with a prefix arg the meaning of
 `org-gnus-prefer-web-links' is reversed."
-  (if (and (org-xor current-prefix-arg org-gnus-prefer-web-links)
+  (if (and (xor current-prefix-arg org-gnus-prefer-web-links)
 	   newsgroups		  ;make web links only for nntp groups
 	   (not x-no-archive))	  ;and if X-No-Archive isn't set
       (format "https://groups.google.com/groups/search?as_umsgid=%s"
@@ -169,7 +169,7 @@ (defun org-gnus-store-link ()
 	    newsgroups x-no-archive)
        ;; Fetching an article is an expensive operation; newsgroup and
        ;; x-no-archive are only needed for web links.
-       (when (org-xor current-prefix-arg org-gnus-prefer-web-links)
+       (when (xor current-prefix-arg org-gnus-prefer-web-links)
 	 ;; Make sure the original article buffer is up-to-date.
 	 (save-window-excursion (gnus-summary-select-article))
 	 (setq to (or to (gnus-fetch-original-field "To")))
diff --git a/lisp/ol.el b/lisp/ol.el
index 9e4781f6e..3d62a6fa0 100644
--- a/lisp/ol.el
+++ b/lisp/ol.el
@@ -1692,7 +1692,7 @@ (defun org-store-link (arg &optional interactive?)
 				(abbreviate-file-name
 				 (buffer-file-name (buffer-base-buffer)))))
 	   ;; Add a context search string.
-	   (when (org-xor org-link-context-for-files (equal arg '(4)))
+	   (when (xor org-link-context-for-files (equal arg '(4)))
 	     (let* ((element (org-element-at-point))
 		    (name (org-element-property :name element))
 		    (context
@@ -1724,7 +1724,7 @@ (defun org-store-link (arg &optional interactive?)
 			     (abbreviate-file-name
 			      (buffer-file-name (buffer-base-buffer)))))
 	;; Add a context search string.
-	(when (org-xor org-link-context-for-files (equal arg '(4)))
+	(when (xor org-link-context-for-files (equal arg '(4)))
 	  (let ((context (org-link--normalize-string
 			  (or (org-link--context-from-region)
 			      (org-current-line-string))
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 8d01eda71..5cc40873c 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -674,7 +674,7 @@ (defun org-attach-sync ()
       (let ((files (org-attach-file-list attach-dir)))
 	(org-attach-tag (not files)))
       (when org-attach-sync-delete-empty-dir
-        (when (and (org-directory-empty-p attach-dir)
+        (when (and (directory-empty-p attach-dir)
                    (if (eq 'query org-attach-sync-delete-empty-dir)
                        (yes-or-no-p "Attachment directory is empty.  Delete?")
                      t))
diff --git a/lisp/org-capture.el b/lisp/org-capture.el
index b96e9f336..c5b1c6d50 100644
--- a/lisp/org-capture.el
+++ b/lisp/org-capture.el
@@ -1323,9 +1323,9 @@ (defun org-capture-place-item ()
 	      ;; prioritize the existing list.
 	      (when prepend?
 		(let ((ordered? (eq 'ordered (org-element-property :type item))))
-		  (when (org-xor ordered?
-				 (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)"
-						 template))
+		  (when (xor ordered?
+			     (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)"
+					     template))
 		    (org-cycle-list-bullet (if ordered? "1." "-")))))
 	      ;; Eventually repair the list for proper indentation and
 	      ;; bullets.
@@ -1867,7 +1867,7 @@ (defun org-capture-fill-template (&optional template initial annotation)
 		     (setq org-capture--prompt-history
 			   (gethash prompt org-capture--prompt-history-table))
                      (push (org-completing-read
-                            (org-format-prompt (or prompt "Enter string") default)
+                            (format-prompt (or prompt "Enter string") default)
 			    completions
 			    nil nil nil 'org-capture--prompt-history default)
 			   strings)
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index e5b22d623..046a3db97 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -79,9 +79,6 @@ (declare-function org-fold-region "org-fold" (from to flag &optional spec))
 (declare-function org-fold-show-all "org-fold" (&optional types))
 (declare-function org-fold-show-children "org-fold" (&optional level))
 (declare-function org-fold-show-entry "org-fold" (&optional hide-drawers))
-;; `org-string-equal-ignore-case' is in _this_ file but isn't at the
-;; top-level.
-(declare-function org-string-equal-ignore-case "org-compat" (string1 string2))
 
 (defvar calendar-mode-map)
 (defvar org-complex-heading-regexp)
@@ -136,105 +133,26 @@ (defmacro org-compat-call (fun &rest args)
   (let ((compat (intern (format "compat--%s" fun))))
     `(,(if (fboundp compat) compat fun) ,@args)))
 
-\f
-;;; Emacs < 29 compatibility
-
-(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal)
-  "Internal variable used by `org-file-has-changed-p'.")
-
-(if (fboundp 'file-has-changed-p)
-    (defalias 'org-file-has-changed-p #'file-has-changed-p)
-  (defun org-file-has-changed-p (file &optional tag)
-    "Return non-nil if FILE has changed.
-The size and modification time of FILE are compared to the size
-and modification time of the same FILE during a previous
-invocation of `org-file-has-changed-p'.  Thus, the first invocation
-of `org-file-has-changed-p' always returns non-nil when FILE exists.
-The optional argument TAG, which must be a symbol, can be used to
-limit the comparison to invocations with identical tags; it can be
-the symbol of the calling function, for example."
-    (let* ((file (directory-file-name (expand-file-name file)))
-           (remote-file-name-inhibit-cache t)
-           (fileattr (file-attributes file 'integer))
-	   (attr (and fileattr
-                      (cons (file-attribute-size fileattr)
-		            (file-attribute-modification-time fileattr))))
-	   (sym (concat (symbol-name tag) "@" file))
-	   (cachedattr (gethash sym org-file-has-changed-p--hash-table)))
-      (when (not (equal attr cachedattr))
-        (puthash sym attr org-file-has-changed-p--hash-table)))))
-
-(if (fboundp 'string-equal-ignore-case)
-    (defalias 'org-string-equal-ignore-case #'string-equal-ignore-case)
-  ;; From Emacs subr.el.
-  (defun org-string-equal-ignore-case (string1 string2)
-    "Like `string-equal', but case-insensitive.
-Upper-case and lower-case letters are treated as equal.
-Unibyte strings are converted to multibyte for comparison."
-    (eq t (compare-strings string1 0 nil string2 0 nil t))))
-
-\f
-;;; Emacs < 28.1 compatibility
-
-(if (fboundp 'file-name-concat)
-    (defalias 'org-file-name-concat #'file-name-concat)
-  (defun org-file-name-concat (directory &rest components)
-    "Append COMPONENTS to DIRECTORY and return the resulting string.
-
-Elements in COMPONENTS must be a string or nil.
-DIRECTORY or the non-final elements in COMPONENTS may or may not end
-with a slash -- if they don't end with a slash, a slash will be
-inserted before contatenating."
-    (save-match-data
-      (mapconcat
-       #'identity
-       (delq nil
-             (mapcar
-              (lambda (str)
-                (when (and str (not (seq-empty-p str))
-                           (string-match "\\(.+\\)/?" str))
-                  (match-string 1 str)))
-              (cons directory components)))
-       "/"))))
-
-(if (fboundp 'directory-empty-p)
-    (defalias 'org-directory-empty-p #'directory-empty-p)
-  (defun org-directory-empty-p (dir)
-    "Return t if DIR names an existing directory containing no other files."
-    (and (file-directory-p dir)
-         (null (directory-files dir nil directory-files-no-dot-files-regexp t)))))
-
-(if (fboundp 'string-clean-whitespace)
-    (defalias 'org-string-clean-whitespace #'string-clean-whitespace)
-  ;; From Emacs subr-x.el.
-  (defun org-string-clean-whitespace (string)
-    "Clean up whitespace in STRING.
-All sequences of whitespaces in STRING are collapsed into a
-single space character, and leading/trailing whitespace is
-removed."
-    (let ((blank "[[:blank:]\r\n]+"))
-      (string-trim (replace-regexp-in-string blank " " string t t)
-                   blank blank))))
-
-(if (fboundp 'format-prompt)
-    (defalias 'org-format-prompt #'format-prompt)
-  ;; From Emacs minibuffer.el, inlining
-  ;; `minibuffer-default-prompt-format' value and replacing `length<'
-  ;; (both new in Emacs 28.1).
-  (defun org-format-prompt (prompt default &rest format-args)
-    "Compatibility substitute for `format-prompt'."
-    (concat
-     (if (null format-args)
-         prompt
-       (apply #'format prompt format-args))
-     (and default
-          (or (not (stringp default))
-              (> (length default) 0))
-          (format " (default %s)"
-                  (if (consp default)
-                      (car default)
-                    default)))
-     ": ")))
+;; Obsolete compatibility wrappers used before inclusion of compat.el.
+
+(define-obsolete-function-alias 'org-file-has-changed-p
+  'file-has-changed-p "9.7")
+(define-obsolete-function-alias 'org-string-equal-ignore-case
+  'string-equal-ignore-case "9.7")
+(define-obsolete-function-alias 'org-file-name-concat
+  'file-name-concat "9.7")
+(define-obsolete-function-alias 'org-directory-empty-p
+  'directory-empty-p "9.7")
+(define-obsolete-function-alias 'org-string-clean-whitespace
+  'string-clean-whitespace "9.7")
+(define-obsolete-function-alias 'org-format-prompt
+  'format-prompt "9.7")
+(define-obsolete-function-alias 'org-xor
+  'xor "9.7")
+(define-obsolete-function-alias 'org-string-distance
+  'string-distance "9.7")
+(define-obsolete-function-alias 'org-buffer-hash
+  'buffer-hash "9.7")
 
 \f
 ;;; Emacs < 27.1 compatibility
@@ -252,22 +170,6 @@ (if (version< emacs-version "27.1")
       (replace-buffer-contents source))
   (defalias 'org-replace-buffer-contents #'replace-buffer-contents))
 
-(unless (fboundp 'proper-list-p)
-  ;; `proper-list-p' was added in Emacs 27.1.  The function below is
-  ;; taken from Emacs subr.el 200195e824b^.
-  (defun proper-list-p (object)
-    "Return OBJECT's length if it is a proper list, nil otherwise.
-A proper list is neither circular nor dotted (i.e., its last cdr
-is nil)."
-    (and (listp object) (ignore-errors (length object)))))
-
-(if (fboundp 'xor)
-    ;; `xor' was added in Emacs 27.1.
-    (defalias 'org-xor #'xor)
-  (defsubst org-xor (a b)
-    "Exclusive `or'."
-    (if a (not b) b)))
-
 (unless (fboundp 'pcomplete-uniquify-list)
   ;; The misspelled variant was made obsolete in Emacs 27.1
   (defalias 'pcomplete-uniquify-list 'pcomplete-uniqify-list))
@@ -297,29 +199,6 @@ (defun org--set-faces-extend (faces extend-p)
   (when (fboundp 'set-face-extend)
     (mapc (lambda (f) (set-face-extend f extend-p)) faces)))
 
-(if (fboundp 'string-distance)
-    (defalias 'org-string-distance 'string-distance)
-  (defun org-string-distance (s1 s2)
-    "Return the edit (levenshtein) distance between strings S1 S2."
-    (let* ((l1 (length s1))
-	   (l2 (length s2))
-	   (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil))
-				  (number-sequence 1 (1+ l1)))))
-	   (in (lambda (i j) (aref (aref dist i) j))))
-      (setf (aref (aref dist 0) 0) 0)
-      (dolist (j (number-sequence 1 l2))
-        (setf (aref (aref dist 0) j) j))
-      (dolist (i (number-sequence 1 l1))
-        (setf (aref (aref dist i) 0) i)
-        (dolist (j (number-sequence 1 l2))
-	  (setf (aref (aref dist i) j)
-	        (min
-	         (1+ (funcall in (1- i) j))
-	         (1+ (funcall in i (1- j)))
-	         (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1)
-		    (funcall in (1- i) (1- j)))))))
-      (funcall in l1 l2))))
-
 (define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance
   "9.5")
 
@@ -340,23 +219,6 @@ (if (fboundp 'line-number-display-width)
     (defalias 'org-line-number-display-width 'line-number-display-width)
   (defun org-line-number-display-width (&rest _) 0))
 
-(if (fboundp 'buffer-hash)
-    (defalias 'org-buffer-hash 'buffer-hash)
-  (defun org-buffer-hash () (md5 (current-buffer))))
-
-(unless (fboundp 'file-attribute-modification-time)
-  (defsubst file-attribute-modification-time (attributes)
-    "The modification time in ATTRIBUTES returned by `file-attributes'.
-This is the time of the last change to the file's contents, and
-is a Lisp timestamp in the same style as `current-time'."
-    (nth 5 attributes)))
-
-(unless (fboundp 'file-attribute-size)
-  (defsubst file-attribute-size (attributes)
-    "The size (in bytes) in ATTRIBUTES returned by `file-attributes'.
-This is a floating point number if the size is too large for an integer."
-    (nth 7 attributes)))
-
 \f
 ;;; Obsolete aliases (remove them after the next major release).
 
@@ -1458,7 +1320,7 @@ (defun org-mode-flyspell-verify ()
 	  (and log
 	       (let ((drawer (org-element-lineage element '(drawer))))
 		 (and drawer
-		      (org-string-equal-ignore-case
+		      (string-equal-ignore-case
 		       log (org-element-property :drawer-name drawer))))))
 	nil)
        (t
diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el
index 43c6b2b74..c699c115b 100644
--- a/lisp/org-fold-core.el
+++ b/lisp/org-fold-core.el
@@ -841,7 +841,7 @@ (defun org-fold-core-next-visibility-change (&optional pos limit ignore-hidden-p
 			  (lambda (p) (next-single-char-property-change p 'invisible nil limit)))))
 	 (next pos))
     (while (and (funcall cmp next limit)
-		(not (org-xor
+		(not (xor
                     invisible-initially?
                     (funcall invisible-p
                              (if previous-p
diff --git a/lisp/org-lint.el b/lisp/org-lint.el
index 0e2967b6c..adc893aff 100644
--- a/lisp/org-lint.el
+++ b/lisp/org-lint.el
@@ -383,7 +383,7 @@ (defun org-lint-duplicate-custom-id (ast)
    ast
    'node-property
    (lambda (property)
-     (and (org-string-equal-ignore-case
+     (and (string-equal-ignore-case
            "CUSTOM_ID" (org-element-property :key property))
 	  (org-element-property :value property)))
    (lambda (property _) (org-element-property :begin property))
diff --git a/lisp/org-persist.el b/lisp/org-persist.el
index 8e73fbc4b..21c09567f 100644
--- a/lisp/org-persist.el
+++ b/lisp/org-persist.el
@@ -279,12 +279,12 @@ (defgroup org-persist nil
 
 (defcustom org-persist-directory
   (expand-file-name
-   (org-file-name-concat
+   (file-name-concat
     (let ((cache-dir (when (fboundp 'xdg-cache-home)
                        (xdg-cache-home))))
       (if (or (seq-empty-p cache-dir)
               (not (file-exists-p cache-dir))
-              (file-exists-p (org-file-name-concat
+              (file-exists-p (file-name-concat
                               user-emacs-directory
                               "org-persist")))
           user-emacs-directory
@@ -675,13 +675,13 @@ (defalias 'org-persist-read:version #'org-persist-read:elisp-data)
 
 (defun org-persist-read:file (_ path __)
   "Read file container from PATH."
-  (when (and path (file-exists-p (org-file-name-concat org-persist-directory path)))
-    (org-file-name-concat org-persist-directory path)))
+  (when (and path (file-exists-p (file-name-concat org-persist-directory path)))
+    (file-name-concat org-persist-directory path)))
 
 (defun org-persist-read:url (_ path __)
   "Read file container from PATH."
-  (when (and path (file-exists-p (org-file-name-concat org-persist-directory path)))
-    (org-file-name-concat org-persist-directory path)))
+  (when (and path (file-exists-p (file-name-concat org-persist-directory path)))
+    (file-name-concat org-persist-directory path)))
 
 (defun org-persist-read:index (cont index-file _)
   "Read index container CONT from INDEX-FILE."
@@ -750,7 +750,7 @@ (defun org-persist--load-index ()
   "Load `org-persist--index'."
   (org-persist-load:index
    `(index ,org-persist--storage-version)
-   (org-file-name-concat org-persist-directory org-persist-index-file)
+   (file-name-concat org-persist-directory org-persist-index-file)
    nil))
 
 ;;;; Writing container data
@@ -804,7 +804,7 @@ (defun org-persist-write:file (c collection)
         (setq path (cadr c)))
       (let* ((persist-file (plist-get collection :persist-file))
              (ext (file-name-extension path))
-             (file-copy (org-file-name-concat
+             (file-copy (file-name-concat
                          org-persist-directory
                          (format "%s-%s.%s" persist-file (md5 path) ext))))
         (unless (file-exists-p file-copy)
@@ -850,7 +850,7 @@ (defun org-persist-write:index (container _)
                  org-persist-directory))))
   (when (file-exists-p org-persist-directory)
     (let ((index-file
-           (org-file-name-concat org-persist-directory org-persist-index-file)))
+           (file-name-concat org-persist-directory org-persist-index-file)))
       (org-persist--merge-index-with-disk)
       (org-persist--write-elisp-file index-file org-persist--index t t)
       (setq org-persist--index-age
@@ -865,7 +865,7 @@ (defun org-persist--save-index ()
 (defun org-persist--merge-index-with-disk ()
   "Merge `org-persist--index' with the current index file on disk."
   (let* ((index-file
-          (org-file-name-concat org-persist-directory org-persist-index-file))
+          (file-name-concat org-persist-directory org-persist-index-file))
          (disk-index
           (and (file-exists-p index-file)
                (org-file-newer-than-p index-file org-persist--index-age)
@@ -887,8 +887,8 @@ (defun org-persist--merge-index (base other)
         (dolist (item (nreverse new))
           (unless (or (memq 'index (mapcar #'car (plist-get item :container)))
                       (not (file-exists-p
-                            (org-file-name-concat org-persist-directory
-                                                  (plist-get item :persist-file))))
+                          (file-name-concat org-persist-directory
+                                            (plist-get item :persist-file))))
                       (member (plist-get item :persist-file) base-files))
             (push item combined)))
         (nreverse combined))
@@ -989,7 +989,7 @@ (cl-defun org-persist-read (container &optional associated hash-must-match load
   (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated)))
          (persist-file
           (when collection
-            (org-file-name-concat
+            (file-name-concat
              org-persist-directory
              (plist-get collection :persist-file))))
          (data nil))
@@ -1077,7 +1077,7 @@ (defun org-persist-write (container &optional associated ignore-return)
                          (run-hook-with-args-until-success 'org-persist-before-write-hook v associated))
                        (plist-get collection :container)))
       (when (or (file-exists-p org-persist-directory) (org-persist--save-index))
-        (let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file)))
+        (let ((file (file-name-concat org-persist-directory (plist-get collection :persist-file)))
               (data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection)))
                             (plist-get collection :container))))
           (puthash file data org-persist--write-cache)
@@ -1097,11 +1097,11 @@ (defun org-persist-write-all (&optional associated)
            ;; The container is an `index' container.
            (eq 'index (caar (plist-get (car org-persist--index) :container)))
            (or (not (file-exists-p org-persist-directory))
-               (org-directory-empty-p org-persist-directory)))
+               (directory-empty-p org-persist-directory)))
       ;; Do not write anything, and clear up `org-persist-directory' to reduce
       ;; clutter.
       (when (and (file-exists-p org-persist-directory)
-                 (org-directory-empty-p org-persist-directory))
+                 (directory-empty-p org-persist-directory))
         (delete-directory org-persist-directory))
     ;; Write the data.
     (let (all-containers)
@@ -1142,7 +1142,7 @@ (defun org-persist--gc-persist-file (persist-file)
   "Garbage collect PERSIST-FILE."
   (when (file-exists-p persist-file)
     (delete-file persist-file)
-    (when (org-directory-empty-p (file-name-directory persist-file))
+    (when (directory-empty-p (file-name-directory persist-file))
       (delete-directory (file-name-directory persist-file)))))
 
 (defmacro org-persist-associated-files:generic (container collection)
@@ -1180,7 +1180,7 @@ (defun org-persist-gc ()
   (let (new-index
         (remote-files-num 0)
         (orphan-files
-         (delete (org-file-name-concat org-persist-directory org-persist-index-file)
+         (delete (file-name-concat org-persist-directory org-persist-index-file)
                  (when (file-exists-p org-persist-directory)
                    (directory-files-recursively org-persist-directory ".+")))))
     (dolist (collection org-persist--index)
@@ -1188,7 +1188,7 @@ (defun org-persist-gc ()
              (web-file (and file (string-match-p "\\`https?://" file)))
              (file-remote (when file (file-remote-p file)))
              (persist-file (when (plist-get collection :persist-file)
-                             (org-file-name-concat
+                             (file-name-concat
                               org-persist-directory
                               (plist-get collection :persist-file))))
              (expired? (org-persist--gc-expired-p
diff --git a/lisp/org-refile.el b/lisp/org-refile.el
index 03c351cf6..9797a0633 100644
--- a/lisp/org-refile.el
+++ b/lisp/org-refile.el
@@ -666,7 +666,7 @@ (defun org-refile-get-location (&optional prompt default-buffer new-nodes)
          (prompt (let ((default (or (car org-refile-history)
                                     (and (assoc cbnex tbl) (setq cdef cbnex)
                                          cbnex))))
-                   (org-format-prompt prompt default)))
+                   (format-prompt prompt default)))
 	 pa answ parent-target child parent old-hist)
     (setq old-hist org-refile-history)
     (setq answ (funcall cfunc prompt tbl nil (not new-nodes)
diff --git a/lisp/org.el b/lisp/org.el
index 5e52608ca..e9fa9a241 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -19445,7 +19445,7 @@ (defun org-fill-paragraph (&optional justify region)
 		 (barf-if-buffer-read-only)
 		 (list (when current-prefix-arg 'full) t)))
   (let ((hash (and (not (buffer-modified-p))
-		   (org-buffer-hash))))
+		   (buffer-hash))))
     (cond
      ((and region transient-mark-mode mark-active
 	   (not (eq (region-beginning) (region-end))))
@@ -19470,7 +19470,7 @@ (defun org-fill-paragraph (&optional justify region)
     ;; If we didn't change anything in the buffer (and the buffer was
     ;; previously unmodified), then flip the modification status back
     ;; to "unchanged".
-    (when (and hash (equal hash (org-buffer-hash)))
+    (when (and hash (equal hash (buffer-hash)))
       (set-buffer-modified-p nil))
     ;; Return non-nil.
     t))
diff --git a/lisp/ox.el b/lisp/ox.el
index a6169ea63..203136994 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -4626,11 +4626,11 @@ (defun org-export-resolve-radio-link (link info)
 
 Return value can be a radio-target object or nil.  Assume LINK
 has type \"radio\"."
-  (let ((path (org-string-clean-whitespace (org-element-property :path link))))
+  (let ((path (string-clean-whitespace (org-element-property :path link))))
     (org-element-map (plist-get info :parse-tree) 'radio-target
       (lambda (radio)
-	(and (org-string-equal-ignore-case
-	      (org-string-clean-whitespace (org-element-property :value radio))
+	(and (string-equal-ignore-case
+	      (string-clean-whitespace (org-element-property :value radio))
               path)
 	     radio))
       info 'first-match)))
diff --git a/mk/default.mk b/mk/default.mk
index 997b22b66..4ad1a4281 100644
--- a/mk/default.mk
+++ b/mk/default.mk
@@ -38,7 +38,7 @@ pkgdir = $(shell pwd)/pkg-deps
 EFLAGS ?=
 
 # Third-party packages to install when running make
-EPACKAGES ?=
+EPACKAGES ?= compat
 
 # Configuration for testing
 # Verbose ERT summary by default for Emacs-28 and above.
diff --git a/testing/lisp/test-ol.el b/testing/lisp/test-ol.el
index a38d9f979..565539571 100644
--- a/testing/lisp/test-ol.el
+++ b/testing/lisp/test-ol.el
@@ -63,19 +63,19 @@ (ert-deftest test-org-link/toggle-link-display ()
       (dotimes (_ 2)
         (goto-char 1)
         (re-search-forward "\\[")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "example")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "com")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "]")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "\\[")
         (should-not (org-invisible-p))
         (re-search-forward "link")
         (should-not (org-invisible-p))
         (re-search-forward "]")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (org-toggle-link-display)))))
 
 \f
diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el
index 0ed44c6af..6a47b3384 100644
--- a/testing/lisp/test-org-capture.el
+++ b/testing/lisp/test-org-capture.el
@@ -154,7 +154,7 @@ (ert-deftest test-org-capture/abort ()
   "Test aborting a capture process."
   ;; Newly create capture buffer should not be saved.
   (let ((capture-file (make-temp-name
-                       (org-file-name-concat
+                       (file-name-concat
                         temporary-file-directory
                         "org-test"))))
     (unwind-protect
-- 
2.40.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-org-manual.org-Document-compat-library-installation.patch --]
[-- Type: text/x-patch, Size: 2242 bytes --]

From a5a5f3b14ce81279c6ba8d9bad2a58c83ab88ac4 Mon Sep 17 00:00:00 2001
Message-Id: <a5a5f3b14ce81279c6ba8d9bad2a58c83ab88ac4.1680511419.git.yantar92@posteo.net>
In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sat, 1 Apr 2023 12:18:57 +0200
Subject: [PATCH 4/7] org-manual.org: Document compat library installation

* doc/org-manual.org (Using Org's git repository): Document that users
must also install compat library when using git version of Org.
* etc/ORG-NEWS (Org mode now uses =compat.el= third-party package to
support older Emacs versions): Announce amendments to the Org
installation from git sources.
---
 doc/org-manual.org | 4 ++++
 etc/ORG-NEWS       | 7 +++++++
 2 files changed, 11 insertions(+)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 50662669e..aa9886e5f 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -140,6 +140,10 @@ *** Using Org's git repository
 (add-to-list 'load-path "~/src/org-mode/lisp")
 #+end_src
 
+You must also manually install =compat= library required by Org mode.
+Using built-in =package.el=, you can run =M-x package-install <RET>
+compat <RET>=.
+
 You can also compile with =make=, generate the documentation with
 =make doc=, create a local configuration with =make config= and
 install Org with =make install=.  Please run =make help= to get the
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index ac233a986..0302b8cda 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -13,6 +13,13 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org.
 
 * Version 9.7 (not released yet)
 ** Important announcements and breaking changes
+*** Org mode now uses =compat.el= third-party package to support older Emacs versions
+
+This change is mostly technical and should not affect most users.
+However, people who install Org from git source might be affected.
+It is now necessary to manually install =compat.el= using Emacs'
+package manager.
+
 *** =python-mode.el (MELPA)= support in =ob-python.el= is removed
 
 =python-mode.el= support has been removed from =ob-python.el=.  The
-- 
2.40.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-mk-Expand-shell-commands-once-only.patch --]
[-- Type: text/x-patch, Size: 2303 bytes --]

From 5bb17634a14bb1af4944f73465552cbfd7068a77 Mon Sep 17 00:00:00 2001
Message-Id: <5bb17634a14bb1af4944f73465552cbfd7068a77.1680511419.git.yantar92@posteo.net>
In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sun, 2 Apr 2023 13:53:47 +0200
Subject: [PATCH 5/7] mk: Expand shell commands once only

* mk/default.mk (pkgdir):
* mk/targets.mk (GITVERSION):
(GITSTATUS):
(DATE):
(YEAR): Only expand the variables once, not in every make sub-process.
Previous code ran pwd/date/git in every make sub-process, slowing
things down significantly and unnecessarily.
---
 mk/default.mk | 2 +-
 mk/targets.mk | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/mk/default.mk b/mk/default.mk
index 4ad1a4281..b43a9b3ac 100644
--- a/mk/default.mk
+++ b/mk/default.mk
@@ -32,7 +32,7 @@ TMPDIR ?= /tmp
 testdir = $(TMPDIR)/tmp-orgtest
 
 # Where to store Org dependencies
-pkgdir = $(shell pwd)/pkg-deps
+pkgdir := $(shell pwd)/pkg-deps
 
 # Extra flags to be passed to Emacs
 EFLAGS ?=
diff --git a/mk/targets.mk b/mk/targets.mk
index ab8b830bb..18faa02f5 100644
--- a/mk/targets.mk
+++ b/mk/targets.mk
@@ -14,15 +14,15 @@ ifneq ($(wildcard .git),)
   # Use the org.el header.
   ORGVERSION := $(patsubst %-dev,%,$(shell $(BATCH) --eval "(require 'lisp-mnt)" \
     --visit lisp/org.el --eval '(princ (lm-header "version"))'))
-  GITVERSION ?= $(shell git describe --match release\* --abbrev=6 HEAD 2>/dev/null || echo  "release_N/A-N/A-$(shell git describe --match release\* --abbrev=6 --always HEAD)")
-  GITSTATUS  ?= $(shell git status -uno --porcelain)
+  GITVERSION := $(shell git describe --match release\* --abbrev=6 HEAD 2>/dev/null || echo  "release_N/A-N/A-$(shell git describe --match release\* --abbrev=6 --always HEAD)")
+  GITSTATUS  := $(shell git status -uno --porcelain)
 else
  -include mk/version.mk
   GITVERSION ?= N/A
   ORGVERSION ?= N/A
 endif
-DATE          = $(shell date +%Y-%m-%d)
-YEAR          = $(shell date +%Y)
+DATE          := $(shell date +%Y-%m-%d)
+YEAR          := $(shell date +%Y)
 ifneq ($(GITSTATUS),)
   GITVERSION := $(GITVERSION:.dirty=).dirty
 endif
-- 
2.40.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-mk-Echo-main-compilation-states-when-running-make.patch --]
[-- Type: text/x-patch, Size: 2268 bytes --]

From 9c22dcd8cb0ea0e17e322bbad3d62975572ea80c Mon Sep 17 00:00:00 2001
Message-Id: <9c22dcd8cb0ea0e17e322bbad3d62975572ea80c.1680511419.git.yantar92@posteo.net>
In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sun, 2 Apr 2023 14:05:22 +0200
Subject: [PATCH 6/7] mk: Echo main compilation states when running make

* lisp/Makefile (all compile compile-dirty):
($(LISPV)):
($(LISPI)): Echo compile stage.
* mk/targets.mk (uppkg): Echo compile stage and hide the installation
command.
---
 lisp/Makefile | 7 +++++--
 mk/targets.mk | 7 ++++---
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/lisp/Makefile b/lisp/Makefile
index f507f18a2..45d8109f0 100644
--- a/lisp/Makefile
+++ b/lisp/Makefile
@@ -20,6 +20,7 @@ _ORGCM_ := dirall single source slint1 slint2
 
 # do not clean here, done in toplevel make
 all compile compile-dirty::	 autoloads
+	@$(info ========= Compiling lisp files using '$(ORGCM)' target)
 ifeq ($(filter-out $(_ORGCM_),$(ORGCM)),)
 	$(MAKE) compile-$(ORGCM)
 else
@@ -52,12 +53,14 @@ slint1:
 autoloads:	cleanauto $(LISPI) $(LISPV)
 
 $(LISPV):	$(LISPF)
-	@echo "org-version: $(ORGVERSION) ($(GITVERSION))"
+	@$(info ========= Auto-generating Org version number)
+	@$(info org-version: $(ORGVERSION) ($(GITVERSION)))
 	@$(RM) $(@)
 	@$(MAKE_ORG_VERSION)
 
 $(LISPI):	$(LISPV) $(LISPF)
-	@echo "org-loaddefs: $(ORGVERSION) ($(GITVERSION))"
+	@$(info ========= Auto-generating Org loaddefs)
+	@$(info org-loaddefs: $(ORGVERSION) ($(GITVERSION)))
 	@$(RM) $(@)
 	@$(MAKE_ORG_INSTALL)
 
diff --git a/mk/targets.mk b/mk/targets.mk
index 18faa02f5..072106237 100644
--- a/mk/targets.mk
+++ b/mk/targets.mk
@@ -103,9 +103,10 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f
 endif
 
 uppkg::
-	-$(MKDIR) -p $(pkgdir)
-	-$(FIND) $(pkgdir) \(  -name \*.elc \) -exec $(RM) {} +
-	$(INSTALL_PACKAGES)
+	$(info ========= Installing required third-party packages)
+	@$(MKDIR) -p $(pkgdir)
+	@$(FIND) $(pkgdir) \(  -name \*.elc \) -exec $(RM) {} +
+	-@$(INSTALL_PACKAGES)
 
 up0 up1 up2::
 	git checkout $(GIT_BRANCH)
-- 
2.40.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-mk-Do-not-run-package-refresh-packages-unless-necess.patch --]
[-- Type: text/x-patch, Size: 2322 bytes --]

From 53da71e055630ef8bc6b1191f11a4ec03dabd8c7 Mon Sep 17 00:00:00 2001
Message-Id: <53da71e055630ef8bc6b1191f11a4ec03dabd8c7.1680511419.git.yantar92@posteo.net>
In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sun, 2 Apr 2023 15:11:06 +0200
Subject: [PATCH 7/7] mk: Do not run `package-refresh-packages' unless
 necessary

* mk/default.mk (package-install):
(package-define-refresh-mark):
(package-need-refresh-mark):
(package-refresh-maybe):
(package-install-maybe):
(INSTALL_PACKAGES): Update the command avoiding
`package-refresh-packages' when all the required third-party packages
are already present in the `load-path'.
---
 mk/default.mk | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/mk/default.mk b/mk/default.mk
index b43a9b3ac..67bf96c2e 100644
--- a/mk/default.mk
+++ b/mk/default.mk
@@ -81,7 +81,10 @@ REPRO_ARGS ?=
 req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))'
 lst-ob-lang = ($(ob-lang) . t)
 req-extra   = --eval '(require '"'"'$(req))'
-package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))'
+package-define-refresh-mark = --eval '(setq org--compile-packages-missing nil)'
+package-need-refresh-mark = --eval '(unless (require '"'"'$(package) nil t) (setq org--compile-packages-missing t))'
+package-refresh-maybe = --eval '(if org--compile-packages-missing (package-refresh-contents) (message "No third-party packages need to be installed"))'
+package-install-maybe = --eval '(unless (require '"'"'$(package) nil t) (package-install '"'"'$(package)))'
 BTEST_RE   ?= \\(org\\|ob\\|ox\\)
 BTEST_LOAD  = \
 	--eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \
@@ -93,8 +96,8 @@ INSTALL_PACKAGES =
 else
 INSTALL_PACKAGES = \
 	$(BATCH) \
-        --eval '(package-refresh-contents)' \
-        $(foreach package,$(EPACKAGES),$(package-install))
+        $(package-define-refresh-mark) $(foreach package,$(EPACKAGES),$(package-need-refresh-mark)) $(package-refresh-maybe) \
+        $(foreach package,$(EPACKAGES),$(package-install-maybe))
 endif
 
 BTEST = $(BATCH) $(BTEST_INIT) \
-- 
2.40.0


[-- Attachment #9: Type: text/plain, Size: 224 bytes --]


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

  reply	other threads:[~2023-04-03  8:45 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-11 10:36 Useful package? Compat.el Timothy
2021-10-11 14:28 ` Russell Adams
2021-10-11 14:40   ` Timothy
2021-10-11 18:04     ` Joost Kremers
2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko
2023-01-27 13:34   ` [POLL] Use compat.el in Org? Bastien Guerry
2023-01-27 20:38     ` Tim Cross
2023-01-27 21:38       ` Daniel Mendler
2023-01-27 22:29         ` Samuel Wales
2023-01-28 16:04   ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Kyle Meyer
2023-01-30 11:35   ` Greg Minshall
2023-01-30 19:33     ` Ihor Radchenko
2023-01-30 19:40       ` Greg Minshall
2023-01-30 21:38         ` Daniel Mendler
2023-04-01 10:31   ` [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Ihor Radchenko
2023-04-01 11:38     ` Daniel Mendler
2023-04-01 14:20       ` Max Nikulin
2023-04-02  8:52         ` Ihor Radchenko
2023-04-02 15:31           ` Max Nikulin
2023-04-02 16:04             ` Ihor Radchenko
2023-04-02 16:37     ` Max Nikulin
2023-04-02 17:00       ` [PATCH v2] " Ihor Radchenko
2023-04-03  8:46         ` Ihor Radchenko [this message]
2023-04-08 11:15         ` Max Nikulin
2023-04-08 11:41           ` Ihor Radchenko
2023-04-08 16:37             ` Max Nikulin
2023-04-13 12:42               ` Ihor Radchenko
2023-04-17 17:20                 ` Max Nikulin
2023-04-20  9:27                   ` Ihor Radchenko
2023-04-28 15:27                     ` Max Nikulin
2023-04-30 10:39                       ` [PATCH v4] " Ihor Radchenko
2023-05-03 12:14                         ` [PATCH] epm.el: A CLI tool for package.el Max Nikulin
2023-05-04 10:24                           ` Ihor Radchenko
2023-05-04 16:16                             ` Max Nikulin
2023-05-05  9:39                               ` Ihor Radchenko
2023-05-06  6:39                         ` [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Max Nikulin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87jzytbbg2.fsf@localhost \
    --to=yantar92@posteo.net \
    --cc=emacs-orgmode@gnu.org \
    --cc=manikulin@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).