简体   繁体   中英

Emacs Semantic Won't Parse File Correctly On Windows

Recently I was switching my programming environment from CentOS to Windows. I am a fan of Emacs, so I want to use Emacs to program on Windows too. Everything goes on smoothly but when I use emacs semantics to parse system includes, here comes the problem.

It seems that emacs semantic will choose which file to parse and which not. I specify the MS Visual Studio include directories for emacs to parse, but it won't. I also tried MinGW headers, but emacs only parse a few of the files. My init.el file is like this

(defun my-semantic-hook()
  (semantic-add-system-include "C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\include")
  )

I don't know if I should use / or \\ in emacs on windows, but it seems both will work. And if I use semantic-c-describe-environment the output is

This file’s project include is handled by:
    EDE : #<ede-cpp-root-target ede-cpp-root-target>
     with the system path:
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include
    D:/WorkSpace/

  This file’s system include path is:
    /usr/include
    c:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/include/

You can see that I also tried EDE to specify the system include path, but it doesn't work too. However, the other features of semantic works pretty well. If I write #include "lib1.h" or #include "headers/lib1.h" or using EDE #include <myproj/headers/lib1.h> , they all work well. However, when it comes to the VS include files or MinGW include files things just going wrong. I suppose if semantic checks the file first, and it found something wrong then it just skip the file? Then how could I fix the problem?

Now the problem has new progress. I've tried use semantic on my old project using SDL2 library. After I wrote the project configuration for EDE and opened one of the source file, something happened. Semantic parse some system include files like stdio.h. Then I can jump to it through semantic.

Then I tried another file using iostream. However semantic still doesn't parse it. But I can use Cc , u command to jump to the file and I manually call semantic to parse it. Then I went back to my original file using iostream, the company backend using semantic can work pretty well now.

So now I can make sure that the problem is that semantic doesn't parse file itself. Maybe it's because it only parses files with .h or .c at the end of the file name? But on linux it works well with files like iostream, why on windows it won't? How to fix it?

  1. add system includes example:

      (semantic-reset-system-include 'c-mode) (dolist (x 'your-system-includes) (semantic-add-system-include x 'c-mode)) 
  2. add project roots:

     (setq semanticdb-project-roots 'your-project-roots) 

There are an implementation in More Reasonable Emacs for how to find the correct system include paths on Windows, Darwin, and Linux in system-cc-include of cc.el

;;;; -*- lexical-binding:t -*-
;;;;
;; More reasonable Emacs on MacOS, Windows and Linux
;; https://github.com/junjiemars/.emacs.d
;;;;
;; cc.el
;;;;


(platform-supported-when windows-nt

  (defun check-vcvarsall-bat ()
    "Return the path of vcvarsall.bat if which exists."
    (let* ((pfroot (windows-nt-posix-path (getenv "PROGRAMFILES")))
           (vsroot (concat pfroot " (x86)/Microsoft Visual Studio/"))
           (vswhere (concat vsroot "Installer/vswhere.exe")))
      (windows-nt-posix-path
       (or (let* ((cmd (shell-command* (shell-quote-argument vswhere)
                         "-nologo -latest -property installationPath"))
                  (bat (and (zerop (car cmd))
                            (concat (string-trim> (cdr cmd))
                                    "/VC/Auxiliary/Build/vcvarsall.bat"))))
             (when (file-exists-p bat) bat))
           (let* ((ver (car (directory-files vsroot t "[0-9]+" #'string-greaterp)))
                  (bat (concat ver "/BuildTools/VC/Auxiliary/Build/vcvarsall.bat")))
             (when (file-exists-p bat) bat)))))))


(platform-supported-when windows-nt

  (defun make-cc-env-bat ()
    "Make cc-env.bat in `exec-path'."
    (let ((vcvarsall (check-vcvarsall-bat))
          (arch (downcase (getenv "PROCESSOR_ARCHITECTURE"))))
      (when vcvarsall
        (save-str-to-file 
         (concat "@echo off\n"
                 "rem generated by More Reasonable Emacs https://github.com/junjiemars/.emacs.d\n\n"
                 "pushd %cd%\n"
                 "cd /d \"" (file-name-directory vcvarsall) "\"\n"
                 "\n"
                 "call vcvarsall.bat " arch "\n"
                 "set CC=cl" "\n"
                 "set AS=ml" (if (string-match "[_a-zA-Z]*64" arch) "64" "") "\n"
                 "\n"
                 "popd\n"
                 "echo \"%INCLUDE%\"\n")
         (v-home% ".exec/cc-env.bat"))))))


(defun check-cc-include ()
  "Return cc include paths list."
  (platform-supported-if windows-nt
      ;; Windows: msvc
      (let ((cmd (shell-command* (make-cc-env-bat))))
        (when (zerop (car cmd))
          (mapcar (lambda (x) (windows-nt-posix-path x))
                  (var->paths
                   (car (nreverse 
                         (split-string* (cdr cmd) "\n" t "\"")))))))
    ;; Darwin/Linux: clang or gcc
    (let ((cmd (shell-command* "echo '' | cc -v -E 2>&1 >/dev/null -")))
      (when (zerop (car cmd))
        (take-while
         (lambda (p)
           (string-match "End of search list." p))
         (drop-while
          (lambda (p)
            (string-match "#include <...> search starts here:" p))
          (split-string* (cdr cmd) "\n" t "[ \t\n]")))))))


(defvar system-cc-include nil
  "The system include paths used by C compiler.

This should be set with `system-cc-include'")


(defun system-cc-include (&optional cached)
  "Returns a list of system include directories. 

Load `system-cc-include' from file when CACHED is t, 
otherwise check cc include on the fly."
  (let ((c (v-home% "config/.cc-inc.el")))
    (if (and cached (file-exists-p (concat c "c")))
        (progn
          (load (concat c "c"))
          system-cc-include)
      (let ((paths (platform-supported-if darwin
                       (mapcar (lambda (x)
                                 (string-trim> x " (framework directory)"))
                               (check-cc-include))
                     (check-cc-include))))
        (when (save-sexp-to-file
               `(setq system-cc-include ',paths) c)
          (byte-compile-file c))
        (setq system-cc-include paths)))))



(provide 'cc)

Call system-cc-include function should returns a list of system include paths:

(defun set-semantic-cc-env! (&optional project-includes project-roots preprocessors)
    "Use `semantic-mode' in`c-mode'.

PROJECT-INCLUDES specify C include directories
via `semantic-add-system-include',
check it by `semantic-dependency-system-include-path'.'

PROJECT-ROOTS specify C project root directories
via `semanticdb-_project-roots'.

PREPROCESSORS specify C preprocessors
via `semantic-lex-c-preprocessor-symbol-map'

Use `semantic-c-describe-environment' to describe the current C environment."
    (semantic-reset-system-include 'c-mode)

    (dolist (x (append (when-fn% system-cc-include cc
                         (system-cc-include t))
                       project-includes))
      (semantic-add-system-include x 'c-mode))

    (setq% semanticdb-project-roots project-roots semantic/db)

    (when-fn% global-semantic-idle-summary-mode semantic
      (global-semantic-idle-summary-mode))

    (when-fn% semantic-ia-fast-jump semantic
      (define-key semantic-mode-map (kbd "C-c , f") #'semantic-ia-fast-jump))

    (when-fn% semantic-ia-complete-symbol semantic
      (define-key semantic-mode-map (kbd "C-c , TAB") #'semantic-ia-complete-symbol))

    (setq% semantic-lex-c-preprocessor-symbol-map
           preprocessors semantic/bovine/c)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM