This fixes following "#include" references in 'M-x man' buffers, and
using ffap, both on macOS machines, and on systems where for some reason
clang is available but gcc is not.
* lisp/subr.el (internal--c-header-file-path): Fix finding C
headers with clang.
(internal--gcc-is-clang-p): New function factored out from...
* lisp/emacs-lisp/ert-x.el (ert-gcc-is-clang-p): ...here.
* lisp/man.el (Man-header-file-path): Bump :version tag.
* test/lisp/subr-tests.el
(subr-tests-internal--c-header-file-path/clang-mocked): New test.
(cherry picked from commit
3dc3dbc2e38340aba7f818eab21abfd93a132175)
(defun ert-gcc-is-clang-p ()
"Return non-nil if the `gcc' command actually runs the Clang compiler."
- ;; Some macOS machines run llvm when you type gcc. (!)
- ;; We can't even check if it's a symlink; it's a binary placed in
- ;; "/usr/bin/gcc". So we need to check the output.
- (string-match "Apple \\(LLVM\\|[Cc]lang\\)\\|Xcode\\.app"
- (shell-command-to-string "gcc --version")))
+ (internal--gcc-is-clang-p))
(defvar tramp-default-host-alist)
(defvar tramp-methods)
(defcustom Man-header-file-path (internal--c-header-file-path)
"C Header file search path used in Man."
- :version "24.1" ; add multiarch
+ :version "31.1"
:type '(repeat string))
(defcustom Man-name-local-regexp (concat "^" (regexp-opt '("NOM" "NAME")) "$")
(defun evenp (integer) "Return t if INTEGER is even." (eq (logand integer 1) 0))
+(defun internal--gcc-is-clang-p ()
+ "Return non-nil if the `gcc' command actually runs the Clang compiler."
+ ;; Recent macOS machines run llvm when you type gcc by default. (!)
+ ;; We can't even check if it's a symlink; it's a binary placed in
+ ;; "/usr/bin/gcc". So we need to check the output.
+ (when-let* ((out (ignore-errors
+ (with-temp-buffer
+ (call-process "gcc" nil t nil "--version")
+ (buffer-string)))))
+ (string-match "Apple \\(LLVM\\|[Cc]lang\\)\\|Xcode\\.app" out)))
+
(defun internal--c-header-file-path ()
"Return search path for C header files (a list of strings)."
- (let ((arch (with-temp-buffer
- (when (eq 0 (ignore-errors
- (call-process "gcc" nil '(t nil) nil
- "-print-multiarch")))
- (goto-char (point-min))
- (buffer-substring (point) (line-end-position)))))
- (base '("/usr/include" "/usr/local/include")))
- (if (seq-empty-p arch) base
- (append base (list (expand-file-name arch "/usr/include"))))))
+ (delete-dups
+ (let ((base '("/usr/include" "/usr/local/include")))
+ (cond ((or (internal--gcc-is-clang-p)
+ (and (executable-find "clang")
+ (not (executable-find "gcc"))))
+ ;; This is either macOS, or a system with clang only.
+ (with-temp-buffer
+ (ignore-errors
+ (call-process (if (internal--gcc-is-clang-p) "gcc" "clang")
+ nil t nil
+ "-v" "-E" "-"))
+ (goto-char (point-min))
+ (narrow-to-region
+ (save-excursion
+ (re-search-forward
+ "^#include <\\.\\.\\.> search starts here:\n" nil t)
+ (point))
+ (save-excursion
+ (re-search-forward "^End of search list.$" nil t)
+ (pos-bol)))
+ (while (search-forward "(framework directory)" nil t)
+ (delete-line))
+ (append base
+ (reverse
+ (split-string (buffer-substring-no-properties
+ (point-min) (point-max)))))))
+ ;; Prefer GCC.
+ ((let ((arch (with-temp-buffer
+ (when (eq 0 (ignore-errors
+ (call-process "gcc" nil '(t nil) nil
+ "-print-multiarch")))
+ (goto-char (point-min))
+ (buffer-substring (point) (line-end-position))))))
+ (if (seq-empty-p arch) base
+ (append base (list (expand-file-name arch "/usr/include"))))))))))
;;; subr.el ends here
-;;; -*- lexical-binding: t; -*-
-;;; tty-tip.el --- Display help in kind of tooltips on ttys
+;;; tty-tip.el --- Display help in pseudo-tooltips on ttys -*- lexical-binding: t; -*-
;; Copyright (C) 2024-2025 Free Software Foundation, Inc.
(insert "x86_64-linux-gnu\n") 0))))
(should (member "/usr/include/x86_64-linux-gnu" (internal--c-header-file-path)))))
+(ert-deftest subr-tests-internal--c-header-file-path/clang-mocked ()
+ ;; Handle clang 15.0.0 output on macOS 15.2.
+ (cl-letf (((symbol-function 'internal--gcc-is-clang-p) (lambda () t))
+ ((symbol-function 'call-process)
+ (lambda (_program &optional _infile _destination _display &rest _args)
+ (insert "\
+Apple clang version 15.0.0 (clang-1500.3.9.4)
+Target: arm64-apple-darwin24.2.0
+Thread model: posix
+InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
+ \"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang\"
+[[[...Emacs test omits some verbose junk from the output here...]]]
+clang -cc1 version 15.0.0 (clang-1500.3.9.4) default target arm64-apple-darwin24.2.0
+ignoring nonexistent directory \"/usr/local/include\"
+#include \"...\" search starts here:
+#include <...> search starts here:
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/15.0.0/include
+ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
+ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
+End of search list.
+# 1 \"<stdin>\"
+# 1 \"<built-in>\" 1
+# 1 \"<built-in>\" 3
+# 418 \"<built-in>\" 3
+# 1 \"<command line>\" 1
+# 1 \"<built-in>\" 2
+# 1 \"<stdin>\" 2")
+ 0)))
+ (should (member "/usr/include" (internal--c-header-file-path)))
+ (should (member "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/15.0.0/include"
+ (internal--c-header-file-path)))))
+
(provide 'subr-tests)
;;; subr-tests.el ends here