view lisp/cedet/semantic/bovine/gcc.el @ 105799:3fe6da4a95a9

* cedet/srecode/srt-mode.el (semantic-analyze-possible-completions): * cedet/semantic/symref/list.el (semantic-symref-rb-toggle-expand-tag): * cedet/semantic/symref/grep.el (semantic-symref-perform-search): * cedet/semantic/bovine/gcc.el (semantic-gcc-query): * cedet/semantic/bovine/c.el (semantic-c-parse-lexical-token): * cedet/semantic/analyze/debug.el (semantic-analyzer-debug-add-buttons) (semantic-analyzer-debug-global-symbol) (semantic-analyzer-debug-missing-innertype) (semantic-analyzer-debug-insert-include-summary): * cedet/semantic/util.el (semantic-file-tag-table): (semantic-describe-buffer-var-helper, semantic-something-to-tag-table) (semantic-recursive-find-nonterminal-by-name): * cedet/semantic/tag-ls.el (semantic-tag-calculate-parent-default): * cedet/semantic/tag-file.el (semantic-prototype-file): * cedet/semantic/symref.el (semantic-symref-parse-tool-output): * cedet/semantic/sb.el (semantic-sb-fetch-tag-table): * cedet/semantic/lex-spp.el (semantic-lex-spp-lex-text-string): * cedet/semantic/idle.el (semantic-idle-work-for-one-buffer): (semantic-idle-summary-maybe-highlight): * cedet/semantic/ia-sb.el (semantic-ia-speedbar) (semantic-ia-sb-tag-info): * cedet/semantic/grammar.el (semantic-analyze-possible-completions): * cedet/semantic/find.el (semantic-brute-find-tag-by-position): * cedet/semantic/ede-grammar.el (project-compile-target): (ede-proj-makefile-insert-variables): * cedet/semantic/debug.el (semantic-debug-set-parser-location): (semantic-debug-set-source-location, semantic-debug-interface-layout) (semantic-debug-mode, semantic-debug): * cedet/semantic/db.el (semanticdb-needs-refresh-p): * cedet/semantic/db-typecache.el (semanticdb-typecache-refresh-for-buffer): * cedet/semantic/db-javascript.el (semanticdb-equivalent-mode): * cedet/semantic/db-find.el (semanticdb-find-log-new-search) (semanticdb-find-translate-path-includes--internal) (semanticdb-reset-log, semanticdb-find-log-activity): * cedet/semantic/db-file.el (object-write): * cedet/semantic/db-el.el (semanticdb-equivalent-mode): * cedet/semantic/db-ebrowse.el (semanticdb-ebrowse-C-file-p) (semanticdb-create-ebrowse-database): * cedet/semantic/db-debug.el (semanticdb-table-sanity-check): * cedet/semantic/complete.el (semantic-displayor-focus-request) (semantic-collector-calculate-completions-raw) (semantic-complete-read-tag-analyzer): * cedet/semantic/analyze.el (semantic-analyze-pulse): * cedet/ede/util.el (ede-update-version-in-source): * cedet/ede/proj.el (project-delete-target): * cedet/ede/proj-elisp.el (ede-update-version-in-source) (ede-proj-flush-autoconf): * cedet/ede/pconf.el (ede-proj-configure-synchronize) (ede-proj-configure-synchronize): * cedet/ede/locate.el (ede-locate-file-in-project-impl): * cedet/ede/linux.el (ede-linux-version): * cedet/ede/emacs.el (ede-emacs-version): * cedet/ede/dired.el (ede-dired-add-to-target): * cedet/ede.el (ede-buffer-header-file, ede-find-target) (ede-buffer-documentation-files, ede-project-buffers, ede-set) (ede-target-buffers, ede-buffers, ede-make-project-local-variable): * cedet/cedet-idutils.el (cedet-idutils-fnid-call): (cedet-idutils-lid-call, cedet-idutils-expand-filename) (cedet-idutils-version-check): * cedet/cedet-global.el (cedet-gnu-global-call): (cedet-gnu-global-expand-filename, cedet-gnu-global-root) (cedet-gnu-global-version-check, cedet-gnu-global-scan-hits): * cedet/cedet-cscope.el (cedet-cscope-call) (cedet-cscope-expand-filename, cedet-cscope-version-check): Use with-current-buffer. * cedet/ede.el (ede-make-project-local-variable) (ede-set-project-variables, ede-set): Use dolist.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Fri, 30 Oct 2009 02:16:41 +0000
parents 7f4c7f5c0eba
children 83dde921cc1b
line wrap: on
line source

