123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- (require 'ede)
- (defvar semantic-lex-spp-project-macro-symbol-obarray)
- (declare-function semantic-lex-make-spp-table "semantic/lex-spp")
- (declare-function semanticdb-file-table-object "semantic/db")
- (declare-function semanticdb-needs-refresh-p "semantic/db")
- (declare-function semanticdb-refresh-table "semantic/db")
- (defvar ede-cpp-root-project-list nil
- "List of projects created by option `ede-cpp-root-project'.")
- (defun ede-cpp-root-file-existing (dir)
- "Find a cpp-root project in the list of cpp-root projects.
- DIR is the directory to search from."
- (let ((projs ede-cpp-root-project-list)
- (ans nil))
- (while (and projs (not ans))
- (let ((root (ede-project-root-directory (car projs))))
- (when (string-match (concat "^" (regexp-quote root)) dir)
- (setq ans (car projs))))
- (setq projs (cdr projs)))
- ans))
- (defun ede-cpp-root-project-file-for-dir (&optional dir)
- "Return a full file name to the project file stored in DIR."
- (let ((proj (ede-cpp-root-file-existing dir)))
- (when proj (oref proj :file))))
- (defvar ede-cpp-root-count 0
- "Count number of hits to the cpp root thing.
- This is a debugging variable to test various optimizations in file
- lookup in the main EDE logic.")
- (defun ede-cpp-root-project-root (&optional dir)
- "Get the root directory for DIR."
- (let ((projfile (ede-cpp-root-project-file-for-dir
- (or dir default-directory))))
- (setq ede-cpp-root-count (1+ ede-cpp-root-count))
-
- (when projfile
- (file-name-directory projfile))))
- (defun ede-cpp-root-load (dir &optional rootproj)
- "Return a CPP root object if you created one.
- Return nil if there isn't one.
- Argument DIR is the directory it is created for.
- ROOTPROJ is nil, since there is only one project."
-
- (ede-cpp-root-file-existing dir))
- (add-to-list 'ede-project-class-files
- (ede-project-autoload "cpp-root"
- :name "CPP ROOT"
- :file 'ede/cpp-root
- :proj-file 'ede-cpp-root-project-file-for-dir
- :proj-root 'ede-cpp-root-project-root
- :load-type 'ede-cpp-root-load
- :class-sym 'ede-cpp-root
- :new-p nil)
- t)
- (defclass ede-cpp-root-target (ede-target)
- ()
- "EDE cpp-root project target.
- All directories need at least one target.")
- (defclass ede-cpp-root-project (ede-project eieio-instance-tracker)
- ((tracking-symbol :initform 'ede-cpp-root-project-list)
- (include-path :initarg :include-path
- :initform '( "/include" "../include/" )
- :type list
- :documentation
- "The default locate function expands filenames within a project.
- If a header file (.h, .hh, etc) name is expanded, and
- the :locate-fcn slot is nil, then the include path is checked
- first, and other directories are ignored. For very large
- projects, this optimization can save a lot of time.
- Directory names in the path can be relative to the current
- buffer's `default-directory' (not starting with a /). Directories
- that are relative to the project's root should start with a /, such
- as \"/include\", meaning the directory `include' off the project root
- directory.")
- (system-include-path :initarg :system-include-path
- :initform nil
- :type list
- :documentation
- "The system include path for files in this project.
- C files initialized in an ede-cpp-root-project have their semantic
- system include path set to this value. If this is nil, then the
- semantic path is not modified.")
- (spp-table :initarg :spp-table
- :initform nil
- :type list
- :documentation
- "C Preprocessor macros for your files.
- Preprocessor symbols will be used while parsing your files.
- These macros might be passed in through the command line compiler, or
- are critical symbols derived from header files. Providing header files
- macro values through this slot improves accuracy and performance.
- Use `:spp-files' to use these files directly.")
- (spp-files :initarg :spp-files
- :initform nil
- :type list
- :documentation
- "C header file with Preprocessor macros for your files.
- The PreProcessor symbols appearing in these files will be used while
- parsing files in this project.
- See `semantic-lex-c-preprocessor-symbol-map' for more on how this works.")
- (header-match-regexp :initarg :header-match-regexp
- :initform
- "\\.\\(h\\(h\\|xx\\|pp\\|\\+\\+\\)?\\|H\\)$\\|\\<\\w+$"
- :type string
- :documentation
- "Regexp used to identify C/C++ header files.")
- (locate-fcn :initarg :locate-fcn
- :initform nil
- :type (or null function)
- :documentation
- "The locate function can be used in place of
- `ede-expand-filename' so you can quickly customize your custom target
- to use specialized local routines instead of the EDE routines.
- The function symbol must take two arguments:
- NAME - The name of the file to find.
- DIR - The directory root for this cpp-root project.
- It should return the fully qualified file name passed in from NAME. If that file does not
- exist, it should return nil."
- )
- )
- "EDE cpp-root project class.
- Each directory needs a project file to control it.")
- (defmethod initialize-instance ((this ede-cpp-root-project)
- &rest fields)
- "Make sure the :file is fully expanded."
-
- (call-next-method)
- (let ((f (expand-file-name (oref this :file))))
-
- (let ((old (eieio-instance-tracker-find (file-name-directory f)
- :directory 'ede-cpp-root-project-list)))
-
- (when (and old (not (eq old this)))
- (delete-instance old)))
-
- (when (or (not (file-exists-p f))
- (file-directory-p f))
- (delete-instance this)
- (error ":file for ede-cpp-root must be a file"))
- (oset this :file f)
- (oset this :directory (file-name-directory f))
- (ede-project-directory-remove-hash (file-name-directory f))
- (ede-add-project-to-global-list this)
- (unless (slot-boundp this 'targets)
- (oset this :targets nil))
-
-
- ))
- (defmethod ede-find-subproject-for-directory ((proj ede-cpp-root-project)
- dir)
- "Return PROJ, for handling all subdirs below DIR."
- proj)
- (defmethod ede-find-target ((proj ede-cpp-root-project) buffer)
- "Find an EDE target in PROJ for BUFFER.
- If one doesn't exist, create a new one for this directory."
- (let* ((targets (oref proj targets))
- (dir default-directory)
- (ans (object-assoc dir :path targets))
- )
- (when (not ans)
- (setq ans (ede-cpp-root-target dir
- :name (file-name-nondirectory
- (directory-file-name dir))
- :path dir
- :source nil))
- (object-add-to-list proj :targets ans)
- )
- ans))
- (defmethod ede-expand-filename-impl ((proj ede-cpp-root-project) name)
- "Within this project PROJ, find the file NAME.
- This knows details about or source tree."
-
-
-
- (let ((ans (call-next-method)))
- (unless ans
- (let* ((lf (oref proj locate-fcn))
- (dir (file-name-directory (oref proj file))))
- (if lf
- (setq ans (funcall lf name dir))
- (if (ede-cpp-root-header-file-p proj name)
-
- (let ((ip (oref proj include-path))
- (tmp nil))
- (while ip
-
- (setq tmp (ede-cpp-root-translate-file proj (car ip)))
-
- (setq tmp (expand-file-name name tmp))
- (if (file-exists-p tmp)
- (setq ans tmp))
- (setq ip (cdr ip)) ))
-
- (setq ans (call-next-method)))
- )))
- (or ans (call-next-method))))
- (defmethod ede-project-root ((this ede-cpp-root-project))
- "Return my root."
- this)
- (defmethod ede-project-root-directory ((this ede-cpp-root-project))
- "Return my root."
- (file-name-directory (oref this file)))
- (defmethod ede-cpp-root-header-file-p ((proj ede-cpp-root-project) name)
- "Non nil if in PROJ the filename NAME is a header."
- (save-match-data
- (string-match (oref proj header-match-regexp) name)))
- (defmethod ede-cpp-root-translate-file ((proj ede-cpp-root-project) filename)
- "For PROJ, translate a user specified FILENAME.
- This is for project include paths and spp source files."
-
- (let ((dir (file-name-directory (oref proj file))))
-
- (if (and (not (string= filename "")) (= (aref filename 0) ?/))
-
- (setq filename (expand-file-name (substring filename 1)
- dir))
-
- (setq filename (expand-file-name filename)))
- filename))
- (defmethod ede-set-project-variables ((project ede-cpp-root-project) &optional buffer)
- "Set variables local to PROJECT in BUFFER.
- Also set up the lexical preprocessor map."
- (call-next-method)
- (when (and (featurep 'semantic/bovine/c) (featurep 'semantic/lex-spp))
- (setq semantic-lex-spp-project-macro-symbol-obarray
- (semantic-lex-make-spp-table (oref project spp-table)))
- ))
- (defmethod ede-system-include-path ((this ede-cpp-root-project))
- "Get the system include path used by project THIS."
- (oref this system-include-path))
- (defmethod ede-preprocessor-map ((this ede-cpp-root-project))
- "Get the pre-processor map for project THIS."
- (require 'semantic/db)
- (let ((spp (oref this spp-table))
- (root (ede-project-root this))
- )
- (mapc
- (lambda (F)
- (let* ((expfile (ede-expand-filename root F))
- (table (when expfile
- (semanticdb-file-table-object expfile)))
- )
- (when (not table)
- (message "Cannot find file %s in project." F))
- (when (and table (semanticdb-needs-refresh-p table))
- (semanticdb-refresh-table table)
- (setq spp (append spp (oref table lexical-table))))))
- (oref this spp-files))
- spp))
- (defmethod ede-system-include-path ((this ede-cpp-root-target))
- "Get the system include path used by project THIS."
- (ede-system-include-path (ede-target-parent this)))
- (defmethod ede-preprocessor-map ((this ede-cpp-root-target))
- "Get the pre-processor map for project THIS."
- (ede-preprocessor-map (ede-target-parent this)))
- (defun ede-create-lots-of-projects-under-dir (dir projfile &rest attributes)
- "Create a bunch of projects under directory DIR.
- PROJFILE is a file name sans directory that indicates a subdirectory
- is a project directory.
- Generic ATTRIBUTES, such as :include-path can be added.
- Note: This needs some work."
- (let ((files (directory-files dir t)))
- (dolist (F files)
- (if (file-exists-p (expand-file-name projfile F))
- `(ede-cpp-root-project (file-name-nondirectory F)
- :name (file-name-nondirectory F)
- :file (expand-file-name projfile F)
- attributes)))))
- (provide 'ede/cpp-root)
|