From: Stefan Kangas Date: Mon, 6 Jan 2025 11:29:21 +0000 (+0100) Subject: Fix finding C headers with clang X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=0b56c3138f3e3cc55ca406c157ba9a385dd27e2b;p=emacs.git Fix finding C headers with clang 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) --- diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el index ff03a365f9e..3475d449951 100644 --- a/lisp/emacs-lisp/ert-x.el +++ b/lisp/emacs-lisp/ert-x.el @@ -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) diff --git a/lisp/man.el b/lisp/man.el index bafb4d20f68..b8c08d34068 100644 --- a/lisp/man.el +++ b/lisp/man.el @@ -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")) "$") diff --git a/lisp/subr.el b/lisp/subr.el index f1bf4a4e671..8eab1cce29c 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -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 diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el index 234d4cc554e..9f0301ff72b 100644 --- a/lisp/tty-tip.el +++ b/lisp/tty-tip.el @@ -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. diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el index 2cb0b616074..5b17c598efa 100644 --- a/test/lisp/subr-tests.el +++ b/test/lisp/subr-tests.el @@ -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 \"\" +# 1 \"\" 1 +# 1 \"\" 3 +# 418 \"\" 3 +# 1 \"\" 1 +# 1 \"\" 2 +# 1 \"\" 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