;;; semantic/bovine/gcc.el --- gcc querying special code for the C parser

;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.

;; Author: Eric M. Ludlam <eric@siege-engine.com>

;; This file is part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:
;;
;; GCC stores things in special places.  These functions will query
;; GCC, and set up the preprocessor and include paths.

(require 'semantic/dep)

(defvar semantic-lex-c-preprocessor-symbol-file)
(defvar semantic-lex-c-preprocessor-symbol-map)
(declare-function semantic-c-reset-preprocessor-symbol-map "semantic/bovine/c")

;;; Code:

(defun semantic-gcc-query (gcc-cmd &rest gcc-options)
  "Return program output to both standard output and standard error.
GCC-CMD is the program to execute and GCC-OPTIONS are the options
to give to the program."
  ;; $ gcc -v
  ;;
  (let ((buff (get-buffer-create " *gcc-query*"))
        (old-lc-messages (getenv "LC_ALL")))
    (with-current-buffer buff
      (erase-buffer)
      (setenv "LC_ALL" "C")
      (condition-case nil
          (apply 'call-process gcc-cmd nil (cons buff t) nil gcc-options)
        (error ;; Some bogus directory for the first time perhaps?
         (let ((default-directory (expand-file-name "~/")))
           (condition-case nil
               (apply 'call-process gcc-cmd nil (cons buff t) nil gcc-options)
             (error ;; gcc doesn't exist???
              nil)))))
      (setenv "LC_ALL" old-lc-messages)
      (prog1
          (buffer-string)
        (kill-buffer buff)
        )
      )))

;;(semantic-gcc-get-include-paths "c")
;;(semantic-gcc-get-include-paths "c++")
(defun semantic-gcc-get-include-paths (lang)
  "Return include paths as gcc uses them for language LANG."
  (let* ((gcc-cmd (cond
                   ((string= lang "c") "gcc")
                   ((string= lang "c++") "c++")
                   (t (if (stringp lang)
                          (error "Unknown lang: %s" lang)
                        (error "LANG=%S, should be a string" lang)))))
         (gcc-output (semantic-gcc-query gcc-cmd "-v" "-E" "-x" lang null-device))
         (lines (split-string gcc-output "\n"))
         (include-marks 0)
         (inc-mark "#include ")
         (inc-mark-len (length "#include "))
         inc-path)
    ;;(message "gcc-output=%s" gcc-output)
    (dolist (line lines)
      (when (> (length line) 1)
        (if (= 0 include-marks)
            (when (and (> (length line) inc-mark-len)
                       (string= inc-mark (substring line 0 inc-mark-len)))
              (setq include-marks (1+ include-marks)))
          (let ((chars (append line nil)))
            (when (= 32 (nth 0 chars))
              (let ((path (substring line 1)))
                (when (file-accessible-directory-p path)
                  (when (if (memq system-type '(windows-nt))
                            (/= ?/ (nth 1 chars))
                          (= ?/ (nth 1 chars)))
                    (add-to-list 'inc-path
                                 (expand-file-name (substring line 1))
                                 t)))))))))
    inc-path))


(defun semantic-cpp-defs (str)
  "Convert CPP output STR into a list of cons cells with defines for C++."
  (let ((lines (split-string str "\n"))
        (lst nil))
    (dolist (L lines)
      (let ((dat (split-string L)))
        (when (= (length dat) 3)
          (add-to-list 'lst (cons (nth 1 dat) (nth 2 dat))))))
    lst))

(defun semantic-gcc-fields (str)
  "Convert GCC output STR into an alist of fields."
  (let ((fields nil)
        (lines (split-string str "\n"))
        )
    (dolist (L lines)
      ;; For any line, what do we do with it?
      (cond ((or (string-match "Configured with\\(:\\)" L)
                 (string-match "\\(:\\)\\s-*[^ ]*configure " L))
             (let* ((parts (substring L (match-end 1)))
                    (opts (split-string parts " " t))
                    )
               (dolist (O (cdr opts))
                 (let* ((data (split-string O "="))
                        (sym (intern (car data)))
                        (val (car (cdr data))))
                   (push (cons sym val) fields)
                   ))
               ))
            ((string-match "gcc[ -][vV]ersion" L)
             (let* ((vline (substring L (match-end 0)))
                    (parts (split-string vline " ")))
               (push (cons 'version (nth 1 parts)) fields)))
            ((string-match "Target: " L)
             (let ((parts (split-string L " ")))
               (push (cons 'target (nth 1 parts)) fields)))
            ))
    fields))

(defvar semantic-gcc-setup-data nil
  "The GCC setup data.
This is setup by `semantic-gcc-setup'.
This is an alist, and should include keys of:
  'version  - the version of gcc
  '--host   - the host symbol (used in include directories)
  '--prefix - where GCC was installed.
It should also include other symbols GCC was compiled with.")

;;;###autoload
(defun semantic-gcc-setup ()
  "Setup Semantic C/C++ parsing based on GCC output."
  (interactive)
  (let* ((fields (or semantic-gcc-setup-data
                     (semantic-gcc-fields (semantic-gcc-query "gcc" "-v"))))
         (defines (semantic-cpp-defs (semantic-gcc-query "cpp" "-E" "-dM" "-x" "c++" null-device)))
         (ver (cdr (assoc 'version fields)))
         (host (or (cdr (assoc 'target fields))
                   (cdr (assoc '--target fields))
                   (cdr (assoc '--host fields))))
         (prefix (cdr (assoc '--prefix fields)))
         ;; gcc output supplied paths
         (c-include-path (semantic-gcc-get-include-paths "c"))
         (c++-include-path (semantic-gcc-get-include-paths "c++")))
    ;; Remember so we don't have to call GCC twice.
    (setq semantic-gcc-setup-data fields)
    (unless c-include-path
      ;; Fallback to guesses
      (let* ( ;; gcc include dirs
             (gcc-exe (locate-file "gcc" exec-path exec-suffixes 'executable))
             (gcc-root (expand-file-name ".." (file-name-directory gcc-exe)))
             (gcc-include (expand-file-name "include" gcc-root))
             (gcc-include-c++ (expand-file-name "c++" gcc-include))
             (gcc-include-c++-ver (expand-file-name ver gcc-include-c++))
             (gcc-include-c++-ver-host (expand-file-name host gcc-include-c++-ver)))
        (setq c-include-path
              ;; Replace cl-function remove-if-not.
              (delq nil (mapcar (lambda (d)
                                  (if (file-accessible-directory-p d) d))
                                (list "/usr/include" gcc-include))))
        (setq c++-include-path
              (delq nil (mapcar (lambda (d)
                                  (if (file-accessible-directory-p d) d))
                                (list "/usr/include"
                                      gcc-include
                                      gcc-include-c++
                                      gcc-include-c++-ver
                                      gcc-include-c++-ver-host))))))

    ;;; Fix-me: I think this part might have been a misunderstanding, but I am not sure.
    ;; If this option is specified, try it both with and without prefix, and with and without host
    ;; (if (assoc '--with-gxx-include-dir fields)
    ;;     (let ((gxx-include-dir (cdr (assoc '--with-gxx-include-dir fields))))
    ;;       (nconc try-paths (list gxx-include-dir
    ;;                              (concat prefix gxx-include-dir)
    ;;                              (concat gxx-include-dir "/" host)
    ;;                              (concat prefix gxx-include-dir "/" host)))))

    ;; Now setup include paths etc
    (dolist (D (semantic-gcc-get-include-paths "c"))
      (semantic-add-system-include D 'c-mode))
    (dolist (D (semantic-gcc-get-include-paths "c++"))
      (semantic-add-system-include D 'c++-mode)
      (let ((cppconfig (concat D "/bits/c++config.h")))
        ;; Presumably there will be only one of these files in the try-paths list...
        (when (file-readable-p cppconfig)
          ;; Add it to the symbol file
          (if (boundp 'semantic-lex-c-preprocessor-symbol-file)
              ;; Add to the core macro header list
              (add-to-list 'semantic-lex-c-preprocessor-symbol-file cppconfig)
            ;; Setup the core macro header
            (setq semantic-lex-c-preprocessor-symbol-file (list cppconfig)))
          )))
    (if (not (boundp 'semantic-lex-c-preprocessor-symbol-map))
        (setq semantic-lex-c-preprocessor-symbol-map nil))
    (dolist (D defines)
      (add-to-list 'semantic-lex-c-preprocessor-symbol-map D))
    (when (featurep 'semantic/bovine/c)
      (semantic-c-reset-preprocessor-symbol-map))
    nil))

(provide 'semantic/bovine/gcc)

;; Local variables:
;; generated-autoload-file: "../loaddefs.el"
;; generated-autoload-feature: semantic/loaddefs
;; generated-autoload-load-name: "semantic/bovine/gcc"
;; End:

;; arch-tag: 7086f4a0-1ce8-48e2-9783-d750d3765186
;;; semantic/bovine/gcc.el ends here