]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix finding C headers with clang
authorStefan Kangas <stefankangas@gmail.com>
Mon, 6 Jan 2025 11:29:21 +0000 (12:29 +0100)
committerEshel Yaron <me@eshelyaron.com>
Wed, 8 Jan 2025 08:52:23 +0000 (09:52 +0100)
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)

lisp/emacs-lisp/ert-x.el
lisp/man.el
lisp/subr.el
lisp/tty-tip.el
test/lisp/subr-tests.el

index ff03a365f9ee3f861c400ad2788599ba3f77726b..3475d4499510a0b088b54a2747c471e3dcc32dc2 100644 (file)
@@ -526,11 +526,7 @@ The same keyword arguments are supported as in
 
 (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)
index bafb4d20f68f40778f5fdd233a99f506f3676fd9..b8c08d340689e4b6b1ef4c9c7431314bb79a205e 100644 (file)
@@ -227,7 +227,7 @@ the associated section number."
 
 (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")) "$")
index f1bf4a4e671545f86a05190c54712982066efa2d..8eab1cce29c22a3f4da738c501998ccb6004c781 100644 (file)
@@ -7077,16 +7077,53 @@ that does the same thing as `caadr'."
 
 (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
index 234d4cc554ee26f76613c429295816551da727be..9f0301ff72b381dc9e728dadc408010d036095a7 100644 (file)
@@ -1,5 +1,4 @@
-;;; -*- 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.
 
index 2cb0b616074e90e5dd2e59c6115e25c0351f2550..5b17c598efa85b0bdc690470f780f2732961c146 100644 (file)
@@ -1410,5 +1410,38 @@ final or penultimate step during initialization."))
                  (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